蓝鸥iOS培训Block技术中的weak-strong
本文章由蓝鸥iOS培训肖浩老师整理提供,蓝鸥iOS培训将陆续发布技术文章,如有需要可以添加关注,希望对您的学习有所帮助。
本篇文章的主要内容 ·了解何谓block。 ·了解block的使用方法。
Block 是iOS在4.0版本之后新增的程序语法.
在iOS SDK 4.0之后,Block几乎出现在所有新版的API之中,换句话说,如果不了解Block这个概念就无法使用SDK 4.0版本以后的新功能,因此虽然Block本身的语法有点难度,但为了使用iOS的新功能我们还是得硬着头皮去了解这个新的程序概念。 一、看一看什么是Block
我们使用^运算符来声明一个Block变量,而且在声明完一个Block变量后要像声明普通变量一样,最后要加;。 声明Block变量
接下来,我们通过一个例子来声明一个简单的Block变量. int (^block)( int ) = NULL;
我们一起来看一下声明Block变量的语法 数据返回值类型 (^变量名) (参数列表) = NULL; 赋值Block变量 block = ^(int m){ return m * m; };
使用Block变量
//通过使用block变量,计算整型常量10的平方,并且打印在控制器输出 NSLog(@\"10的平方是:%d\
注意,到目前我们应该有发现block变量的使用步骤,有类似于函数的步骤
蓝鸥科技有限公司 版权所有
http://www.lanou3g.com
·首先都要声明(声明函数,声明block变量);
·然后都要进行实现(实现函数,为block变量赋值实现过程); ·最后都要进行调用才能实现具体功能 二、看一看如何直接使用block参数 ·数组排序 //声明数组变量 NSMutableArray
*mutableArray
=
[[NSMutableArray
alloc]
initWithObjects:@\"5\ //直接使用block进行数组升序排序
[mutableArray sortUsingComparator:^NSComparisonResult(id obj1, id obj2) { //将两个参数转换为字符串的对象 NSString *value1 = (NSString *)obj1; NSString *value2 = (NSString *)obj2;
//value1与value2两个对象的比较结果直接返回 return [value1 compare:value2]; }];
//打印可变数组变量
NSLog(@\"%@\·简单的网络异步请求 //声明网络地址对象
NSURL *url = [NSURL URLWithString:@\"http://www.qq.com\"];
//根据网络地址对象,声明网络请求对象
NSURLRequest *request = [NSURLRequest requestWithURL:url];
//直接使用block变量完成链接成功后的数据返回功能
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue]
蓝鸥科技有限公司 版权所有
http://www.lanou3g.com
completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) { //将二进制数据使用utf8编码转换成字符串对象 NSString
*result
=
[[NSString
alloc]
initWithData:data
encoding:NSUTF8StringEncoding];
//打印链接完成后的结果 NSLog(@\"%@\ }];
可以看出ios平台中的很多功能都已经集成了Block语法的处理方法. 三、看一看深入理解Block语法
在本节,主要要去介绍的就是使用__block修饰的变量能够完成的作用。 先来看一个例子。
//声明一个局部整型变量 int intValue = 3;
//声明一个返回值为int,一个int参数的block变量 int (^block)(int) = ^(int m){ return m * intValue; };
//调用block变量,5作为参数之后的结果 NSLog(@\"block(5) = %d\
在上面的例子中,我们将intValue变量称为block执行过程中的外部变量,在block执行过程中可以直接使用该外部变量。 再看一个例子。
//声明一个局部整型变量 int intValue = 3;
蓝鸥科技有限公司 版权所有
http://www.lanou3g.com
//声明一个返回值为int,一个int参数的block变量 int (^block)(int) = ^(int m){ intValue++; return m * intValue; };
//调用block变量,5作为参数之后的结果 NSLog(@\"block(5) = %d\
在上面的例子中,我们编译程序后发现编译器会有红色错误,错误提示为 Variable is not assignable (missing __block type specifier) 为什么会出现不能被赋值的错误提示呢?
·block在实现时就会对它引用到的它所在方法中定义的栈变量进行一次只读拷贝 在 block 块内使用该只读拷贝。
那为了避免上述错误,就要使用__block修饰符来修饰外部变量,用来通知编译器该外部变量intValue与block中的intValue指的是同一块儿内存地址,而不需要内存拷贝。
如下例:
//将intValue局部整型变量使用__block修饰符进行修饰 __block int intValue = 3;
//声明一个返回值为int,一个int参数的block变量 int (^block)(int) = ^(int m){ intValue++; return m * intValue; };
//调用block变量,5作为参数之后的结果 NSLog(@\"block(5) = %d\四、使用Block要注意的内存问题
蓝鸥科技有限公司 版权所有
http://www.lanou3g.com
使用weak–strong dance技术来避免循环引用 举例如下 //
// ViewController.m //
// Created by lewis. //
#import \"ViewController.h\"
@interface ViewController () @end
@implementation ViewController {
id observer; }
- (void)viewDidLoad {
[super viewDidLoad];
//添加观察者,观察主题修改消息通知,并且在收到消息通知后,打印视图控制器对象 observer
=
[[NSNotificationCenter
object:nil
defaultCenter]
queue:[NSOperationQueue
addObserverForName:@\"kThemeChangeNotification\" mainQueue] usingBlock:^(NSNotification *note) { NSLog(@\"%@\
蓝鸥科技有限公司 版权所有
http://www.lanou3g.com
}]; }
//当视图控制器对象销毁时,移除观察者 - (void)dealloc {
if (observer) {
[[NSNotificationCenter defaultCenter] removeObserver:observer]; } } @end
在上面代码中,我们添加向通知中心注册了一个观察者,然后在 dealloc 时解除该注册,一切看起来正常。但这里有两个问题:
在消息通知 block 中引用到了 self,在这里 self 对象被 block 保留一次,而 observer 又 retain 该 block的一份拷贝,通知中心又持有 observer。因此只要 observer对象还没有被解除注册,block 就会一直被通知中心持有,从而 self 就不会被释放,其 dealloc 就不会被调用。而我们却又期望在 dealloc 中通过 removeObserver 来解除注册以消除通知中心对 observer/block 的 保留次数。
同时,observer 是在 self 所在类中定义赋值,因此是被 self retain 的,这样就形成了循环引用。 解决方式如下. //
// ViewController.m //
// Created by lewis. //
#import \"ViewController.h\"
蓝鸥科技有限公司 版权所有
http://www.lanou3g.com
@interface ViewController () @end
@implementation ViewController {
id observer; }
- (void)viewDidLoad {
[super viewDidLoad];
//先声明一个weak弱对象
__weak ViewController *wSelf = self;
//添加观察者,观察主题修改消息通知,并且在收到消息通知后,打印视图控制器对象 observer
=
[[NSNotificationCenter
object:nil
defaultCenter]
queue:[NSOperationQueue
addObserverForName:@\"kThemeChangeNotification\" mainQueue] usingBlock:^(NSNotification *note){
//在block的执行过程中,使用强对象对弱对象进行引用 ViewController *bSelf = wSelf; if (bSelf) {
NSLog(@\"%@\ } }]; }
蓝鸥科技有限公司 版权所有
http://www.lanou3g.com
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated. }
//当视图控制器对象销毁时,移除观察者 - (void)dealloc {
if (observer) {
[[NSNotificationCenter defaultCenter] removeObserver:observer]; } } @end
在 block 之前定义对 self 的一个弱引用 wSelf,因为是弱引用,所以当 self 被释放时 wSelf 会变为nil;
在 block 中引用该弱应用,考虑到多线程情况,通过使用强引用 bSelf 来引用该弱引用,这时如果 self 不为 nil 就会 retain self,以防止在后面的使用过程中 self 被释放; 在之后的 block 块中使用该强引用 bself,注意在使用前要对 bSelf 进行了 nil 检测,因为多线程环境下在用弱引用 wSelf 对强引用 bSelf 赋值时,弱引用 wSelf 可能已经为 nil 了。
通过这种weak-strong手法,block 就不会持有 self 的引用,从而打破了循环引用。
声明:文章由蓝鸥科技的肖浩老师整理提供,仅供学习使用,禁止进行商业用途。如需转载,请注明转自蓝鸥科技。
蓝鸥科技有限公司 版权所有
因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- igbc.cn 版权所有 湘ICP备2023023988号-5
违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务