1、关于block的循环引用:
block属性,一般用copy修饰;
1.1.如果没有对block进行copy操作,block就存储于栈空间
1.2.如果对block进行copy操作,block就存储于堆空间---强引用
1.3.如果block存储于栈空间,不会对block内部所用到的对象产生强引用
1.4.如果block存储于堆空间,就会对block内部所用到的对象产生强引用
注意1:由于使用了copy修饰,如果block中调用了block属性的对象,就会造成循环引用
为了避免循环引用,需要对对象进行若引用修饰:
1 ICKPerson *p = [[ICKPerson alloc] init]; 2 // 1、修饰方法1 3 // __unsafe_unretained typeof(p) weakP = p; 4 // 2、修饰方法2 5 __block typeof(p) weakP = p; 6 p.testBlock = ^{ 7 [weakP run]; 8 };
2、关于block中变量的值:
2.1 如果变量没有通过__block修饰,那么block中的变量本质是值捕获,在创建block的同时,是将变量的值传入到block中,无论什么时候调用,变量的值就是最初传进去的值
1 int age = 10; 2 void (^block)() = ^{ // 值捕获 3 NSLog(@"age=%d", age);// 打印是10; 4 }; 5 age = 20; 6 block();
2.2 如果变量通过__block修饰,那么block中的变量实际传递的是变量的地址,在创建block的同时,是将变量的地址传入到block中,在调用block的时候,其变量的值是当时变量的值(通过地址(指针)获取到)。
1 __block int age = 1; 2 void (^block)() = ^{ // 值捕获 3 NSLog(@"age=%d", age);// 打印是20; 4 }; 5 age = 20; 6 block();
3、关于block的内部实现:
创建block的时候,内部是创建了对应的函数;
在调用block的时候,是调用了之前封装的函数。
4、关于block的应用:
4.1.如何定义block
1 1、// inline 2 // blockName:block变量名 3 // 返回值类型(^变量名)(返回值类型) 4 <#returnType#>(^blockName)(<#parameterTypes#>) = ^(<#parameters#>) { 5 <#statements#> 6 }; 7 void(^block)() = ^(){ 8 NSLog(@"block"); 9 }; 10 2、// name:Block类型别名 11 typedef void(^MyBlock)() 12 MyBlock myBlock = ^(){ 13 };
4.2、调用block
1 block(); 2 myBlock();
4.3、实战练习:
// 4.通讯录Block使用:
// 点击保存,通知联系人刷新表格,用代理
// block:小弟 代理:打电话
// block:先把刷新表格的代码保存起来
// 等用户点击了保存按钮的时候,调用Block
4.3.1、在头文件中(向其他文件中传递数据的文件)定义一个block:是否带参数,根据需求确定
1 @class ICKAddViewController,ICKContact; 2 typedef void(^ICKAddViewControllerBlock)(ICKContact *contact); 3 @interface ICKAddViewController : UIViewController 4 @property (nonatomic, strong) ICKAddViewControllerBlock contactBlock; 5 @end
4.3.2、在获取数据后,跳转页面之前,调用block,将数据传递过去
1 - (IBAction)addcontact { 2 ICKContact *contact = [ICKContact contactWithName:self.nameFiled.text andPhone:self.phoneFiled.text]; 3 // 调用block 4 if (self.contactBlock) { 5 self.contactBlock(contact); 6 } 7 [self.navigationController popViewControllerAnimated:YES]; 8 }
4.3.3、在获取(保存、利用)数据的文件中(拿到获取数据的对象的时候)调用其block属性,保存block代码段(实现特定功能的代码)
1 // 跳转控制器时数据传递 2 - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{ 3 ICKAddViewController *addVc = segue.destinationViewController; 4 // 声明block 5 addVc.contactBlock = ^(ICKContact *contact){ 6 [self.contacts addObject:contact]; 7 8 // 存储数据 9 NSString *cache = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0]; 10 NSString *path = [cache stringByAppendingString:@"contacts.data"]; 11 [NSKeyedArchiver archiveRootObject:self.contacts toFile:path]; 12 [self.tableView reloadData]; 13 }; 14 }