Objective-C编程 - 关于Block的要点
来源:互联网 发布:python 2.7不支持中文 编辑:程序博客网 时间:2024/05/17 22:13
1. 首先,我们快速过一下,什么是Block?
Block是一段代码,它在OC中以^开头,可以有返回值,和参数列表,但就是没有名字。
所以,你可以把它认为是匿名函数。
事实上,它和Swift中的闭包(Closure)是一样的。
或者,学过.NET的童鞋知道委托吧,它和委托也差不多概念。
都是可以在一个方法中传入它,作为参数的方法。
无参无返回值的Block:
[MyObject myMethodParam1: xx param2: ^{
...
}];
有参有返回值的Block:
[MyObject myMethodParam1: xx param2: ^BOOL(id param1, id param2) {
...
}];
好了,说了那么多,我们来看个例子:
myDict enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) { NSLog(@"Key - %@: Value - %@", key, value); if ([@"END" isEqualToString:key]) { *stop = YES; }}];
上面这段代码枚举一个字典的键值对,知道遇到END键值退出循环,否则枚举所有的键值对。
2. 在Block中我们可不可以使用Block范围以外声明的变量呢?
答案是可以的,但是它是只读的,你如果要修改这个变量,会编译错误。
我们还是来看上面那段代码的例子,在循环中,我们增加了一个外部变量,想要让Block提早结束
BOOL stopEarly = NO;double stopValue = 100.2;[myDict enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) { NSLog(@"Key - %@: Value - %@", key, value); if ([@"END" isEqualToString:key] || [value doubleValue] == stopValue) { *stop = YES; stopEarly = YES; // 这段代码编译会出错!! }}];
上面的代码stopValue变量的Block内读取没有任何问题,但是当我们企图在Block内修改stopEarly变量的值时,编译出错了!
那么如果,我们执意要修改Block外面的变量,是不是可以呢?
答案是可以的。
我们要使用__block关键字,原理上是通过使用该关键字,我们可以把block外的变量从栈中移到堆中,这样就可以在Block内部使用了。
当Block结束时,变量又回到栈中。
还是上面的代码,我们作下修改,如下:
__block BOOL stopEarly = NO;double stopValue = 100.2;[myDict enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) { NSLog(@"Key - %@: Value - %@", key, value); if ([@"END" isEqualToString:key] || [value doubleValue] == stopValue) { *stop = YES; stopEarly = YES; }}];if (stopEarly) NSLog(@"Block提前终止了!");
3. 当我们向Block内的对象发送消息时,系统会创建一个指向该对象的强指针
该强指针会一直保留到Block超出自己的范围,不存在。
4. Block数组
property (nonatomic, strong) NSMutableArray *blockArray;...- (void) someMethod { [self.blockArray addObject:^{ ... }];}// 获取数组中的block并调用void (^doit)(void) = self.blockArray[0];doit();
5. 常见的Block中导致循环引用(Memory Cycle)的场景
前面我们曾经提到:
当我们向Block内的对象发送消息时,系统会创建一个指向该对象的强指针
该强指针会一直保留到Block超出自己的范围。
换句话说,Block内的所有对象,都会在堆上保留自己的内存,也就是说,Block会保留
指向这些对象的强指针(strong pointer)。
我们来看下面的代码:
@property (nonatomic, strong) NSMutableArray *blockArray;...// in the blockArray a strong pointer has been kept to the self object// while self holds another strong pointer to blockArray- (void) someMethod { [self.blockArray addObject:^{ [self doSomething]; }];}
上面的代码的问题是:blockArray保留了一个指向类对象的强引用指针,而类对象,也就是self也保留了
一个指向blockArray的强引用指针。
大家都有强指针指向对方, 它们都无法从栈中释放,这就导致了内存的循环引用。
解决方案:
为了打破循环引用,我们要使用一个弱类型的局部变量。
什么意思?
由于局部变量都是强指针类型,都保留指向堆中的强指针,所以我们要想办法创建一个弱指针类型的局部变量来
打破循环引用。
可以使用关键字:
__weak
比如:
__weak MyClass *weakSelf = self;
这样即使self本身是强指针类型的,而我们创建的weakSelf却变成了弱指针类型。
于是,上面有问题的代码我们可以进行如下的修改:
@property (nonatomic, strong) NSMutableArray *blockArray;...- (void) someMethod { __weak MyClass *weakSelf = self; [self.blockArray addObject:^{ [weakSelf doSomething]; }];}
这样block这边保留的对于对象的指针就变成了弱类型的指针,循环引用被打破了!
这是一个常用的解决方案,必须要记住!!
- Objective-C编程 - 关于Block的要点
- Objective- C 编程 Block
- Objective-C的Block
- objective-c block的使用
- Objective-c的block(块)
- Objective-C Block的实现
- Objective-C Block的实现
- Objective-c的Block基础
- Objective-c - block的简写
- 【读书笔记】Objective-C高级编程--Block概要
- 【《Objective-C 高级编程》 学习笔记--Block】
- Objective-C和C++混编的要点
- Objective-C和C++混编的要点
- Objective-C的Block的实现原理
- Objective-C代码块(block)的练习
- 谈Objective-C Block的实现
- 谈Objective-C Block的实现
- 谈Objective-C Block的实现
- Android微信分享
- ListView的下拉刷新、滑动删除和上拉加载更多
- 132. Palindrome Partitioning II
- 计算器应用程序
- 第十二周oj项目D汉罗塔
- Objective-C编程 - 关于Block的要点
- Linux 内核资源限制 -- 栈限制
- 基于opencv的简单视频处理类示例
- adb
- openv直方图均衡化综合示例
- 有限元网格开源软件GMSH基础
- 第12周OJ实践 进制转换(十进制转二进制)
- 图的深度遍历
- 15款顶级开源人工智能工具推荐