zoukankan      html  css  js  c++  java
  • block 使用中常见的问题

    一、block的定义及优点
    Apple文档说:
    A block is an anonymous inline collection of code, and sometimes also called a "closure".
    Block是一个C级别的语法以及运行时的一个特性,和标准C中的函数(函数指针)类似,但是其运行需要编译器和运行时支持。从ios4.0,Mac_OSX v10.6开始就很好的支持Block。
    在其他语言和环境中,更流行的把一个block对象称为闭包(在javascript,java,scale,groovy等语言中都有)。
    项目中感觉使用Block最大的便利就是简化的回调过程。以前使用UIView的动画,进程要控制动画结束后进行相应的处理。iOS 4.0之后,UIView新增了对Block的支持,现在只要使用简单的一个Block代码就可以在写动画的代码部分直接添加动画结束后的操作。
    二、block的声明和定义

     
    ex:
    c函数指针和blocks调用
    1.      int (*CFunc) (int a) //c函数指针
    2.      int result = CFunc(10); 
    3.      int (^BFunc)  (int  a) //blocks定义 
    4.      int result = BFunc(10);
    复制代码

    注意 :在声明时一个没有使用任何参数的block必须在参数列表上面用void标明。 但定义时可以省略:

    1. int (^myBlock)(void) = ^{  
    2.     return 20130212;  
    3. };
    复制代码
    三、使用block
    1、定义并调用block
    如果你声明了一个block作为变量,你可以把它作为一个函数来使用
    1. int (^oneFrom)(int) = ^(int anInt) { return anInt - 1; };
    2. NSLog("1 from 10 is %d", oneFrom(10)); // Prints "1 from 10 is 9"
    复制代码
    2、block用作方法、函数(多线程,动画)的参数
    Cocoa提供了一系列使用block的方法。你可以把一个block作为方法的参数就像其他参数那样。下面是zon的一个例子
    1.   items =  [items sortedArrayUsingComparator:^(id item1, id item2) {
    2.                 EPGItem *epg1 = item1;
    3.                 EPGItem *epg2 = item2;
    4.                 
    5.                 // NSComparisonResult is a typedef for int
    6.                 NSComparisonResult result = [[NSNumber numberWithFloat:[[epg2 score] floatValue]] compare:[NSNumber numberWithFloat:[[epg1 score] floatValue]]];
    7.                 if (result) {
    8.                     return result;
    9.                 }
    10.                 return (NSComparisonResult)NSOrderedSame; // NSOrderedSame == 0
    11.             }];
    复制代码
    (NSArray *)sortedArrayUsingComparator:(NSComparator)cmptr NS_AVAILABLE(10_6, 4_0);
    typedef NSComparisonResult (^NSComparator)(id obj1, id obj2);
    3、block代替delegate
    简化的回调过程
    1. typedef void (^SRRefreshBlock)(NLPullRefreshView* sender);
    2. @interface NLPullRefreshView : UIView {
    3. @property (nonatomic, copy)  SRRefreshBlock    block;
    4. @property(nonatomic,weak) NSObject <NLPullRefreshViewDelegate>  *delegate;
    5. @end
    6. @protocol NLPullRefreshViewDelegate
    7. - (void)nlRefreshTableHeaderDidTriggerRefresh:(NLPullRefreshView*)view;
    8. @end
    9. @implementation NLPullRefreshView{
    10. - (void)pullApart:(NLPullRefreshView*)refreshView
    11. {
    12.     if ([_delegate respondsToSelector:@selector(nlRefreshTableHeaderDidTriggerRefresh:)]) {
    13.         [(id)_delegate performSelector:@selector(nlRefreshTableHeaderDidTriggerRefresh:)
    14.                             withObject:self
    15.                             afterDelay:0.0];
    16.     }
    17.     if (_block) {
    18.         _block(self);
    19.     }
    20. }
    21. }
    复制代码
    四、block注意点
    1、block文本(即, ^{ ... }) 是表示block的局部栈数据结构(stack-local data structure)的地址.
    所以这些栈数据仅在当前声明的范围内有效,必须避免如下的使用:
    1. void dontDoThis() {
    2. void (^blockArray[3])(void); // an array of 3 block references
    3. for (int i = 0; i < 3; ++i) {
    4. blockArray[i] = ^{ printf("hello, %d ", i); };
    5. // WRONG: The block literal scope is the "for" loop
    6. }
    7. }
    8. void dontDoThisEither() {
    9. void (^block)(void);
    10. int i = random():
    11. if (i > 1000) {
    12. block = ^{ printf("got i at: %d ", i); };
    13. // WRONG: The block literal scope is the "then" clause
    14. }
    15. // ...
    16. }
    复制代码
    2、
      一个Block的内部时可以引用自身作用域外的变量的,包括static变量(RW),extern变量(RW)或自由变量(R),对于自由变量,在Block中只读的。在引入block的同时,还引入了一种特殊的__block关键字变量存储修饰符,指自由变量拥有读写权限:
    1. __block int x = 123;
    2. // x lives in block storage
    3. void (^printXAndY)(int) = ^(int y) {
    4. x = x + y;
    5. NSLog("%d %d ", x, y);
    6. };
    复制代码
    但是使用__block的变量有两个限制:它们不能是可变长的数组,并且它们不能是包含有C_9_9_可变长度的数组变量的数据结构。  3、block与内存管理 无ARC:block调用的时机可能是随意的,既然block可以引用外部环境,为了保证block被调用的时候当时的环境变量不被释放,被block引用的变量都会被自动隐式retain一次,这样至少可以保证我们的调用是有效的,但他也隐藏了一个问题:retain cycle!(防止retain cycle方法1:尽量保持子对象引用父对象的时候使用弱引用方法2:及时地将造成retain cycle中的一个变量设置为nil,将环break掉)
    1. DoSomethingManager *manager = [[DoSomethingManager alloc] init];
    2. manager.complete = ^{
    3. //...complete actions
    4. [manager otherAction];
    5. manager.complete = nil;
    6. [manager release];
    7. };
    复制代码
    manager的complete被设置为nil,如此一来retain cycle也被破坏掉,前提是你确实不需要再次回调block了。 使用ARC: ARC中,变量可以用三个关键字修饰:__strong: 赋值给这个变量的对象会自动被retain一次,如果在block中引用它,block也会retain它一次。__unsafe_unretained: 赋值给这个变量不会被retain,也就是说被他修饰的变量的存在不能保证持有对象的可靠性,它可能已经被释放了,而且留下了一个不安全的指针。不会被block retain。 __week:类似于__unsafe_unretained,只是如果所持有的对象被释放后,变量会自动被设置为nil,这样更安全些,不过只在IOS5.0以上的系统支持,同样不会被block retain。另外我们也可以用 __block 关键字修饰一个变量,表示这个变量能在block中被修改(值修改,而不是修改对象中的某一个属性,可以理解为修改指针的指向)。会被自动retain。于其他变量不同的是被 __block 修饰的变量在块中保存的是变量的地址。(其他为变量的值)
    1. DoSomethingManager *manager = [[DoSomethingManager alloc] init];
    2. manager.complete = ^{
    3. //...complete actions
    4. [manager otherAction];
    5. manager.complete = nil;
    6. };
    复制代码
    没什么问题,只是去掉了ARC中禁止的release。
    当然,我们也可以这么写:
    1. __block DoSomethingManager *manager = [[DoSomethingManager alloc] init];
    2. manager.complete = ^{
    3. //...complete actions [
    4. manager otherAction];
    5. manager = nil;
    6. };
    复制代码
    如果不用ARC,manager不会在block中被retain,但是采用了ARC就有些复杂了。block会retain manager变量,但是,由于__block变量保存更为底层的变量地址, 因此当此变量被指向其他对象时,block便不对原来的对象负责,引发的结果就是之前对象被release掉,retain cycle被破坏。但是,有一个问题就是,object的释放动作是在Block内部执行,如果Block没有被执行的话,循环参照一直存在。 另一种方案算是目前比较好的解决方案,就是让Block的参照变为弱参照 __weak
    1. MyObject *object = [[MyObject alloc] init];
    2. object.str = @"hoge";
    3. __weak MyObject *weakObject = object;
    4. object.block = ^{  
    5.   MyObject strongObject = weakObject; 
    6.    if (strongObject) {       
    7. NSLog(@"block: str=%@", strongObject.str);  
    8.   }
    9. };
    复制代码
    考虑到异步通信时Blocks的使用情况,weak变量weakObject有可能随时变为nil,所以类似于下面先变为strong变量,并检查是否为nil的处理方式应该更安全。
     
     
     
    转载 -- http://www.apkbus.com/android-128123-1-1.html
  • 相关阅读:
    深度学习框架caffe在macOS Heigh Sierra上安装过程实录
    关于MacOS升级10.13系统eclipse菜单灰色无法使用解决方案
    Struts2中的OGNL详解
    JAR包介绍大全用途作用详解JAVA
    使用SQLQuery 在Hibernate中使用sql语句
    Spring整合Struts的两种方式介绍
    springMVC使用@ResponseBody返回json
    springMVC controller配置方式总结
    安装GitLab出现ruby_block[supervise_redis_sleep] action run
    Mac系统下源码编译安装MySQL 5.7.17
  • 原文地址:https://www.cnblogs.com/tianlin106/p/3614973.html
Copyright © 2011-2022 走看看