block浅析

Block 的本质是可以截取自动变量的匿名函数。

一.block的三种定义方式

1.返回值类型(^block的名字)(参数类型) = ^(参数类型和参数名) {};

void(^block)() = ^(){

NSLog(@"调用了block");

};

2.//返回值类型(^block的名字)(参数类型) = ^(参数类型和参数名) {};

//如果有参数,定义的时候,必须要写参数,而且必须要有参数变量名

int(^block)(int) = ^(int a){

return 1;

};

3.系统提供了一个定义block的宏

returnType(^blockName)(parameterTypes) = ^(parameters) {

//        statements

//    };

二.block类型

@property (nonatomic, strong) void(^block)();//这样在类中可以拿到self.block

//当然也可以取别名:

typedef void(^BlockType)();//BlockType不是变量名,而是这种类型的block的别名

//然后就可以这样

@property (nonatomic, strong) BlockType block;

三.block变量的传递

(1)如果是局部变量,Block是值传递

(2)如果是静态变量,全局变量,__block修饰的变量,block都是指针传递


@property (nonatomic, strong) CompletionBlock zfbBlock;

//block只能使用strong,不要使用copy

//因为当使用copy的时候,set方法是调用了copy帮你深拷贝一次,没有这个必要.

//就像NSString一样,他一般都是@"a"这种常量,没必要再去深拷贝一次,所以NSString常量也用strong不用copy.

__weak typeof (&*self) weakSelf= self;

/*

因为block会给内部的强指针对象进行一次强引用,比如常见的传入block中的self进行强引用

并且在self中,block又是strong的,self对block是强引用

所以,你强引用我,我强引用你,谁也不会被释放,就造成了循环引用

所以,为了避免循环引用,我们要在block使用self之前,进行这一步操作:

在block中使用weakSelf,就不会产生循环引用问题了.

使用了__weak修饰符的对象,作用等同于定义为weak的property。自然不会导致循环引用问题.

*/


Block 回调实现

首先解释一下我们例子要实现什么功能(其实是烂大街又最形象的例子):

有两个视图控制器 A 和 B,现在点击 A 上的按钮跳转到视图 B ,并在 B 中的textfield 输入字符串,点击 B 中的跳转按钮跳转回 A ,并将之前输入的字符串

显示在 A 中的 label 上。也就是说 A 视图中需要回调 B 视图中的数据。

我们可以简单地这样思考,需要回调数据的是 A 视图,那么 Block 就应该在 B 中定义,用于获取传入回调数据。

因此我们在 BViewController.h 中定义如下:

//BViewController.h#import

typedefvoid(^CallBackBlcok(NSString*text);

//1@interfaceBViewController:UIViewController

@property(nonatomic,copy)CallBackBlcok callBackBlock;//2

@end

在这里,代码 1 用 typedef 定义了void(^) (NSString *text)的别名为CallBackBlcok。这样我们就可以在代码 2 中,使用这个别名定义一个 Block 类型的变量callBackBlock。

在定义了callBackBlock之后,我们可以在 B 中的点击事件中添加callBackBlock的传参操作:

//BViewController.m

- (IBAction)click:(id)sender {

self.callBackBlock(_textField.text);//1[

self.navigationControllerpopToRootViewControllerAnimated:YES];}

这样我们就可以在想要获取数据回调的地方,也就 A 的视图中调用 block:

// AViewController.m

- (IBAction)push:(id)sender { 

  BViewController *bVC = [self.storyboardinstantiateViewControllerWithIdentifier:@"BViewController"];    bVC.callBackBlock= ^(NSString*text){

// 1NSLog(@"text is %@",text);

self.label.text= text;   

};   

[self.navigationControllerpushViewController:bVC animated:YES];}

代码 1 中,通过对回调将 B 中的数据传递到代码块中,并赋值给 A

中的 label,实现了整个回调过程。

上例是通过将 block 直接赋值给 block 属性,也可以通过方法参数的方式传递 block 块。


关于 Block 的疑惑

到目前为止,一切看起来都很美好(如果你照着上面的例子做的话),功能正常, A 视图中也获取到数据了。但是某些人可能就要说了,你的代码有问题,你的思路有问题,你这是误人子弟。

是的,代码的确还有问题,第一个问题就是循环引用的问题,在 A 视图的block 代码块中:

bVC.callBackBlock= ^(NSString*text){NSLog(@"text is %@",text);self.label.text= text;          };

代码self.label.text = text;,在 Block 中引用 self ,也就是 A ,而 A 创建并引用了 B ,而 B 引用callBackBlock,此时就形成了一个循环引用,而编译器也不会报任何错误,我们需要非常小心这个问题(面试百分百问到我会乱说?)。此时我们通常的解决方法是使用弱引用来解除这个循环:

__weakAViewController*weakSelf =self;    bVC.callBackBlock= ^(NSString*text){NSLog(@"text is %@",text);//        self.label.text = text;weakSelf.label.text= text;    };

第二个问题是我自己对 Block 的理解不到位,我们都知道 Block 能截取自动变量,并且是不能在 Block 块中进行修改的(除非用__block修饰符),但是很明显weakSelf.label.text的值被修改了,并且没有用__block修饰符, 这是为什么呢?因为label是个全局变量,而如果像如下的局部变量a是不能修改的,编译器也会报错:

局部变量

通过这个小例子发现的两个问题,也算是值得了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Block 的使用有两种:1.独立Block 。2.内联Block 。 《一》独立Block 使用方式 一、定义一...
    乡村小子阅读 2,540评论 0 0
  • 对block的了解不是特别多,平常用代理用的比较多; Block写法:^(传入参数列){行为主体};Block实体...
    阿基米敬阅读 2,895评论 3 3
  • block是语言的的扩展功能,它是一种带有自动变量(局部变量)的匿名函数. /******************...
    long2016阅读 1,696评论 0 1
  • 刚刚落下帷幕的第89届奥斯卡以两段获奖感言的乌龙事件喜泪收官,几家欢喜几家愁,恶搞和唏嘘声在网络上的声势绝对不亚于...
    一碗甜椒阅读 4,965评论 0 0
  • 学习,模仿,如初来乍到 我欣赏你克服了心魔那一刻,但我忘记了奖赏你,对不起我忽视你了,我只会命令你去追赶别人的脚步...
    在努力生活的小姑娘阅读 1,053评论 0 1