iOS當中函數(shù)式編程是通過Block來實現(xiàn)的歼争,前些天看到一段代碼,目的是改造UIButton來實現(xiàn)通過Block來定義button的響應事件,正好是實現(xiàn)函數(shù)式編程的一個方法堪置,現(xiàn)在過來分析一下。
首先张惹,iOS 官方提供的UIButton定義響應事件處理機制使用addTarget舀锨,如下所示:
[self.btn addTarget:self
action:@selector(btnAction)
forControlEvents:UIControlEventTouchUpInside];
首先定義了btnAction函數(shù),然后通過上述代碼來進行注冊宛逗。對于每一個按鈕坎匿,都需要定義一個函數(shù)來實現(xiàn)處理方法,當然不同的函數(shù)可以復用同一個方法雷激。但在應用當中替蔬,很多按鈕的處理功能是比較簡單的,使用函數(shù)來處理在代碼閱讀性上也不方便屎暇,你還需要在整個文件當中找到函數(shù)定義的位置承桥,使用Block首先就能解決這個問題。
再來看下如何使用Block來實現(xiàn)根悼。
首先需要對UIButton進行一個分類快毛,代碼如下:
typedefvoid(^btnBlock)(UIButton*btn);
@interfaceUIButton(buttonBlock)
- (void)addBlock:(btnBlock) block;
@end
static char propertyBlock;
@implementation UIButton(buttonBlock)
- (void)addBlock:(btnBlock)block
{
objc_setAssociatedObject(self
, &propertyBlock,
block,
OBJC_ASSOCIATION_COPY_NONATOMIC);
[self addTarget:self
action:@selector(btnAction)
forControlEvents:UIControlEventTouchUpInside];
}
- (void)btnAction
{
btnBlock block = objc_getAssociatedObject(self, &propertyBlock);
block(self);
}
@end
上述代碼在UIButton的基礎上增加了一個addBlock接口,其接入一個Block作為按鈕的響應處理方法番挺。上面代碼本質上其實也是調用了addTarget方法唠帝,只不過其內部對其進行了封裝。將傳入的Block保存成一個成員變量玄柏,然后使用addTarget注冊一個內部的處理方法襟衰,內部處理方法再調用Block。上述代碼當中使用了runtime機制:objc_setAssociatedObject粪摘,objc_getAssociatedObject瀑晒。看起來不知道是干嘛的徘意,其實使用runtime主要是解決一個問題:分類無法擴展原有類的成員變量苔悦,只能增加新的方法。你也可以在分類當中這樣定義
@property (nonatomic,strong) btnBlock actionBlock;
但是這樣并不能給分類增加成員椎咧,你只是定義了兩個新的方法:get與set玖详,你還需要實現(xiàn)get與set把介,如果你直接在代碼當中使用actionBlock = xxx,你將會得到錯誤蟋座。
objc_setAssociatedObject的作用是將兩個對象進行關聯(lián)拗踢,在使用當中可以通過該方法來動態(tài)在分類當中增加成員變量。上述代碼可以理解為先Block存放在一個成員變量當中向臀,然后在觸發(fā)時再從成員變量當中讀取Block運行巢墅。
最后在代理當中的調用如下所示:
[self.btnaddBlock:^(UIButton*btn) {
self.view.backgroundColor= [UIColorwhiteColor];
}];
然后再擴展一下iOS當中Block的一些?基本知識,首先Block當中的定義如下所示:
void(^localBlock)(NSString*name,NSIntegerage) = ^(NSString*name,NSIntegerage)
{
NSLog(@"%@ is %ld yeas old",name,age);
};
Block一個好處是可以引用Block定義處外部的變量券膀,也就是閉包君纫。但有一點要注意的是,如果外部是類似NSInteger變量芹彬,其在Block定義時庵芭,會對NSInteger做一個copy備份,其會作為一個const對象存放其中雀监,不能改變其值,也不會影響到Block外部的值眨唬。其實不完全是這樣会前,即使是一個NSString*類型的值,其在Block內部也是不可以修改的匾竿。應該這樣理解瓦宜,所以Block外部的變量在Block當中都不能修改,我們能夠修改的是變量指向的對象岭妖,因為在iOS當中變量都是指針临庇,我們在Block當中不能修改指針的指向,卻可以修改指向對象的內容昵慌。如果的確需要修改變量的值假夺,需要在外部變量定義處增加__block的修飾符。這樣在Block定義當中會傳入指針的引用斋攀,這樣就能夠修改其指向了已卷。另外如果要在Block當中引用self成員時,需要將self賦給一個指針淳蔼,使用__weak來進行修飾侧蘸,不然很容易造成交叉引用,使資源無法釋放鹉梨。