iOS 编写高质量Objective-C代码(六)
栏目: Objective-C · 发布时间: 6年前
内容简介:级别: ★★☆☆☆标签:「iOS」「Block」「Objective-C」作者:MrLiuQ
级别: ★★☆☆☆
标签:「iOS」「Block」「Objective-C」
作者:MrLiuQ
审校:QiShare团队
前言: 这几篇文章是小编在钻研《Effective Objective-C 2.0》的知识产出,其中包含作者和小编的观点,以及小编整理的一些demo。希望能帮助大家以简洁的文字快速领悟原作者的精华。 在这里,QiShare团队向原作者Matt Galloway表达诚挚的敬意。
文章目录如下:
iOS 编写高质量Objective-C代码(六)本篇的主题是iOS中的 “Block的原理及应用” 。
先简单介绍一下今天的主角: block
。
- block(块):是一种 “ 词法闭包 ” ,通过block,开发者可将代码块像对象一样传递。
一、理解“block”的概念:
1. block的数据结构:
通过clang命令行工具(OC转C++),我们先来看一下 block
的内部数据结构大概是什么样子的?
struct Block_descriptor { unsigned long int reserved; unsigned long int size; void (*copy)(void *dst, void *src); void (*dispose)(void *); }; struct Block_layout { void *isa; int flags; int reserved; void (*invoke)(void *, ...); struct Block_descriptor *descriptor; /* Imported variables. */ }; 复制代码
解析:很显然,Block_layout是一个结构体:里面有一个isa指针,指向Class对象。还有一个函数指针,指向了块的实现代码。
2. block的三种类型:全局块、栈块、堆块。
根据block在内存中的位置,block被分成三种类型:
类型 | 内存位置 | 介绍 |
---|---|---|
__NSStackBlock__ | 栈区 | 栈内有效,出栈后销毁。 |
__NSMallocBlock__ | 堆区 | copy到堆空间上。可以在定义的那个范围之外使用。 |
__NSGlobalBlock__ | 全局区 | 不捕捉任何外部变量,全部信息在编译器就已确定。 |
- 1. NSStackBlock 栈块: 栈块保存于栈区,超出变量作用域,栈上的
block
以及声明的_block
都会被销毁。
例如:
__block NSString *name = @"QiShare"; void (^block)(void) = ^{ NSLog(@"%@ is an iOS team which loves to share technology.", name); }; NSLog(@"block = %@", block); 复制代码
小知识点:当block内部需要修改或访问外部变量时,外部变量需要额外用 __block
修饰。否则修改不了。
我们来看下打印:
什么?居然是 __NSMallocBlock__
(堆块)? 那是因为ARC环境下,编译器自动帮我们加了copy操作。
这时我们关掉ARC:设置 Objective-C Automatic Reference Counting = NO
。再来看下打印:
- 2. NSMallocBlock 堆块: 堆block内存位于堆区,在变量作用域结束时依然可以使用。
通过上面的例子: 在ARC下,block会默认加上copy操作:变成 __NSMallocBlock__
。
- 3. NSGlobalBlock 全局块: 块中无任何外界对象,所需的内存在编译时就可以确定,内存位于全局区。 类似于“单例”,copy是一个空操作。
例如:
void (^qiShare)(void) = ^{ NSLog(@"We love sharing."); }; NSLog(@"%@",qiShare); 复制代码
二、为常用的block类型创建typedef
为了增加代码的***可读性*** 和 可拓展性 , 需要为常用的block起个别名。
以 typedef
为块起别名,也可令块变量用起来更加简单~ 比如:
- (void)getDataWithToken:(NSString *)token success:(void (^)(id responseDic))success; //! 以上要改成下面这种 typedef void (^SuccessBlock)(id responseDic); - (void)getDataWithToken:(NSString *)token success:(SuccessBlock)success; 复制代码
三、用handler块降低代码分散程度
在我们iOS开发中,经常会异步执行一些任务,等待任务执行结束后再通知对象调用相关方法。 一般有两种做法:
- 第一种:使用NSNotificationCenter:
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
- 第二种:使用委托协议:详情见 iOS 编写高质量Objective-C代码(四) 。
- 第三种:使用block回调:直接把block对象当做参数传给相关方法执行。
举个例子:AFNetworking的API设计及使用就是block回调
- 接口设计:
- (NSURLSessionDataTask *)POST:(NSString *)URLString parameters:(id)parameters success:(void (^)(NSURLSessionDataTask *task, id responseObject))success failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure { return [self POST:URLString parameters:parameters progress:nil success:success failure:failure]; } 复制代码
- 使用:
AFHTTPSessionManager *manger =[AFHTTPSessionManager manager]; NSString *urlString = @""; NSMutableDictionary *parameter= @{@"":@"",@"":@""}; [manger POST:urlString parameters:parameter success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { NSLog(@"成功"); } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { NSLog(@"%@",error); }]; } 复制代码
四、用block引用其所属对象时避免出现循环引用
在我们日常开发中,如果block使用不当,很容易导致内存泄漏。
- 理由:如果
block
被当前ViewController(self
)持有,这时,如果block内部再持有ViewController(self
),就会造成循环引用。 - 解决方案:在
block
外部对 弱化self
,再在block内部 强化 已经弱化的weakSelf
For Example:
__weak typeof(self) weakSelf = self; [self.operationQueue addOperationWithBlock:^{ __strong typeof(weakSelf) strongSelf = weakSelf; if (completionHandler) { KTVHCLogDataStorage(@"serial reader async end, %@", request.URLString); completionHandler([strongSelf serialReaderWithRequest:request]); } }]; 复制代码
当然,也不是所有block中使用到 self
都要先弱化成 weakSelf
,再强化成 strongSelf
, 只要block没有被self所持有的,在block中就可以使用self。 比如下面:
[QiNetwork requestBlock:^(id responsObject) { NSLog(@"%@",self.name); }]; 复制代码
小贴士:内存泄漏检测相关知识请看: iOS 内存泄漏排查方法及原因分析
关注我们的途径有:
QiShare(微信公众号)
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 编写高质量Python程序(三)基础语法
- 如何编写高质量的函数 -- 命名/注释/鲁棒篇
- 编写高质量箭头函数的5个最佳做法
- iOS 编写高质量Objective-C代码(三)
- iOS 编写高质量Objective-C代码(二)
- iOS 编写高质量Objective-C代码(二)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Head First jQuery
Ryan Benedetti , Ronan Cranley / O'Reilly Media / 2011-9 / USD 39.99
Want to add more interactivity and polish to your websites? Discover how jQuery can help you build complex scripting functionality in just a few lines of code. With Head First jQuery, you'll quickly g......一起来看看 《Head First jQuery》 这本书的介绍吧!