内容简介:首先我们来看一下有哪几种Block:那么这3种Block分别在哪里体现出来呢?接下来,我们通过代码来看一下:我们稍微修改下上面的代码,让block去截获变量的值,
首先我们来看一下有哪几种Block:
那么这3种Block分别在哪里体现出来呢?接下来,我们通过代码来看一下:
void(^block)(void) = ^{
NSLog(@"123456");
};
block();
NSLog(@"%@",block);
//万物皆对象,block也不例外
//运行代码,可以看到打印的内容是:
//BlockDemo[34002:5702720] 123456
//BlockDemo[34002:5702720] <__NSGlobalBlock__: 0x107c8b088>
//此时这个block就是GlobalBlock
复制代码
我们稍微修改下上面的代码,让block去截获变量的值,
int a = 10;
void(^block)(void) = ^{
NSLog(@"a=%d",a);
};
block();
NSLog(@"%@",block);
//运行代码,可以看到打印的内容是:
//BlockDemo[34061:5705903] a=10
//BlockDemo[34061:5705903] <__NSMallocBlock__: 0x6000021ccd50>
//此时的block就是MallocBlock
复制代码
我们再改变一下block的打印,
int a = 10;
void(^block)(void) = ^{
NSLog(@"a=%d",a);
};
block();
NSLog(@"%@",^{
NSLog(@"a=%d",a);
});
//运行代码,可以看到打印的内容是:
//BlockDemo[34108:5708687] a=10
//BlockDemo[34108:5708687] <__NSStackBlock__: 0x7ffee9f71970>
//此时打印出的就是我们看似不常用,不常见到,却可能在不知不觉中使用的StackBlock
复制代码
NSGlobalBlock :最初创建一个 block 的时候,他是存在于5大内存区(栈区,堆区,静态区,常量区,代码区(全局区))的全局区,当我们引入外部变量, block 会自动捕获变量,当前这个变量 a 由栈区捕获到堆区,因为 a 和 block 必须在同一个内存空间才可以进行相应的操作,所以 block 会由全局区迁移到堆区上去,所以 block 就存放到栈区 (NSStackBlock) ,但是由于栈区空间是由系统自动分配的,自动销毁的,所以我们再写 void(^block)(void) = 这句代码的时候实际上是做了一个 copy 操作,将存放在栈区上的 block 拷贝到了堆区 (NSMallocBlock) 。
Block的循环引用
首先我们来看下什么是正常的释放:
dealloc 给B发送
release 信息的时候,A不会再持有B,然后B的
retainCount 会减1,当B的
retainCount=0
的时候,B就会调用自己的析构函数,从而B就可以释放掉。
再来看一下什么是循环引用:
下面我们用代码来实现看一下:
@property (nonatomic, copy) ZHBlock block;
@property (nonatomic, copy) NSString *name;
self.name = @"ZH";
self.block = ^{
NSLog(@"%@",self.name);
};
self.block();
复制代码
在这里 self-->block-->self 造成循环引用,其实代码这样写,Xcode会在这里给我们一个警告,告诉我们会有循环引用, Capturing 'self' strongly in this block is likely to lead to a retain cycle 这里,大家都会利用 __weak typeof(self) weakSelf = self; 来解决循环引用,这样完成之后,大家肯定会觉得这样写不完善,应该还有一个 __strong ,那么为什么会要用这个 __strong 呢?对的就是防止“提前释放”,那么下面我们用代码来演示一下提前释放:
self.name = @"ZH";
__weak typeof(self) weakSelf = self;
self.block = ^{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"%@",weakSelf.name);
});
};
self.block();
复制代码
运行代码就会发现, weakSelf.name 打印出来的是 <null> ,因为当前控制器 pop 回去的时候就会调用析构函数 dealloc ,然后控制器就被释放掉了,这个name就没有任何意义,所以就会被置为空。
那么还有没有其他的方法来解决循环引用呢?
__block ViewController *vc = self;
self.block = ^{
NSLog(@"%@",vc.name);
vc = nil;
};
self.block();
复制代码
还有没有方法呢? 这个循环引用的实质就是在 block 里面用了 self ,那么不用 self 就可以了啊,但是在这里我们要打印 name 属性,这个 name 又是当前 vc 的属性,那么就是说我们要在 block 里面使用 vc ,那么如果把 vc 当做参数,传入 block 是不是可以呢,我们来试一下
typedef void(^ZHBlock)(ViewController *);
self.block = ^(ViewController *vc){
NSLog(@"%@", vc.name);
};
self.block(self);
复制代码
运行代码可以成功哦!
Block的一种应用(注:仅仅是个人做个记录而已)
首先写两个方法,如下:
-(ViewController *)where
{
NSLog(@"从东土大唐而来");
return self;
}
-(void)there
{
NSLog(@"去往西天拜佛求经");
}
复制代码
在调用这两个方法的时候,可以这样写: [[self where] there]; 如果换成点语法呢,可以这样写: self.where.there; 同样可以打印出两个语句,这种点语法的格式就有点类似于链式编程。
此时如果想往 -(void)there 方法传入一个参数该怎么做呢,可以看到这是一个 getter 方法,无法传入参数,可是又要做到通讯的目的:那么试着在 there 方法中返回一个 block ,
-(ViewController *)where
{
NSLog(@"从东土大唐而来");
return self;
}
-(void(^)(NSString *))there
{
NSLog(@"去往西天拜佛求经");
void (^block)(NSString *) =^(NSString *name)
{
NSLog(@"%@",name);
};
return block;
}
复制代码
此时再用点语法调用就可以传入参数: self.where.there(@"三藏语录"); 打印可以看到语句输出正确, ---这就是面向链式编程最基础的写法。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 考古 - HttpInterceptor 循环引用错误
- iOS: NSTimer的循环引用(解决)
- Objective-C中block的循环引用问题
- element上传组件循环引用及简单时间倒计时
- 内存二三事: Xcode 内存图、Instruments 可视化检测循环引用
- 强引用、软引用、弱引用、虚引用
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Head First Web Design
Ethan Watrall、Jeff Siarto / O’Reilly Media, Inc. / 2009-01-02 / USD 49.99
Want to know how to make your pages look beautiful, communicate your message effectively, guide visitors through your website with ease, and get everything approved by the accessibility and usability ......一起来看看 《Head First Web Design》 这本书的介绍吧!