先说点其他的,不知道是网站访问量过大,还是因为设置不合理或者受攻击了,从一月份开始主机就不断被关闭,上次升级了下服务器,终于平静了段时间,但是今天早上又出现了,然后就选择关闭了一点功能,比如rss全文订阅,这个估计用的人比较少,先关一段时间试试效果。
今天说下OC的block块的一点备忘,Block是iOS中一种比较特殊的数据类型,是苹果官方特别推荐使用的一种数据类型,应用场景有:动画、多线程、集合遍历、网络请求回调等
Block的作用:用来保存某一段代码,可以在恰当的时间取出来再调用。
基础的介绍使用就看参考链接里面的那两个文章就行了,这里说下几个注意地方,昨天看到的,感觉别人总结的很全面
一、基本的几个使用代码示例
1.1、基础使用
block的基础使用可以参考下面的代码,当然也可以有返回值,这里没有设置返回值
#import "ViewController.h"
typedef void(^testtt2)(int);
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
UIButton *button2 = [[UIButton alloc] initWithFrame:CGRectMake(10, 200, 100, 40)];
[button2 setTitle:@"声明块使用" forState:UIControlStateNormal];
[button2 setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
[button2 addTarget:self action:@selector(test2) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button2];
}
//声明块
-(void)test2{
NSLog(@"test2");
//声明一个块
void (^testt)(int) = ^(int count){
NSLog(@"%d",count);
};
//使用
testt(10);
//使用typedaf块
testtt2 te = ^(int count){
NSLog(@"%d",count);
};
te(20);
//更改局部变量
__block int m =0;
testtt2 te2 = ^(int count){
m=count;
NSLog(@"m1: %d",m);
};
te2(30);
NSLog(@"m2: %d",m);
//加不加括号
void (^test3)()=^{
NSLog(@"没有变量");
};
test3();
void (^test4)()=^(){
NSLog(@"没有变量2");
};
test4();
}
@end
1.2、回调使用
block块也可以作为回调函数,作用类似于delegate,但是更加简洁方便,这里写一个BlockTest的类,在这个类中有一个请求函数,当函数执行之后回调
1.2.1、BlockTest.h
#import <Foundation/Foundation.h>
typedef void(^testCall)(int m,NSString*str);
@interface BlockTest : NSObject
@property(copy,nonatomic)testCall tess;
//发起一个请求,请求结束回掉block块
-(void)touchWithCall:(testCall)tes;
@end
1.2.2、BlockTest.m
#import "BlockTest.h"
@implementation BlockTest
-(void)touchWithCall:(testCall)tes
{
self.tess = tes;
if (self.tess) {
self.tess(1,@"hudongdong");
}
}
@end
1.2.3、使用的时候,比如按钮点击时发送请求
- (void)viewDidLoad {
[super viewDidLoad];
UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(10, 100, 100, 40)];
[button setTitle:@"测试回调" forState:UIControlStateNormal];
[button setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
[button addTarget:self action:@selector(test) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
}
//块回调
-(void)test{
NSLog(@"test");
BlockTest *bb = [[BlockTest alloc] init];
[bb touchWithCall:^(int m, NSString *str) {
NSLog(@"回调了%d,%@",m,str);
}];
}
这里请求完毕之后就会得到回调结果1,"hudongdong"了。
二、Block块使用的六个注意事项
这个是网友总结的,原文链接在参考链接里面
对于刚学习OC新伙伴,block块一直都是一个比较纠结、比较难懂的知识点,不过,在使用一段时间后,就会感觉很酸爽。block块的原理及使用我就不再赘述,网上有很多这方面的资料。我个人使用这么长时间以来,觉得使用block块应该注意以下几点。
2.1、在使用block前需要对block指针做判空处理
例如:XXXX为定义的block块
if (XXXX ) {
if(XXXX != nil){
//XXXX(参数);或XXXX(参数);
}
}
在使用block块,最好对block进行判空处理,不进行判空处理直接使用的话,一旦指针为空就会直接产生崩溃。
2.2、block如果作为属性变量时,要copy一下,将栈上的block拷贝到堆上
例如,作为属性时,写成@property (nonatomac,copy)XXXXXX;(注:XXXXXX为block块)
如果不进行copy,若是栈上的block被释放,此block块属性变量就为空了,程序有可能就会直接产生崩溃。
2.3、在block使用之后要对block指针做赋空值处理,如果是MRC的编译环境下,要先release掉block对象。
block作为类对象的成员变量,使用block的人有可能用类对象参与block中的运算而产生循环引用。
将block赋值为空,是解掉循环引用的重要方法。(不能只在dealloc里面做赋空值操作,这样已经产生的循环引用不会被破坏掉)
例如:
if (_sucBlock ) {
_sucBlock(参数);
}
//MRC下:要先将[_sucBlock release];(之前copy过)
_sucBlock = nil; //在使用之后将Block赋空值,解引用 !!!
还有一种改法,在block接口设计时,将可能需要的变量作为形参传到block中,从设计上解决循环引用的问题。
2.4、使用时将self或成员变量加入block之前要先将self变为__weak弱引用
这与第三条其实是一个问题,就是解决循环引用问题。
2.5、在多线程环境下(block中的weakSelf有可能被析构的情况下),需要先将self转为strong指针,避免在运行到某个关键步骤时self对象被析构。
第四、第五条合起来有个名词叫weak–strong dance,以下代码来自AFNetworking,堪称使用weak–strong dance的经典。
__weak typeof(self) weakSelf = self;
AFNetworkReachabilityStatusBlock callback = ^(AFNetworkReachabilityStatus status) {
__strong typeof(weakSelf) strongSelf = weakSelf;
strongSelf.networkReachabilityStatus = status;
if (strongSelf.networkReachabilityStatusBlock) {
strongSelf.networkReachabilityStatusBlock(status);
}
};
第一行:__weak __typeof(self)weakSelf = self;
如之前第四条所说,为防止callback内部对self强引用,weak一下。
第三行:__strong typeof(weakSelf) strongSelf = weakSelf;
按照之前第五条的说法给转回strong了,这里typeof()里面写的是weakSelf,里面写self也没有问题,因为typeof是编译时确定变量类型,所以这里写self 不会被循环引用。
第四、五、六行,如果不转成strongSelf而使用weakSelf,后面几句话中,有可能在第四句执行之后self的对象可能被析构掉,然后后面的StausBlock没有执行,导致逻辑错误。
最后第五行,使用前对block判空。
其中用到了__typeof(self),这里涉及几个知识点:
2.5.1. __typeof、__typeof__、typeof的区别
没有区别,对于老的LLVM编译器上面这句话会编译报错,所以在很早的ARC使用者中流行__typeof(&*self)这种写法
2.6、block回调不起作用,可能是调用block属性变量的类的实例对象已不是原来的对象。
这个问题只能具体情况具体分析了,程序运行可能不会错,就是block回调不起作用,有些功能实现不了,断点调试发现根本不走回调。之前我有一个同事就遇到过这个问题,另外一个同事给他解决了一个小时也没解决,我让他检查一下调用block块的类对象,果然,与原来的地址不是一个,他又新建一个对象,前后就花了1分钟解决(得意一下)。
三、demo下载
Github下载:https://github.com/DamonHu/HudongBlogDemo/tree/master/blcokTest
Gitosc下载:http://git.oschina.net/DamonHoo/blcokTest
四、参考链接
- Objective-C语法之代码块(block)的使用
- iOS之Block代码块的定义及使用
- Block的基本使用、typedef给Block定义别名、Block的应用场景、Block的注意事项
- 关于block块使用的6点注意事项
- strong和copy的区别
版权属于:东哥笔记 - DongGe.me
本文链接:https://dongge.org/blog/400.html
自2017年12月26日起,『转载以及大段采集进行后续编辑』须注明本文标题和链接!否则禁止所有转载和采集行为!