- 類與對象
- 數(shù)據(jù)成員
- 函數(shù)成員
TODO:
- 初始化器和析構器
- 繼承
- 多態(tài)
類與對象
Objective-C(以下簡稱OC) 是一種面向對象語言超凳,因此除了基本數(shù)據(jù)類型万栅,它具有類類型所禀。OC 中類的聲明形式類似:
@interface MyClass: NSObject
{
NSString* private; //實例變量
@public NSString* public; //實例變量
}
@property int num; //屬性
-(void)ObjectMethod: (int)num; //對象方法劲室,又叫實例方法
+(void)ClassMethod; //類方法
-(NSString*)private ;
-(void)setPrivate: (NSString*)str;
@end
OC 用 @interface
聲明類幕帆,相當于C++語法中的class
關鍵字侮繁。@end
表示聲明的結束虑粥。OC中的大部分中大部分類都會直接或者間接繼承自NSObject
,這是因為NSObject
中定義了一些OC對象通用的方法宪哩,比如定義一個類時[[MyClass alloc] init]
娩贷,其中alloc
和init
方法就是在NSObject
中定義的,否則我們就要在類定義中自己實現(xiàn)這兩個方法锁孟。
OC中類的聲明放在.h
文件彬祖,類是現(xiàn)實存在.m
文件茁瘦。上面聲明的類其實現(xiàn)類似:
@implement MyClass
-(void)ObjectMethod: (int)num
{
self.num = num;
}
+(void)ClassMethod
{
NSLog(@"This ClassMethod");
}
-(NSString*)private {
return private;
}
-(void)setPrivate: (NSString*)str {
private = str
}
定義一個類對象的語法如下:
MyClass* myClass = [[MyClass alloc] init]
大概是因為OC中的類對象都是分配在堆上的,所以储笑,類對象都聲明為指針的形式甜熔。
數(shù)據(jù)成員:屬性和實例變量
上述類聲明中的有一個數(shù)據(jù)成員,就是
@property in num;
屬性的存取方式
myClass.num = 5;
int someNum = myClass.num;
對于任何屬性突倍,編譯器都會自動生成一個與之關聯(lián)的實例變量腔稀。比如與num
關聯(lián)的實例變量是_num
。同時還生成一個getter訪問器方法和一個setter訪問器方法羽历。
-(int)num {
return _num;
}
-(void)setNum: (int)num {
_num = num;
}
可以發(fā)現(xiàn)這里的_num
和它的兩個訪問器和我們在MyClass
實現(xiàn)中定義的NSString* private;
形式是類似的烧颖。
private
和public
一樣是實例變量,不同的是窄陡,一般的實例變量(如:private
)只能在類的內部訪問炕淮,都是私有的。為了能在類的外部訪問(如myClass->public = @"hello";
)跳夭,需要在實例變量聲明語句加上@public
前綴(如:public
)涂圆。
雖然private
不能在外部通過->
來訪問,但因為我們?yōu)?code>private編寫了getter訪問器和setter訪問器币叹,在OC中润歉,我們就可以使用myClass.private = @"world"
這樣的語法來訪問private,其實編譯器會自動將該語句轉化成[myClass setPrivate:@"world"]
颈抚,也就是實際是調用setter方法來訪問private
實例變量的踩衩。
可想而知,如果沒有屬性贩汉,那么對于每個我們希望通過myClass.XXX
形式來訪問的實例變量驱富,我們都需要為其編寫兩個訪問器方法,這實在是太過繁瑣匹舞。有了屬性這個語法糖褐鸥,就可以讓編譯器自動為我們完成這些工作了。
同樣赐稽,有了屬性叫榕,我們也不需要再使用@public
關鍵字,通過->
指針訪問符來訪問實例變量了姊舵。
需要注意的時晰绎,對于在.h
和.m
文件中分別編寫類聲明和類實現(xiàn)代碼情況,即我們通常所遵循的方式括丁。外部使用時通過#import "xxx.h"
只能知道xxx.h
文件中的定義荞下,如果我們將某個實例變量定義在xxx.m
的實現(xiàn)代碼中,那么就是為該實例變量加上@public
前綴,外部對象也不能訪問該實例變量锄弱,因為它根本不知道該實例變量的存在。這點對于方法也是成立的祸憋,盡管方法都是public的会宪,但如果方法只在.m
文件中定義,沒有在.h
文件中聲明蚯窥,那么對于外部對象該方法就相當于是私有的掸鹅。相當于私有并不等于私有,這點在編譯器報錯時可以體現(xiàn)拦赠。只定義在.m
文件中情況巍沙,訪問時編譯器會提示沒有定義該實例變量或者方法,而如果是聲明在.h
文件中非@public
實例變量荷鼠,訪問時編譯器會提示該實例變量是受保護的句携。
函數(shù)成員:方法
OC中的方法都是public的,沒有 private 和 protected 方法允乐。
OC中類的方法分為實例方法
和類方法
矮嫉,聲明形式如下
-(void)ObjectMethod: (int)num; //對象方法,又叫實例方法
+(void)ClassMethod; //類方法
在語法層面牍疏,實例方法就是通過實例對象來調用的方法蠢笋,如[myClass ObjectMethod:10]
,定義時在方法名前加-
前綴鳞陨;類方法就是通過類名來調用的方法昨寞,如[MyClass ClassMethod]
,定義時在方法名前加+
前綴厦滤。
[[MyClass alloc] init]
援岩,其中alloc
就是類方法,init
就是實例方法掏导。
類方法中是不能訪問本類的實例成員的窄俏。在邏輯上類方法可以在類對象不存在時調用,此時實例變量都還不存在碘菜,那么通過類方法訪問實例成員必然出錯凹蜈。即使類對象存在,假設有多個類對象忍啸,那么類方法是訪問那個類對象的實例成員也是無法確定仰坦。在實現(xiàn)上,編譯器會為實例方法自動添加指向當前對象的self
指針參數(shù)计雌,通過self
就能確定所訪問的對象悄晃。而類方法是沒有self
參數(shù)的,所以類方法無法確定是哪個類對象。
OC中方法的外部參數(shù)名不同妈橄,就是不同的方法庶近。因此可以寫方法名相同,參數(shù)類型和數(shù)量相同眷蚓,以及返回值相同的鼻种,只有外部參數(shù)名不同的多個方法。
-(void)sum: (int)arg1 arg2: (int)arg2;
-(void)sum:(int)arg1 secondArg: (int)arg2;
這樣的兩個方法是可以同時存在的沙热。
初始化器和析構器
初始化器
MyClass* myClass = [[MyClass alloc] init]
OC中創(chuàng)建一個對象需要配合使用alloc
和init
兩個方法叉钥。正如方法名的字面意思,alloc
方法用于分配對象空間篙贸,init
方法用于對對象的實例變量進行初始化操作投队。
alloc
方法在NSObject
中已經定義,這也是我們的類要繼承于NSObject
的原因之一爵川。alloc
方法會將分配的內存空間用0來填充敷鸦,這樣所有的實例變量的值就會是0或者nil。
在init
的方法中寝贡,會先調用父類的init
方法轧膘,再初始化自己的實例變量。
init
是對象初始化器兔甘,在調用init
之前還會調用一個類初始化器initialize
谎碍。
@implementation MyClass
...
-(id)init {
self = [super init];
NSLog(@"this init");
return self;
}
+(void)initialize {
if self == [MyClass class] {
NSLog(@"this is initialize");
}
}
...
@end
在類定義中實現(xiàn)這兩個初始化器,然后調用MyClass* myClass = [[MyClass alloc] init]
會輸出如下結果:
類型初始化器initialize
只能有一個洞焙,而對象初始化器init
可以有多個蟆淀。
- (id)init;
- (id)initWithName: (NSString*)name;
- (id)initWithLocation: (NSPoint*)location;
在初始化器中,要使用實例變量澡匪,不要使用屬性熔任。
析構器 dealloc
在析構器中,主要做三件事
- ARC對對象屬性的引用計數(shù)器減1唁情,這個造作是自動完成疑苔。
- 手動釋放我們自己分配的動態(tài)內存
- 關閉非內存資源,比如文件句柄甸鸟,socket連接等