1??Block的修飾
ARC情況下(
ARC是iOS 5推出的新功能亩鬼,全稱(chēng)叫 ARC(Automatic Reference Counting)本谜。簡(jiǎn)單地說(shuō)纹冤,就是代碼中自動(dòng)加入了retain/release清酥,原先需要手動(dòng)添加的用來(lái)處理內(nèi)存管理的引用計(jì)數(shù)的代碼可以自動(dòng)地由編譯器完成了雄可。
該機(jī)能在 iOS 5/ Mac OS X 10.7 開(kāi)始導(dǎo)入凿傅,利用 Xcode4.2 可以使用該機(jī)能。簡(jiǎn)單地理解ARC数苫,就是通過(guò)指定的語(yǔ)法聪舒,讓編譯器(LLVM 3.0)在編譯代碼時(shí),自動(dòng)生成實(shí)例的引用計(jì)數(shù)管理部分代碼虐急。有一點(diǎn)箱残,ARC并不是GC,它只是一種代碼靜態(tài)分析(Static Analyzer)工具止吁。
)
1.如果用copy修飾Block被辑,該Block就會(huì)存儲(chǔ)在堆空間。則會(huì)對(duì)Block的內(nèi)部對(duì)象進(jìn)行強(qiáng)引用敬惦,導(dǎo)致循環(huán)引用盼理。內(nèi)存無(wú)法釋放。
解決方法:
新建一個(gè)指針(__weak typeof(Target) weakTarget = Target )指向Block代碼塊里的對(duì)象俄删,然后用weakTarget進(jìn)行操作宏怔。就可以解決循環(huán)引用問(wèn)題奏路。
2.如果用weak修飾Block,該Block就會(huì)存放在楇铮空間鸽粉。不會(huì)出現(xiàn)循環(huán)引用問(wèn)題。
MRC情況下
用copy修飾后妨猩,如果要在Block內(nèi)部使用對(duì)象潜叛,則需要進(jìn)行(__block typeof(Target) blockTarget = Target )處理秽褒。在Block里面用blockTarget進(jìn)行操作壶硅。
2??Block的定義格式
返回值類(lèi)型(^block變量名)(形參列表) = ^(形參列表) {
};
默認(rèn)情況下,Block內(nèi)部不能修改外面的局部變量
Block內(nèi)部可以修改使用__block修飾的局部變量
3??Block的模式
1.無(wú)參數(shù)無(wú)返回值的Block
2.有參數(shù)無(wú)返回值的Block
3.有參數(shù)有返回值的Block
4??Block簡(jiǎn)單用法舉例
①無(wú)參數(shù)無(wú)返回值的Block
/**
*? 無(wú)參數(shù)無(wú)返回值的Block
*/
-(void)func1{
? ? /**
? ? *? void :就是無(wú)返回值
? ? *? emptyBlock:就是該block的名字
? ? *? ():這里相當(dāng)于放參數(shù)。由于這里是無(wú)參數(shù)销斟,所以就什么都不寫(xiě)
? ? */
? ? void (^emptyBlock)() = ^(){
? ? ? ? NSLog(@"無(wú)參數(shù),無(wú)返回值的Block");
? ? };
? ? emptyBlock();
}
②有參數(shù)無(wú)返回值的Block
/**
? ? *? 調(diào)用這個(gè)block進(jìn)行兩個(gè)參數(shù)相加
? ? *
? ? *? @param int 參數(shù)A
? ? *? @param int 參數(shù)B
? ? *
? ? *? @return 無(wú)返回值
? ? */
? ? void (^sumBlock)(int ,int ) = ^(int a,int b){
? ? ? ? NSLog(@"%d + %d = %d",a,b,a+b);
? ? };
? ? /**
? ? *? 調(diào)用這個(gè)sumBlock的Block庐椒,得到的結(jié)果是20
? ? */
? ? sumBlock(10,10);
③有參數(shù)有返回值的Block
/**
? ? *? 有參數(shù)有返回值
? ? *
? ? *? @param NSString 字符串1
? ? *? @param NSString 字符串2
? ? *
? ? *? @return 返回拼接好的字符串3
? ? */? ?
? ? NSString* (^logBlock)(NSString *,NSString *) = ^(NSString * str1,NSString *str2){
? ? ? ? return [NSString stringWithFormat:@"%@%@",str1,str2];
? ? };
? ? //調(diào)用logBlock,輸出的是 我是Block
? ? NSLog(@"%@", logBlock(@"我是",@"Block"));
5??Block結(jié)合typedef使用
自己定義一個(gè)Block類(lèi)型,用定義的類(lèi)型去創(chuàng)建Block蚂踊,更加簡(jiǎn)單便捷约谈。
這里舉例一個(gè)Block回調(diào)修改上一下界面的背景顏色。
ViewController1 控制器1犁钟,ViewController2 控制器2
控制器1跳轉(zhuǎn)到控制器2棱诱,然后在控制器2觸發(fā)事件回調(diào)修改控制器1的背景顏色為紅色。
ViewController2的實(shí)現(xiàn)
#import
@interface ViewController2 : UIViewController
/**
*? 定義了一個(gè)changeColor的Block涝动。這個(gè)changeColor必須帶一個(gè)參數(shù)迈勋,這個(gè)參數(shù)的類(lèi)型必須為id類(lèi)型的
*? 無(wú)返回值
*? @param id
*/
typedef void(^changeColor)(id);
/**
*? 用上面定義的changeColor聲明一個(gè)Block,聲明的這個(gè)Block必須遵守聲明的要求。
*/
@property (nonatomic, copy) changeColor backgroundColor;
@end
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
? ? //聲明一個(gè)顏色
? ? UIColor *color = [UIColor redColor];
? ? //用剛剛聲明的那個(gè)Block去回調(diào)修改上一界面的背景色
? ? self.backgroundColor(color);
}
ViewController1的實(shí)現(xiàn)
-(void)touchesBegan:(NSSet?*)touches?withEvent:(UIEvent?*)event{
ViewController2?*vc?=[[ViewController2?alloc]init];
//?回調(diào)修改顏色
vc.backgroundColor?=?^(UIColor?*color){
self.view.backgroundColor?=?color;
};
[self.navigationController?pushViewController:vc?animated:YES];
}
=========================================================================================
1.block簡(jiǎn)介
在 iOS中醋粟, block一共分三種靡菇。
(1)全局靜態(tài) block,不會(huì)訪問(wèn)任何外部變量米愿,執(zhí)行完就銷(xiāo)毀厦凤。
^{
? ? ? ? NSLog(@"Hello World!");
? ? }();
(2)保存在棧中的 block,當(dāng)函數(shù)返回時(shí)會(huì)被銷(xiāo)毀育苟,和第一種的區(qū)別就是調(diào)用了外部變量较鼓。
? ? [UIView animateWithDuration:3 animations:^{
? ? ? ? self.view.backgroundColor = [UIColor redColor];
? ? }];
(3)保存在堆中的 block,當(dāng)引用計(jì)數(shù)為 0 時(shí)會(huì)被銷(xiāo)毀违柏。例如按鈕的點(diǎn)擊事件笨腥,一直存在,即使執(zhí)行過(guò)勇垛,也不銷(xiāo)毀脖母,因?yàn)榘粹o還可能被點(diǎn)擊,持有按鈕的View被銷(xiāo)毀闲孤,它才會(huì)被銷(xiāo)毀谆级。
#import
typedef void(^ButtonClickBlcok)();
@interface TestView : UIView
@property (nonatomic, copy) ButtonClickBlcok buttonClickBlcok;
@end
#import "TestView.h"
@implementation TestView
- (IBAction)buttonClick:(id)sender {
? ? if (self.buttonClickBlcok) {
? ? ? ? self.buttonClickBlcok();
? ? }
}
@end
2.block優(yōu)點(diǎn)
block的代碼可讀性更好烤礁。因?yàn)閼?yīng)用block和實(shí)現(xiàn)block的地方在一起。代理的聲明和實(shí)現(xiàn)就分開(kāi)來(lái)了肥照,在兩個(gè)類(lèi)中脚仔。代理使用起來(lái)也更麻煩,因?yàn)橐暶鲄f(xié)議舆绎、聲明代理鲤脏、遵守協(xié)議、實(shí)現(xiàn)協(xié)議里的方法吕朵。block不需要聲明猎醇,也不需要遵守,只需要聲明和實(shí)現(xiàn)就可以了努溃。
block是一種輕量級(jí)的回調(diào)硫嘶,可以直接訪問(wèn)上下文,由于block的代碼是內(nèi)聯(lián)的梧税,運(yùn)行效率更高沦疾。block就是一個(gè)對(duì)象,實(shí)現(xiàn)了匿名函數(shù)的功能第队。所以我們可以把block當(dāng)做一個(gè)成員變量哮塞、屬性、參數(shù)使用凳谦,使用起來(lái)非常靈活忆畅。像用AFNetworking請(qǐng)求數(shù)據(jù)和GCD實(shí)現(xiàn)多線程,都使用了block回調(diào)晾蜘。
3.block缺點(diǎn)
blcok的運(yùn)行成本高邻眷。block出棧需要將使用的數(shù)據(jù)從棧內(nèi)存拷貝到堆內(nèi)存,當(dāng)然對(duì)象的話就是引用計(jì)數(shù)加1剔交,使用完或者block置nil后才銷(xiāo)毀肆饶。delegate只是保存了一個(gè)對(duì)象指針(一定要用week修飾delegate,不然也會(huì)循環(huán)引用)岖常,直接回調(diào)驯镊,沒(méi)有額外消耗。就像C的函數(shù)指針竭鞍,只多做了一個(gè)查表動(dòng)作板惑。
block容易造成循環(huán)引用,而且不易察覺(jué)偎快。因?yàn)闉榱薭lcok不被系統(tǒng)回收冯乘,所以我們都用copy關(guān)鍵字修飾,實(shí)行強(qiáng)引用晒夹。block對(duì)捕獲的變量也都是強(qiáng)引用裆馒,所以就會(huì)造成循環(huán)引用姊氓。
#import "ViewController.h"
typedef void(^TestBlock)(void);
@interface ViewController ()
{
? ? void (^_testCycleBlock)(void);
}
@end
@implementation ViewController
- (void)viewDidLoad {
? ? [super viewDidLoad];
? ? __weak ViewController *weakSelf = self;
? ? _testCycleBlock = ^{
? ? ? ? /**
? ? ? ? ? //引發(fā)循環(huán)引用
? ? ? ? ? NSLog(@"%@", self);
? ? ? ? */
? ? ? ? //防止循環(huán)引用
? ? ? ? NSLog(@"%@", weakSelf);
? ? };
}
@end
4.如何使用
優(yōu)先使用block。
如果回調(diào)函數(shù)很多喷好,多余三個(gè)使用代理翔横。
如果回調(diào)的很頻繁,次數(shù)很多梗搅,像UITableview禾唁,每次初始化、滑動(dòng)无切、點(diǎn)擊都會(huì)回調(diào)荡短,使用代理。
??block和代理都各有優(yōu)缺點(diǎn)订雾,所以我們一定要理解區(qū)分使用場(chǎng)景肢预,應(yīng)用適合的回調(diào)方式矛洞。優(yōu)化APP的性能洼哎,提高流暢性,從點(diǎn)滴做起沼本。