美文网首页
iOS开发block

iOS开发block

作者: 常绿箩 | 来源:发表于2016-06-13 08:44 被阅读176次

一、基本概念:

Block是一种C语言的数据类型,指向结构体的指针,平常我们将Block当作一个代码段使用,相当于函数,Block相比于函数的优点是 Block可以当做一个参数传递而函数/方法不能.。我们可以用Block写一些函数语句,可以使用多线程。Block也可以作为一个回调,不仅包含回调期间的代码,也包含了执行期间需要的数据。类似于"闭包",闭包的定义是可以从函数外部访问函数内部的变量。

二、基本用法:

1)无参无返回值(最简单形式)

定义格式:void (^block名)() = ^{代码块;};

使用格式:block名();

2)无参有返回值(以返回值为int为例)

定义格式:int (^block名)() = ^{代码块;};

使用格式:int result = block名();

3)有参无返回值(以参数为int为例)

定义格式:void (^block名)(int) = ^(int a){代码块;};

使用格式:  block名(6);

4)有参有返回值(以参数、返回值为int为例;可以有多个参数)

定义格式:int (^block名)(int) = ^(int a){代码块;};

使用格式:int result = block名(6);

5)利用typedef定义block类型(和指向函数的指针很像)

定义格式:typedef 返回值类型(^新别名)(参数类型列表);

例:typedef int (^myBlock)(int,int);

三、Block访问外部变量

1)在block内部可以访问block外部的变量,但是,这是一个新的内存空间变量;

block内部也可以定义和block外部同名的变量,此时这个局部变量会屏蔽外部变量的作用域。

2)如果想要在block内部修改外部的局部变量,需要给该变量加上__block关键字;原因是加__block,block会引用常量变量的地址,则可以任意修改该变量指向的内容。如果不加__block直接在block内部修改变量,会编译报错,block内部变量是只读的。

四、Block使用技巧和注意事项

1)block的快速提示,输入inlineBlock 会有代码提示;

2)block变量用作方法的参数时,最好把参数类型列表部分加上具体的参数名

3)利用block遍历取值

例: [dict enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {

}];

5)  block修饰:block的发展也经过了MRC和ARC两个阶段;

MRC情况下:用copy修饰后,如果要在block内部使用对象,则需要进行__block typeof(Target) blockTarget = Target处理,在block里面用blockTarget 操作。

ARC情况下:如果用copy修饰,该block就会存储在堆空间以避免在使用时发生释放。但会对block的内部对象进行强引用,导致循环引用,内存无法释放。 所以block使用 self ,要使用 self 弱引用写法. 即__weak typeof(self) weakSelf = self;如果用weak修饰block,该block就会存放在栈空间,虽不会出现循环引用,但容易造成需要使用对象时,对象已经不存在的问题,原因是存储在栈空间的各种数据是系统自动处理的,并不需要程序猿手动处理,所以我们也不知道对象什么时候会被释放。

6)循环引用

分析循环(VC代表viewController控制器)

已知 : op --> self(VC) 强引用

如果 self 强引用的对象,对 op 也有强用.那么就会有循环引用

self(VC) --> queue/OPCache --> op --> self(VC)

所以block使用 self ,要使用 self 弱引用写法. 即__weak typeof(self) weakSelf = self;

GCD中的block(任务)出现self,会造成循环引用吗?  ----- GCD中的block可以直接使用 self

block循环引用的条件: block------->强应用(self)  self ------->强引用(block属性)

NSOperation 中的blcok中是否可以出现 self ?

一般情况下 NSOperationQueue 需要作为一个属性. 将操作添加到操作队列中!

注意: 1.确实会出现循环引用!

但是: 操作一旦执行完毕之后,就会被自动销毁! 所以 NSOperation 中可以出现 self.

7)block可以在两个对象之间进行传值,类似于代理和通知;

以POST请求为例,假如我在A对象中封装了POST请求的方法,该方法请求回来的数据想传递给B对象,就可以利用block实现:

代码示例:

"A对象中声明方法

//MARK:- 一句话封装POST请求

- (void)POSTRequestWithURLString:(NSString *)urlString andDict:(NSDictionary *)pramarts andSuccessBlock:(successBlock)successblock andFalseBlock:(falseBlock)falseblock ;

"实现方法

- (void)POSTRequestWithURLString:(NSString *)urlString andDict:(NSDictionary *)pramarts andSuccessBlock:(successBlock)successblock andFalseBlock:(falseBlock)falseblock {

//MARK:- 创建请求

NSURL *url = [NSURL URLWithString:urlString];

#warning - POST请求要创建可变请求

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:0 timeoutInterval:15];

//MARK:- 设置请求体、请求方法等参数

request.HTTPMethod = @"POST";

NSMutableString *strM = [NSMutableString string];

[pramarts enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {

NSString *pramKey = key;

NSString *pramValue = obj;

[strM appendFormat:@"%@=%@&",pramKey,pramValue];

}];

NSString *pramart = [strM substringToIndex:strM.length-1];

request.HTTPBody = [pramart dataUsingEncoding:NSUTF8StringEncoding];

//MARK:- 发送请求

[[[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {

if (data&&!error) {

if (successblock!=nil) {//一定要先判断block是否为空

successblock( obj,response);//回调

}

}else{

if (falseblock!=nil) {//同上

falseblock(error);

}

}

}]resume];

}

"B对象调用方法

[[YQPOSTRequest sharedPOSTRequest] POSTRequestWithURLString:urlStr andDict:pram andSuccessBlock:^(NSData *data, NSURLResponse *response) {

NSLog(@"%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]);

} andFalseBlock:^(NSError *error) {

NSLog(@"%@",error);

}];

五、解决OC中block循环引用的三种方式

1)解决循环引用的第一种方式

//iOS 5.0 引用来解决循环引用的方式  和weak属性关键字作用类似

//当对象被系统回收时  对象的地址 会自动指向 nil  不会出现野指针访问

__weak typeof(self) weakSelf = self;

2)解决循环引用的第二种方式

//    __weak typeof(self) weakSelf = self;

//会引起 EXC_BAD_ACCESS 错误 是MRC 时代最常见的错误  野指针  --> 坏地址访问

// 和 assgin属性关键字的作用类似  对象被系统回收时 对象的地址不会自动指向nil

// iOS4.0 和block 一起推出的 用来解决循环引用的

__unsafe_unretained typeof(self) weakSelf = self;

3) 解决循环引用的第三种方式

//weak-strong-dance wwdc 推出的解决方式  在AFN中被大量的运用到

__weak typeof(self) weakSelf = self;

[self.tools loadData:^(NSString *result) {

//闭包中对弱引用的weakSelf 在强引用一下

__strong typeof(weakSelf) strongSelf = weakSelf;

NSLog(@"%@ %@",result,strongSelf);

}];

相关文章

网友评论

      本文标题: iOS开发block

      本文链接:https://www.haomeiwen.com/subject/udyedttx.html