前言html
ObjC的語法主要基於smalltalk進行設計的,除了提供常規的面向對象特性外,還增長了不少其餘特性,這一節將重點介紹ObjC中一些經常使用的語法特性。固然這些內容雖然和其餘高級語言命名不同,可是咱們均可以在其中找到他們的影子,在文章中我也會對比其餘語言進行介紹,這一節的重點內容以下:編程
協議protocol閉包
在ObjC中使用@protocol定義一組方法規範,實現此協議的類必須實現對應的方法。熟悉面向對象的童鞋都知道接口自己是對象行爲描述的協議規範。也就是說在ObjC中@protocol和其餘語言的接口定義是相似的,只是在ObjC中interface關鍵字已經用於定義類了,所以它不會再像C#、Java中使用interface定義接口了。框架
假設咱們定義了一個動物的協議AnimalDelegate,人員Person這個類須要實現這個協議,請看下面的代碼:異步
AnimalDelegate.h異步編程
1 // 2 // AnimalDelegate.h 3 // Protocol&Block&Category 4 // 5 // Created by Kenshin Cui on 14-2-2. 6 // Copyright (c) 2014年 Kenshin Cui. All rights reserved. 7 // 8 9 10 //定義一個協議 11 @protocol AnimalDelegate <NSObject> 12 13 @required //必須實現的方法 14 -(void)eat; 15 16 @optional //可選實現的方法 17 -(void)run; 18 -(void)say; 19 -(void)sleep; 20 21 @end
Person.h函數
1 // 2 // Person.h 3 // Protocol&Block&Category 4 // 5 // Created by Kenshin Cui on 14-2-2. 6 // Copyright (c) 2014年 Kenshin Cui. All rights reserved. 7 // 8 9 #import <Foundation/Foundation.h> 10 #import "AnimalDelegate.h" 11 12 @interface Person : NSObject<AnimalDelegate> 13 14 -(void)eat; 15 16 @end
Person.mui
1 // 2 // Person.m 3 // Protocol&Block&Category 4 // 5 // Created by Kenshin Cui on 14-2-2. 6 // Copyright (c) 2014年 Kenshin Cui. All rights reserved. 7 // 8 9 #import "Person.h" 10 11 @implementation Person 12 13 -(void)eat{ 14 NSLog(@"eating..."); 15 } 16 17 @end
這裏須要說明幾點:atom
事實上在ObjC中協議的更多做用是用於約束一個類必須實現某些方法,而從面向對象的角度而言這個類跟接口並不必定存在某種天然關係,多是兩個徹底不一樣意義上的事物,這種模式咱們稱之爲代理模式(Delegation)。在Cocoa框架中大量採用這種模式實現數據和UI的分離,並且基本上全部的協議都是以Delegate結尾。spa
如今假設須要設計一個按鈕,咱們知道按鈕都是須要點擊的,在其餘語言中一般會引入事件機制,只要使用者訂閱了點擊事件,那麼點擊的時候就會觸發執行這個事件(這是對象之間解耦的一種方式:代碼注入)。可是在ObjC中沒有事件的定義,而是使用代理來處理這個問題。首先在按鈕中定義按鈕的代理,同時使用協議約束這個代理(事件的觸發者)必須實現協議中的某些方法,當按鈕處理過程當中查看代理是否實現了這個方法,若是實現了則調用這個方法。
KCButton.h
1 // 2 // KCButton.h 3 // Protocol&Block&Category 4 // 5 // Created by Kenshin Cui on 14-2-2. 6 // Copyright (c) 2014年 Kenshin Cui. All rights reserved. 7 // 8 9 #import <Foundation/Foundation.h> 10 @class KCButton; 11 12 //一個協議能夠擴展另外一個協議,例如KCButtonDelegate擴展了NSObject協議 13 @protocol KCButtonDelegate <NSObject> 14 15 @required //@required修飾的方法必須實現 16 -(void)onClick:(KCButton *)button; 17 18 @optional //@optional修飾的方法是可選實現的 19 -(void)onMouseover:(KCButton *)button; 20 -(void)onMouseout:(KCButton *)button; 21 22 @end 23 24 @interface KCButton : NSObject 25 26 #pragma mark - 屬性 27 #pragma mark 代理屬性,同時約定做爲代理的對象必須實現KCButtonDelegate協議 28 @property (nonatomic,retain) id<KCButtonDelegate> delegate; 29 30 #pragma mark - 公共方法 31 #pragma mark 點擊方法 32 -(void)click; 33 34 @end
KCButton.m
1 // 2 // KCButton.m 3 // Protocol&Block&Category 4 // 5 // Created by Kenshin Cui on 14-2-2. 6 // Copyright (c) 2014年 Kenshin Cui. All rights reserved. 7 // 8 9 #import "KCButton.h" 10 11 @implementation KCButton 12 13 -(void)click{ 14 NSLog(@"Invoke KCButton's click method."); 15 //判斷_delegate實例是否實現了onClick:方法(注意方法名是"onClick:",後面有個:) 16 //避免未實現ButtonDelegate的類也做爲KCButton的監聽 17 if([_delegate respondsToSelector:@selector(onClick:)]){ 18 [_delegate onClick:self]; 19 } 20 } 21 22 @end
MyListener.h
1 // 2 // MyListener.h 3 // Protocol&Block&Category 4 // 5 // Created by Kenshin Cui on 14-2-2. 6 // Copyright (c) 2014年 Kenshin Cui. All rights reserved. 7 // 8 9 #import <Foundation/Foundation.h> 10 @class KCButton; 11 @protocol KCButtonDelegate; 12 13 @interface MyListener : NSObject<KCButtonDelegate> 14 -(void)onClick:(KCButton *)button; 15 @end
MyListener.m
1 // 2 // MyListener.m 3 // Protocol&Block&Category 4 // 5 // Created by Kenshin Cui on 14-2-2. 6 // Copyright (c) 2014年 Kenshin Cui. All rights reserved. 7 // 8 9 #import "MyListener.h" 10 #import "KCButton.h" 11 12 @implementation MyListener 13 -(void)onClick:(KCButton *)button{ 14 NSLog(@"Invoke MyListener's onClick method.The button is:%@.",button); 15 } 16 @end
main.m
1 // 2 // main.m 3 // Protocol&Block&Category 4 // 5 // Created by Kenshin Cui on 14-2-2. 6 // Copyright (c) 2014年 Kenshin Cui. All rights reserved. 7 // 8 9 #import <Foundation/Foundation.h> 10 #import "KCButton.h" 11 #import "MyListener.h" 12 13 int main(int argc, const char * argv[]) { 14 @autoreleasepool { 15 16 KCButton *button=[[KCButton alloc]init]; 17 MyListener *listener=[[MyListener alloc]init]; 18 button.delegate=listener; 19 [button click]; 20 /* 結果: 21 Invoke KCButton's click method. 22 Invoke MyListener's onClick method.The button is:<KCButton: 0x1001034c0>. 23 */ 24 } 25 return 0; 26 }
咱們經過例子模擬了一個按鈕的點擊過程,有點相似於Java中事件的實現機制。經過這個例子咱們須要注意如下幾點內容:
代碼塊Block
在C#異步編程時咱們常常進行函數回調,因爲函數調用是異步執行的,咱們若是想讓一個操做執行完以後執行另外一個函數,則沒法按照正常代碼書寫順序進行編程,由於咱們沒法獲知前一個方法何時執行結束,此時咱們常常會用到匿名委託或者lambda表達式將一個操做做爲一個參數進行傳遞。其實在ObjC中也有相似的方法,稱之爲代碼塊(Block)。Block就是一個函數體(匿名函數),它是ObjC對於閉包的實現,在塊狀中咱們能夠持有或引用局部變量(不由想到了lambda表達式),同時利用Block你能夠將一個操做做爲一個參數進行傳遞(是否是想起了C語言中的函數指針)。在下面的例子中咱們將使用Block實現上面的點擊監聽操做:
KCButton.h
1 // 2 // KCButton.h 3 // Protocol&Block&Category 4 // 5 // Created by Kenshin Cui on 14-2-2. 6 // Copyright (c) 2014年 Kenshin Cui. All rights reserved. 7 // 8 9 #import <Foundation/Foundation.h> 10 @class KCButton; 11 typedef void(^KCButtonClick)(KCButton *); 12 13 @interface KCButton : NSObject 14 15 #pragma mark - 屬性 16 #pragma mark 點擊操做屬性 17 @property (nonatomic,copy) KCButtonClick onClick; 18 //上面的屬性定義等價於下面的代碼 19 //@property (nonatomic,copy) void(^ onClick)(KCButton *); 20 21 #pragma mark - 公共方法 22 #pragma mark 點擊方法 23 -(void)click; 24 @end
KCButton.m
1 // 2 // KCButton.m 3 // Protocol&Block&Category 4 // 5 // Created by Kenshin Cui on 14-2-2. 6 // Copyright (c) 2014年 Kenshin Cui. All rights reserved. 7 // 8 9 #import "KCButton.h" 10 11 12 @implementation KCButton 13 14 -(void)click{ 15 NSLog(@"Invoke KCButton's click method."); 16 if (_onClick) { 17 _onClick(self); 18 } 19 } 20 21 @end
main.m
1 // 2 // main.m 3 // Protocol&Block&Category 4 // 5 // Created by Kenshin Cui on 14-2-2. 6 // Copyright (c) 2014年 Kenshin Cui. All rights reserved. 7 // 8 9 #import <Foundation/Foundation.h> 10 #import "KCButton.h" 11 12 13 int main(int argc, const char * argv[]) { 14 15 KCButton *button=[[KCButton alloc]init]; 16 button.onClick=^(KCButton *btn){ 17 NSLog(@"Invoke onClick method.The button is:%@.",btn); 18 }; 19 [button click]; 20 /*結果: 21 Invoke KCButton's click method. 22 Invoke onClick method.The button is:<KCButton: 0x1006011f0>. 23 */ 24 25 26 return 0; 27 }
上面代碼中使用Block一樣實現了按鈕的點擊事件,關於Block總結以下:
分類Category
當咱們不改變原有代碼爲一個類擴展其餘功能時咱們能夠考慮繼承這個類進行實現,可是這樣一來使用時就必須定義成新實現的子類才能擁有擴展的新功能。如何在不改變原有類的狀況下擴展新功能又能夠在使用時沒必要定義新類型呢?咱們知道若是在C#中可使用擴展方法,其實在ObjC中也有相似的實現,就是分類Category。利用分類,咱們就能夠在ObjC中動態的爲已有類添加新的行爲(特別是系統或框架中的類)。在C#中字符串有一個Trim()方法用於去掉字符串先後的空格,使用起來特別方便,可是在ObjC中卻沒有這個方法,這裏咱們不妨經過Category給NSString添加一個stringByTrim()方法:
NSString+Extend.h
1 // 2 // NSString+Extend.h 3 // Protocol&Block&Category 4 // 5 // Created by Kenshin Cui on 14-2-2. 6 // Copyright (c) 2014年 Kenshin Cui. All rights reserved. 7 // 8 9 #import <Foundation/Foundation.h> 10 11 @interface NSString (Extend) 12 -(NSString *)stringByTrim; 13 @end
NSString+Extend.m
1 // 2 // NSString+Extend.m 3 // Protocol&Block&Category 4 // 5 // Created by Kenshin Cui on 14-2-2. 6 // Copyright (c) 2014年 Kenshin Cui. All rights reserved. 7 // 8 9 #import "NSString+Extend.h" 10 11 @implementation NSString (Extend) 12 -(NSString *)stringByTrim{ 13 NSCharacterSet *character= [NSCharacterSet whitespaceCharacterSet]; 14 return [self stringByTrimmingCharactersInSet:character]; 15 } 16 @end
main.m
1 // 2 // main.m 3 // Protocol&Block&Category 4 // 5 // Created by Kenshin Cui on 14-2-2. 6 // Copyright (c) 2014年 Kenshin Cui. All rights reserved. 7 // 8 9 #import <Foundation/Foundation.h> 10 #import "NSString+Extend.h" 11 12 13 int main(int argc, const char * argv[]) { 14 15 NSString *name=@" Kenshin Cui "; 16 name=[name stringByTrim]; 17 NSLog(@"I'm %@!",name); //結果:I'm Kenshin Cui! 18 19 return 0; 20 }
經過上面的輸出結果咱們能夠看出已經成功將@」 Kenshin Cui 」兩端的空格去掉了。分類文件名通常是「原有類名+分類名稱」,分類的定義是經過在原有類名後加上」(分類名)」來定義的(注意聲明文件.h和實現文件.m都是如此)。
原文連接:http://www.cnblogs.com/kenshincui/p/3869639.html#3285408