iOS - OC 面向对象语法
1、類
1)根類:因為類 NSObject 是層次結(jié)構(gòu)的最頂層,因此稱為根類。
- 可以將類稱為子類(subclass)和父類(superclass),也可以將類稱為子類和超類。
2)分類/類別(category):允許以模塊的方式向現(xiàn)有類定義添加新的方法(默認(rèn)不能添加實例變量)。擴展自己或他人以前實現(xiàn)的類,使它適合自己的需要。
分類的名稱括在類名之后的一對圓括號“( )”中。
@interface QCStudent (Print)@end@implementation QCStudent (Print)@end分類文件名使用符號“+”來分隔類和分類的名字(Xcode 會自動生成)。
QCStudent+Print.mQCStudent+Print.h分類用它可以將類的定義模塊化到相關(guān)方法的組或分類中。它還提供了擴展現(xiàn)有類定義的簡便方式,并且不必訪問類的源代碼,也無需創(chuàng)建子類。
分類可以覆寫該類中的另一個方法,但是通常認(rèn)為這種做法是拙劣的設(shè)計習(xí)慣。一個類可以擁有多個分類。使用分類添加新方法來擴展類不僅會影響這個類,同時也會影響它的所有子類。分類為現(xiàn)有類添加新方法可能對你有用,但它們可能和該類的原始設(shè)計或意圖不一致。對象/分類命名對必須是唯一的。
iOS 開發(fā)中,分類默認(rèn)不允許添加屬性。但是如果在自己開發(fā)的框架中,希望在分類中動態(tài)添加屬性,可以通過 OC 運行時的關(guān)聯(lián)對象功能添加,詳見 iOS - OC Category 分類。
3)類的擴展:有一種特殊的情況是創(chuàng)建一個未命名的分類,并且括號“( )”之間不指定名字。
這種特殊的語法定義稱為類的擴展。定義一個像這樣的未命名的分類時,可以通過定義額外的實例變量和屬性來擴展類,這在有命名的分類中是不允許的。
@interface QCStudent ()@end@implementation QCStudent@end未命名的分類中聲明的方法需要在主實現(xiàn)區(qū)域?qū)崿F(xiàn),而不是在分類的的實現(xiàn)區(qū)域。
未命名的分類的方法都是私有的。如果需要寫一個類,而且數(shù)據(jù)和方法僅供這個類本身使用,未命名分類比較合適。
4)抽象類:有時創(chuàng)建類只是為了更容易創(chuàng)建子類。因此,這些類名為抽象類,或等價的稱為抽象超類。在該類中定義方法和實例變量,但不希望任何人從這個類創(chuàng)建實例。
5)類與類之間的關(guān)系:
- 類的包含(復(fù)合):
- 一個類中有另一個類的 @class 聲明。一個類中包含有 #import 另一個類的 .h 頭文件。
- 一般在 .h 頭文件中用 @class 聲明一個類,在 .m 文件中使用到該類時再在 .m 文件中包含該類的 .h 頭文件。
- 類的包含(復(fù)合):
6)類的加載:
1>、類加載時自動調(diào)用方法:+ (void)load;
+ (void)load {NSLog(@"%@",@"Student ------------- load");}2>、類首次使用時自動調(diào)用方法:+ (void)initialize;
+ (void)initialize {NSLog(@"%@",@"Student ------------- initialize");}3>、使用 %@ 打印對象時會自動調(diào)用方法:- (NSString *)description;
// description 覆寫- (NSString *)description {return [NSString stringWithFormat:@"age : %d, name : %@", self.age, self.name];}
7)是在子類中使用的實例變量,必須先在接口部分聲明,而不是在實現(xiàn)部分聲明。在實現(xiàn)部分聲明和合成的實例變量是私有的,子類中不能直接訪問,需要明確定義或合成取值方法,才能訪問實例變量的值。
8)類前綴:
使用 Objective-C 開發(fā) iOS 程序時,最好在每個類名前面加一個前綴,用來標(biāo)識這個類。
- 目的是防止 N 個人開發(fā)了一樣的類,出現(xiàn)沖突。
- 比如 Jake Will、Kate Room 在同一個項目中都各自開發(fā)了個 Button 類,這樣的程序是不能運行起來的。
- 解決方案:Jake Will 的類名叫做 JWButton,Kate Room 的類名叫做 KRButton。
類前綴的設(shè)置
Xcode 6 之前:
在創(chuàng)建項目時設(shè)置。
Xcode 6 之后:
創(chuàng)建完項目后設(shè)置。
設(shè)置完后,再創(chuàng)建新的文件時會自動添加上設(shè)置的類前綴。
2、對象、方法
1)類的獨特存在就是一個實例(對象),對實例執(zhí)行的操作稱為方法。
2)合成對象:可以定義一個類包含其它類的一個或多個對象,這個新類的對象就是所謂的合成對象,因為它是由其它對象組成的。
- 作為創(chuàng)建子類的代替方法,可以定義一個新類,它包含要擴展類的實例變量。然后,只需在新類中定義適合該類的方法。
3)實例初始化
1>、初始化方式:
alloc :方法保證對象的所有實例變量都變成初始狀態(tài)。 創(chuàng)建對象。init :方法用于初始化類的實例變量。 初始化對象。new :可以將 alloc 和 init 的結(jié)合起來。 創(chuàng)建并初始化對象。- 但用兩步來實現(xiàn)創(chuàng)建和初始化的方式通常更好,這樣可以在概念上理解正在發(fā)生兩個不同的事件:首先創(chuàng)建一個對象,然后對它初始化。
2>、構(gòu)造方法:實例初始化常見的編程習(xí)慣是類中所有初始化方法都以 init 開頭。如果希望在類對象初始化時做一些事情,可以通過重載 init 方法達到這個目的。下面是重載 init 方法的一個標(biāo)準(zhǔn)模板。
不帶參數(shù):- (instancetype)init {self = [super init];if (self) {// 初始化代碼}return self; }帶參數(shù):- (instancetype)initWithAge:(int)age andNo:(int)no { self = [super init];if (self) {_age = age;_no = no; }return self;}類方法:+ (instancetype *)studentWithAge:(int)age {Student *stu = [[Student alloc] init];stu.age = age;return stu;}執(zhí)行父類的初始化方法,使得繼承的實例變量能夠正常的初始化。如果父類初始化成功,返回的值將是非空的。self 用來指明對象是當(dāng)前方法的接收者。必須將父類 init 方法的執(zhí)行結(jié)果賦值給 self,因為初始化過程改變了對象在內(nèi)存中的位置(意味著引用將要改變)。
特殊類型 instancetype 表明從 init 方法返回的類型與它的初始化類(也就是初始化消息的接收者)相同。 init 被定義為返回 instancetype 類型,這是編寫可能被繼承的類 init 方法的一般規(guī)則。當(dāng)編譯器遇見 instancetype 作為返回類型,它就知道返回的類型是發(fā)送消息的對象。
4)消息:請求一個類或?qū)嵗齺韴?zhí)行某個操作時,就是在向它發(fā)送一條消息,消息的接受者稱為接收者。
- OC 采用特定的語法對類和實例應(yīng)用方法:[類/實例 方法];
- 5)類方法(靜態(tài)方法):是對類本身執(zhí)行某些操作的方法。
實例方法(動態(tài)方法):對類的實例執(zhí)行一些操作。
創(chuàng)建方法名時,參數(shù)名實際上是可選的,參數(shù)名可以省略。如:- (int)set :(int)name :(int)age;
方法(函數(shù))不返回任何值時,無需在方法的末尾執(zhí)行一條 return 語句。或者也可以執(zhí)行一條不帶任何指定值的 return 語句:return;。
6)重寫(覆蓋):在子類中新建一個與父類中的方法同名的方法。子類中的新方法必須具有相同的返回類型,并且參數(shù)的數(shù)目和覆寫的方法相同。
- 如果需要來擴展繼承的方法。子類中包含對 if (self = [super init]) 的判斷。
7)重載:在類中,相同名字不同參數(shù)的方法的寫法有一個專門的術(shù)語來描述,叫做重載。
8)懶加載
- 對象在用到時再去加載,而且只加載一次。加載的數(shù)據(jù)比較大時可以節(jié)省內(nèi)存。
一般重寫 getter 方法實現(xiàn)對象的懶加載。
@property (strong, nonatomic) NSArray *shops;- (NSArray *)shops {// 加載數(shù)據(jù)if (_shops == nil) {NSString *filePath = [[NSBundle mainBundle] pathForResource:@"shops" ofType:@"plist"];_shops = [NSArray arrayWithContentsOfFile: filePath];}return _shops;}
3、數(shù)據(jù)封裝(實例變量)
1)數(shù)據(jù)封裝:將實例變量隱藏起來的這種做法實際上涉及一個關(guān)鍵概念 --“數(shù)據(jù)封裝”。
- 不能在類的外部編寫方法直接設(shè)置或獲取實例變量的值,而需要編寫設(shè)置方法和取值方法來設(shè)置和獲取實例變量的值,這便是數(shù)據(jù)封裝的原則。
- 必須通過使用一些方法來訪問這些通常對“外界”隱藏的數(shù)據(jù),這種做法集中了訪問實例變量的方式,并且能夠阻止其它一些代碼直接改變實例變量的值。如果可以直接改變,會讓程序很難跟蹤、調(diào)試和修改。
2)實例變量的定義作用域
@public 全局都可以訪問,實例對象可以使用符號 “->” 直接訪問實例變量。 @protected 只能在類內(nèi)部和子類中訪問 (訪問器方法 默認(rèn)) 。@private 只能在類內(nèi)部訪問 (合成取值方法 默認(rèn))。@package 常用于框架類的實例變量,同一包內(nèi)能用,跨包就不能訪問。3)訪問器方法(accessor):取值方法和設(shè)值方法通常稱為訪問器方法。通常實例變量聲明時以下畫線( _ )字符開頭,此實例變量默認(rèn)為保護(@protected)的。在類內(nèi)部和子類中都可以訪問。
設(shè)值方法(setter):設(shè)置實例變量值的方法通常總稱為設(shè)值方法。定義時在實例變量名前加上 set。如:
// ARC- (void)setAge:(NSNumber *)age {_age = age;}// MRC- (void)setAge:(NSNumber *)age {if (_age) { [_age release]; } _age = [age retain];}取值方法(getter):用于檢索實例變量值的方法叫做取值方法。定義時直接使用實例變量名。如:
- (NSNumber *)age {return _age;}
4)合成取值方法:通常實例變量聲明時不以下畫線( _ )字符開頭,以字母開頭,并且此實例變量是私有(@private)的。只能在類內(nèi)部訪問。
在接口部分中使用 @property 指令標(biāo)識屬性,聲明實例變量的 setter 和 getter 方法。 - 如:@property int numerator, denominator;
在實現(xiàn)部分中使用 @synthesize 指令標(biāo)識屬性,實現(xiàn)實例變量的 setter 和 getter 方法。 - 如:@synthesize numerator, denominator;
1>、如果使用了 @property 指令,就不需要在實現(xiàn)部分聲明相應(yīng)的實例變量。當(dāng)然也可以再聲明相應(yīng)的實例變量,但是那不是必須要做的,編譯器會有一些提示。
- 可以不使用 @synthesize 指令,使用 @property 指令就足夠了,編譯器會自動為你生成 setter 和 getter 方法(聲明并實現(xiàn)),但是注意如果你不使用 @synthesize ,那么編譯器聲明的實例變量會以下劃線( _ )字符作為其名稱的第一個字符。
2>、@property 的修飾
在不寫任何修飾時,Xcode 會自動生成標(biāo)準(zhǔn)的 setter 和 getter 方法,寫修飾時 Xcode 會自動生成帶內(nèi)存管理的 setter 方法,標(biāo)準(zhǔn) getter 方法。
參數(shù)分類:
讀寫屬性:readwrite/readonlysetter 處理:assign/retain/copy原子性:atomic/nonatomic方法名:setter = method / getter = method引用型:strong/weak可選性:nonnull/nullable/null_unspecified/null_resettable // Xcode 7 新增特性readwrite:可讀寫,生成 setter 和 getter 方法。默認(rèn)。readonly :只讀,只生成 getter 方法。assign :修飾普通類型,在 setter 方法中直接賦值。默認(rèn)。簡單賦值,不更改引用計數(shù)。如:@property (nonatomic, assign)int age;retain :修飾 OC 對象,在 setter 方法中 release 舊值,retain 新值。釋放舊的對象,將舊對象的值賦予輸入對象,再提高輸入對象的引用計數(shù)為 1。如:@property (nonatomic, retain)Dog *dog;copy :修飾 NSString 類型,在 setter 方法中 release 舊值,copy 新值。建立了一個相同的對象,地址不同(retain:指針拷貝 copy:內(nèi)容拷貝)。如:@property (nonatomic, copy)NSString *name;atomic :原子性,默認(rèn)。是 OC 使用的一種線程保護技術(shù),防止在寫入未完成的時候被另外一個線程讀取,造成數(shù)據(jù)錯誤。給 setter 和 getter 方法加鎖,保證多線程安全。nonatomic:非原子性,禁止多線程,變量保護,提高性能。不給 setter 和 getter 方法加鎖,執(zhí)行相對快點。setter = method:指定 setter 方法的方法名。 如:@property (nonatomic, setter = setIsRich)BOOL rich; 將 rich 的 setter 方法重命名為 setIsRich 。getter = method:指定 getter 方法的方法名。 如:@property (nonatomic, getter = isRich)BOOL rich; 將 rich 的 getter 方法重命名為 isRich 。strong :強引用,在 OC 中對象默認(rèn)都是 strong。(ARC 下的)和(MRC)retain 一樣 (默認(rèn))。viewController 對根視圖是強引用,view addSubviews 方法是向數(shù)組中添加子視圖,數(shù)組會對子視圖強引用。weak :弱引用,weak 的作用,一旦沒有強引用,會被立即釋放。(ARC 下的)和(MRC)assign 一樣。蘋果從 StoryBoard 拖線默認(rèn)是 weak。weak 當(dāng)指向的內(nèi)存釋放掉后自動 nil 化,防止野指針。nonnull :不可為空nullable :可以為空null_unspecified:不確定是否可以為空(極少情況)null_resettable :set 方法可以為 nil,get 方法不可返回 nil,只能用在屬性的聲明中。
5)點運算符(點語法):訪問的是方法(setter/getter 方法),不是實例變量。
合成取值方法中可以使用點運算符訪問屬性,也可以對自定義的方法使用點運算符,如語句 myFraction.print ,并未考慮編碼風(fēng)格是否良好。
點運算符通常用在屬性上,用于設(shè)置或取得實例變量的值。做其它工作的方法通常不是由點運算符執(zhí)行的,而是使用傳統(tǒng)的方括號形式的消息表達式作為首選的語法。
6)尖運算符(->):當(dāng)實例變量定義為 @public 類型時,實例對象可以使用符號 “->” 直接訪問實例變量。 如:car -> _speed = 80; int a = car -> _speed;
- 7)局部變量:是基本的 C 數(shù)據(jù)類型,并沒有默認(rèn)的初始值,所以在使用前要先賦值。
局部對象變量:默認(rèn)初始值為 nil 。
- 方法的參數(shù)名也是局部變量。執(zhí)行方法時,通過方法傳遞的任何參數(shù)都被復(fù)制到局部變量中。因為方法使用參數(shù)的副本,所以不能改變通過方法傳遞的原值。
- 如果參數(shù)是對象,可以更改其中的實例變量值。當(dāng)你傳遞一個對象作為參數(shù)時,實際上是傳遞了一個數(shù)據(jù)存儲位置的引用。
靜態(tài)變量:在局部變量聲明前加上關(guān)鍵字 static ,可以使局部變量保留多次調(diào)用一個方法所得的值。靜態(tài)變量的初始值為 0 。
- 很多情況下想要將變量定義為全局變量,但不是外部變量,可以在包含這個特定類型實現(xiàn)的文件中將這個變量定義為 static 。
外部變量:在方法外定義的變量不僅是全局變量,而且是外部變量。
使用外部變量時,必須遵循下面這條重要原則:變量必須定義在源文件中的某個位置。即在所有的方法和函數(shù)之外定義變量,并且前面不加關(guān)鍵字 extern 。在所有的函數(shù)之外聲明變量,在聲明前面加上關(guān)鍵字 extern 。
處理外部變量時,變量可以在許多地方聲明為 extern ,但是只能定義一次。
4、繼承、多態(tài)
1)繼承的概念作用于整個繼承鏈。
類的每個實例(對象)都擁有自己的實例變量,即使這些實例變量是繼承來的。
繼承通常用于擴展一個類。不能通過繼承刪除或減少方法。
為什么需要創(chuàng)建子類:(1)希望繼承一個類的函數(shù),也需加入一些新的方法和/或?qū)嵗兞俊?#xff08;2)希望創(chuàng)建一個類的特別版本。(3)希望通過覆寫一個或多個方法 來改變類的默認(rèn)行為。
2)多態(tài):使不同的類共享相同方法名稱的能力稱為多態(tài)。能夠使來自不同類的對象定義相同名稱的方法。
- 3)動態(tài)類型:id 類型的對象。在運行時而不是編譯時確定對象所屬的類,能使程序直到執(zhí)行時才確定對象所屬的類。
- 靜態(tài)類型:將一個變量定義為特定類的對象時,使用的是靜態(tài)類型。靜態(tài)指的是對存儲在變量中的對象類型進行顯示的聲明。
動態(tài)綁定:在運行時而不是編譯時確定對象需要調(diào)用的方法,能使程序直到執(zhí)行時才確定實際要調(diào)用的對象方法。
- OC 系統(tǒng)總是跟蹤對象所屬的類。
id 類型的對象先判定對象所屬的類(動態(tài)類型),然后在運行時確定需要動態(tài)調(diào)用的方法,而不是在編譯的時候(動態(tài)綁定)。
為什么還要關(guān)心靜態(tài)類型:(1)它能更好的在程序編譯階段而不是運行時指出錯誤。(2)它能提高程序的可讀性。
如果使用動態(tài)類型來調(diào)用一個方法,需要注意一下規(guī)則:如果在多個類中實現(xiàn)名稱相同的方法,那么每個方法都必須符合各個參數(shù)的類型和返回值類型,這樣編譯器才能為消息表達式生成正確的代碼。
處理動態(tài)類型的方法:
以下總結(jié)了 NSObject 類所支持的一些基本方法,其中,class-object 是一個類對象(通常是由 class 方法產(chǎn)生的),selector 是一個 SEL 類型的值(通常是由 @selector 指令產(chǎn)生的)。
- (BOOL)isKindOfClass:class-object // 對象是不是 class-object 或其子類的成員- (BOOL)isMemberOfClass:class-object // 對象是不是 class-object 的成員+ (BOOL)isSubclassOfClass:class-object // 某個類是否是指定類的子類- (BOOL)respondsToSelector:selector // 對象是否能夠響應(yīng) selector 所指定的方法+ (BOOL)instancesRespondToSelector:selector // 指定的類實例是否能響應(yīng) selector- (id)performSelector:selector // 應(yīng)用 selector 指定的方法- (id)performSelector:selector withObject:object // 應(yīng)用 selector 指定的方法,傳遞參數(shù) object- (id)performSelector:selector withObject:object1 withObject:object2 // 應(yīng)用 selector 指定的方法,傳遞參數(shù) object1 和 object2[Square class] // 從名為 Square 的類中獲得類對象[mySquare class] // 知道對象 mySquare 所屬的類@selector(alloc) // 為名為 alloc 的方法生成一個 SEL 類型的值。
4)消除 performSelector: 方法警告
#pragma clang diagnostic push#pragma clang diagnostic ignored "-Warc-performSelector-leaks"// performSelector: 方法#pragma clang diagnostic pop
5、協(xié)議、代理
1)協(xié)議:是多個類共享的一個方法列表。協(xié)議中列出的方法沒有相應(yīng)的實現(xiàn),計劃由其他人來實現(xiàn)。協(xié)議中列出的方法,有些是可以選擇實現(xiàn),有些是必須實現(xiàn)。
1>、如果你定義了自己的協(xié)議,那么不必由自己實現(xiàn)它。但是,這就告訴其他程序員,如果要采用這項協(xié)議,則必須實現(xiàn)這些方法。這些方法可以從超類繼承。
協(xié)議不引用任何類,它是無類的。
分類也可以采用一項協(xié)議。
2>、定義一個協(xié)議很簡單:只要使用 @protocol 指令,后面跟上你給出的協(xié)議名稱。定義一項協(xié)議時,可以擴展現(xiàn)有協(xié)議的定義。
@protocol PlayerDelegate <NSObject>- (void)end;@end3>、協(xié)議的修飾
@optional:該指令之后列出的所有方法都是可選的。@required:該指令之后列出的所有方都是必須實現(xiàn)的,默認(rèn)。由于 OC 是弱語法,雖然字面上是必須,但編譯器并沒有強求實現(xiàn)。4>、協(xié)議的聲明
@protocol protocol-name5>、協(xié)議的檢查
// 檢查一個對象是否遵守某項協(xié)議。- (BOOL)conformsToProtocol:(Protocol *)aProtocol;// 用于獲取一個協(xié)議名稱,并產(chǎn)生一個 Protocol 對象,conformsToProtocol: 方法期望這個對象作為它的參數(shù)。@protocol(Drawing)// 檢查對象是否能夠響應(yīng) selector 所指定的方法。- (BOOL)respondsToSelector:selector// 為名為 alloc 的方法生成一個 SEL 類型的值。@selector(alloc)
2)非正式協(xié)議:實際上是一個分類,列出了一組方法但并沒有實現(xiàn)它們。非正式協(xié)議通常是為根類定義的,有時,非正式協(xié)議也稱為抽象協(xié)議。
聲明非正式協(xié)議的類自己并不實現(xiàn)這些方法,并且選擇實現(xiàn)這些方法的子類需要在它的接口部分重新聲明這些方法,同時還要實現(xiàn)這些方法中的一個或多個。
指令 @optional 添加到 OC 2.0 語言中,用于取代非正式協(xié)議的使用。
3)代理:協(xié)議也是一種兩個類之間的接口定義。定義了協(xié)議的類可以看作是將協(xié)議定義的方法代理給了實現(xiàn)它們的類。
- 代理設(shè)計模式的作用:
- 1、A 對象監(jiān)聽 B 對象的一些行為,A 成為 B 的代理
- 2、B 對象想告訴 A 對象一些事情,A 成為 B 的代理
- 代理設(shè)計模式的總結(jié):
- 1、如果你想監(jiān)聽別人的一些行為,那么你就要成為別人的代理
- 2、如果你想告訴別人一些事情,那么就讓別人成為你的代理
- 代理設(shè)計模式的開發(fā)步驟:
- 1、擬一份協(xié)議(協(xié)議名字的格式:控件名 + Delegate),在協(xié)議里面聲明一些代理方法(一般代理方法都是 @optional)
- 2、聲明一個代理屬性:@property (nonatomic, weak) id delegate;
- 3、在內(nèi)部發(fā)生某些行為時,調(diào)用代理對應(yīng)的代理方法,通知代理內(nèi)部發(fā)生什么事
- 4、設(shè)置代理:xxx.delegate = yyy;
- 5、yyy 對象遵守協(xié)議,實現(xiàn)代理方法
- 代理設(shè)計模式的作用:
6、為什么 Objective-C 的方法調(diào)用要用方括
為什么 Objective-C 的方法調(diào)用要用方括號 [obj foo],而不是別的語言常常使用的點 obj.foo ?
首先要說的是,Objective-C 的歷史相當(dāng)久遠,如果你查 wiki 的話,你會發(fā)現(xiàn):Objective-C 和 C++ 這兩種語言的發(fā)行年份都是 1983 年。在設(shè)計之初,二者都是作為 C 語言的面向?qū)ο蟮慕影嗳?#xff0c;希望成為事實上的標(biāo)準(zhǔn)。最后結(jié)果大家都知道了,C++ 最終勝利了,而 Objective-C 在之后的幾十年中,基本上變成了蘋果自己家玩的玩具。不過最終,由于 iPhone 的出現(xiàn),Objective-C 迎來了第二春,在 TOBIE 語言排行榜上,從 20 名開外一路上升,排名曾經(jīng)超越過 C++,達到了第三名(下圖),但是隨著 Swift 的出現(xiàn),Objective-C 的排名則一路下滑。
Objective-C 在設(shè)計之初參考了不少 Smalltalk 的設(shè)計,而消息發(fā)送則是向 Smalltalk 學(xué)來的。Objective-C 當(dāng)時采用了方括號的形式來表示發(fā)送消息,為什么沒有選擇用點呢?我個人覺得是,當(dāng)時市面上并沒有別的面向?qū)ο笳Z言的設(shè)計參考,而 Objective-C 「發(fā)明」了方括號的形式來給對象發(fā)消息,而 C++ 則「發(fā)明」了用點的方式來 “發(fā)消息”。有人可能會爭論說 C++ 的「點」并不是真正的發(fā)消息,但是其實二者都是表示「調(diào)用對象所屬的成員函數(shù)」。
另外,有讀者評論說使用方括號的形式是為了向下兼容 C 語言,我并不覺得中括號是唯一選擇,C++ 不也兼容了 C 語言么?Swift 不也可以調(diào)用 C 函數(shù)么?
最終,其實是 C++ 的「發(fā)明」顯得更舒服一些,所以后來的各種語言都借鑒了 C++ 的這種設(shè)計,也包括 Objective-C 在內(nèi)。Objective-C 2.0 版本中,引入了 dot syntax,即:
a = obj.foo 等價于 a = [obj foo]obj.foo = 1 則等價于 [obj setFoo:1]Objective-C 其實在設(shè)計之中確實是比較特立獨行的,除了方括號的函數(shù)調(diào)用方式外,還包括比較長的,可讀性很強的函數(shù)命名風(fēng)格。
我個人并不討厭 Objective-C 的這種設(shè)計,但是從 Swift 語言的設(shè)計來看,蘋果也開始放棄一些 Objective-C 的特點了,比如就去掉了方括號這種函數(shù)調(diào)用方式。
所以,回到我們的問題,我個人認(rèn)為,答案就是:Objective-C 在 1983 年設(shè)計的時候,并沒有什么有效的效仿對象,于是就發(fā)明了一種有特點的函數(shù)調(diào)用方式,現(xiàn)在看起來,這種方式比點操作符還是略遜一籌。
大多數(shù)語言一旦被設(shè)計好,就很難被再次修改,應(yīng)該說 Objective-C 發(fā)明在 30 年前,還是非常優(yōu)秀的,它的面向?qū)ο蠡O(shè)計得非常純粹,比 C++ 要全面得多,也比 C++ 要簡單得多。
轉(zhuǎn)載于:https://www.cnblogs.com/QianChia/p/5780671.html
總結(jié)
以上是生活随笔為你收集整理的iOS - OC 面向对象语法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 第一章 概率论的基本概念
- 下一篇: [hackinglab][CTF][基础