iOS 使用Block

简介: 引言: Block是Apple在iOS4.0对Objective-C引入的新特性,通过Block可以增强代码的可读性和耦合性,减少非必要性的代理(Delegate)模式.

引言:

BlockAppleiOS4.0对Objective-C引入的新特性,通过Block可以增强代码的可读性和耦合性,减少非必要性的代理(Delegate)模式.

Block是一个代码块,非常类似JavaScript里面的匿名函数,也可以叫做闭包,所以你也可以用匿名函数的方式来理解Block.

本文Block的运行环境是在ARC模式下进行,非ARCBlock内存管理方面还是较为繁琐.所以,有了ARC,开发者不必过多的去关注Block在内存支配方面的问题.


参考资料: 

1:Block使用中的一些疑问解答

http://article.ityran.com/archives/1221

2:Block编程值得注意的那些事儿

http://www.cocoachina.com/macdev/cocoa/2013/0527/6285.html

3:iOS中block实现的探究

http://blog.csdn.net/jasonblog/article/details/7756763?reload


安装: 

让你的项目支持iOS4以上即可



使用:

Block的定义有两种方式如下:

第一种是匿名方式(做一次性使用,该Block不需要被重复使用时 使用):

第二种是通过typedef来定义一个新的Block(这样声明在头文件中,可以在其他类中重复使用,但必须在接口和实现外面声明引用):



以上两种定义Block的结构直接手动输入还是蛮难记的. 不过Xcode已经为我们添加了这两种定义的Code Snippet辅助编码

第一种的辅助输入:inlineBlock


第二种的辅助输入:typedefBlock


使用Block最大的一个好处就是可以在代码块中随时访问外部变量,比如你在A.class类中的某个方法中声明了一段代码块.

你可以在代码块中直接对A.class所拥有的成员变量进行调用,并且,通过一定的条件(__block),还可以随时的修改这些变量的值和指针.

下面看一段代码的实例:


1:通过图中可以看到,对没有通过__block修饰的局部变量进行赋值会修改指针地址,编译器会产生警告,提示这是无效的编码,正确的方式是为局部变量加上__block修饰.

2:在Block里面可以随时访问全局变量,静态变量等,并对它们的值和指针进行修改.

3:但在Block中直接使用所在声明区域的类的成员变量和self时也是可以直接使用和修改的,但需要注意循环引用.


在ARC环境下使用Block时的注意点:

开启ARC以后,Block的内存管理也交给了ARC,这让开发者不用再去关心何时需要引用,何时需要释放.如果要释放某个不再需要使用的Block成员变量,只需要将其设置nil即可. 

但在这强大的环境下,我们的编码也任然需要谨慎,否则很容易产生循环引用.

在编码过程中,编译器可能会产生像下面这样的警告:


Xcode会最大程度的提示你可能造成了循环引用. 产生这个警告的主要原因是我们在Block内使用了不是在Block里面声明的变量. 就像下面这样的代码:

@interface KSViewController () 
{ 
    id _observer; 
} 
 
@end 
 
@implementation KSViewController 
 
- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 
    // Do any additional setup after loading the view, typically from a nib. 
     
    KSTester * tester = [[KSTester alloc] init]; 
    [tester run]; 
     
    _observer = [[NSNotificationCenter defaultCenter] 
                 addObserverForName:@"TestNotificationKey" 
                 object:nil queue:nil usingBlock:^(NSNotification *n) { 
                     NSLog(@"%@", self); 
                 }]; 
} 
 
- (void)dealloc 
{ 
    if (_observer) { 
        [[NSNotificationCenter defaultCenter] removeObserver:_observer]; 
    } 
} 

在上面代码中,我们添加向通知中心注册了一个观察者,然后在 dealloc 时解除该注册,一切看起来正常。但这里有两个问题:
a) 在消息通知 block 中引用到了 self,在这里 self 对象被 block retain,而 _observer 又 retain 该 block的一份拷贝,通知中心又持有 _observer。因此只要 _observer 对象还没有被解除注册,block 就会一直被通知中心持有,从而 self 就不会被释放,其 dealloc 就不会被调用。而我们却又期望在 dealloc 中通过 removeObserver 来解除注册以消除通知中心对 _observer/block 的 retain。
b) 同时,_observer 是在 self 所在类中定义赋值,因此是被 self retain 的,这样就形成了循环引用
如何解决循环引用:

__weak KSViewController * wself = self; 
_observer = [[NSNotificationCenter defaultCenter] 
             addObserverForName:@"TestNotificationKey" 
             object:nil queue:nil usingBlock:^(NSNotification *n) { 
                 KSViewController * sself = wself; 
                 if (sself) { 
                     NSLog(@"%@", sself); 
                 } 
                 else { 
                     NSLog(@"<self> dealloc before we could run this code."); 
                 } 
             }]; 

下面来分析为什么该手法能够起作用。
 
首先,在 block 之前定义对 self 的一个弱引用 wself,因为是弱引用,所以当 self 被释放时 wself 会变为 nil;然后在 block 中引用该弱应用,考虑到多线程情况,通过使用强引用 sself 来引用该弱引用,这时如果 self 不为 nil 就会 retain self,以防止在后面的 使用过程中 self 被释放;然后在之后的 block 块中使用该强引用 sself,注意在使用前要对 sself 进行了 nil 检测,因为多线程环境下在用弱引用 wself 对强引用 sself 赋值时,弱引用 wself 可能已经为 nil 了。
通过这种手法,block 就不会持有 self 的引用,从而打破了循环引用。

总结:

Block在语法方面如果初次接触会令开发者有些畏惧感,不过不要怕,要耐下性子好好记住相关语法,因为这是iOS开发者高手进阶的必备技术之一.



目录
相关文章
|
iOS开发
iOS block修饰符用copy还是strong
iOS block修饰符用copy还是strong
170 0
|
iOS开发 Python
iOS小技能:lldb打印block参数签名
iOS逆向时经常会遇到参数为block类型,本文介绍一个lldb script,可快速打印出Objective-C方法中block参数的类型。
205 0
iOS小技能:lldb打印block参数签名
|
iOS开发 开发者
iOS开发 - 如何写出漂亮的block
iOS开发 - 如何写出漂亮的block
111 0
|
iOS开发
iOS开发- 关于Block的几种应用
iOS开发- 关于Block的几种应用
120 0
|
自然语言处理 iOS开发
IOS——Block
IOS——Block
87 0
|
iOS开发
iOS代理 通知 block传值的规范写法
iOS代理 通知 block传值的规范写法
148 0
|
存储 API iOS开发
iOS Principle:Block(下)
iOS Principle:Block(下)
141 0
iOS Principle:Block(下)
|
C语言 iOS开发 C++
iOS Principle:Block(上)
iOS Principle:Block(上)
122 0
iOS Principle:Block(上)
|
存储 中间件 Java
iOS-底层原理 30:Block底层原理
iOS-底层原理 30:Block底层原理
292 0
iOS-底层原理 30:Block底层原理
|
机器学习/深度学习 C++ iOS开发
iOS - __block 修饰符底层探索
Block技术合集 iOS - Block变量截获 Block的写法及使用
iOS - __block 修饰符底层探索