block底层实现原理

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 = 12  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 }

 

原文地址:https://www.cnblogs.com/jfckliving/p/4775024.html