ios里面的blocks学习

转载请注明,谢谢。

 

Ios4已经直接支持blocks,很有必要学习一下。

在ios,blocks是对象,它封装了一段代码,这段代码可以在任何时候执行。Blocks可以作为函数参数或者函数的返回值,而其本身又可以带输入参数或返回值。它和传统的函数指针很类似,但是有区别:blocks是inline的,并且它对局部变量是只读的。

Blocks的定义:

         int (^Multiply)(int, int) = ^(int num1, int num2) {return num1 * num2;};

定义了一个Multiply的blocks对象,它带有两个int参数,返回int。等式右边就是blocks的具体实现,注意{}blocks体里的;。

Blocks可以访问局部变量,但是不能修改。

              int multiplier = 7;

     int (^myBlock)(int) = ^(int num) {

         multiplier ++;//编译报错

         return num * multiplier;

     };

如果要修改就要加关键字:__block

         __blockint multiplier = 7;

     int (^myBlock)(int) = ^(int num) {

         multiplier ++;//这样就可以了

         return num * multiplier;

     };

 

作为函数的参数,blocks某种意义上替代了回调函数或者delegate。当函数调用了,假设某个事件触发,这时blocks里的内容就会运行。这样有利于代码的整合和阅读,你不需要到处去实现委托方法了。

系统API中已经有很多支持blocks参数了

·       Completionhandlers

·       Notificationhandlers

·       Errorhandlers

·       Enumeration

·       Viewanimation and transitions

·      Sorting

例如:

[UIViewanimateWithDuration:(NSTimeInterval)durationanimations:(void(^)())animations]

集合体中也可以运用blocks。枚举一个数组时我们通常:

         for (id obj in Array);

现在,

NSString *area = @"Europe";

    NSArray *timeZoneNames = [NSTimeZoneknownTimeZoneNames];

    NSMutableArray *areaArray =[NSMutableArrayarrayWithCapacity:1];

    NSIndexSet *areaIndexes =[timeZoneNames indexesOfObjectsWithOptions:NSEnumerationConcurrent

                                                             passingTest:^(id obj, NSUInteger idx, BOOL *stop) {

                                                                 NSString  *tmpStr = (NSString *)obj;

                                                                 return [tmpStr hasPrefix:area];

                                                             }];

   

    NSArray *tmpArray = [timeZoneNames objectsAtIndexes:areaIndexes];

    [tmpArray enumerateObjectsWithOptions:NSEnumerationConcurrent|NSEnumerationReverse

                               usingBlock:^(id obj, NSUInteger idx, BOOL *stop) {

                                   [areaArray addObject:[obj substringFromIndex:[arealength]+1]];

                               }];

    NSLog(@"Cities in %@ timezone:%@", area, areaArray);

blocks中obj就是数组中的每个成员,我们就可以在blocks内对每个对象进行处理。再比如:

NSMutableArray *mArray = [NSMutableArrayarrayWithObjects:@"a",@"b",@"abc",nil];

    NSMutableArray *mArrayCount= [NSMutableArrayarrayWithCapacity:1];

    [mArray enumerateObjectsWithOptions:NSEnumerationConcurrentusingBlock: ^(id obj,NSUInteger idx, BOOL *stop){

        [mArrayCount addObject:[NSNumbernumberWithInt:[obj length]]];

    }];

   

    NSLog(@"%@",mArrayCount);

你会发现,这样写代码更容易读懂。

最后,看一个排序的例子:

    NSArray *stringsArray = [NSArrayarrayWithObjects:

                             @"string1",

                             @"String21",

                             @"string12",

                             @"String11",

                             @"String02", nil];

    staticNSStringCompareOptionscomparisonOptions = NSCaseInsensitiveSearch | NSNumericSearch |

    NSWidthInsensitiveSearch| NSForcedOrderingSearch;

    NSLocale *currentLocale = [NSLocalecurrentLocale];

    NSComparator finderSort =^(idstring1, id string2) {

        NSRange string1Range = NSMakeRange(0, [string1 length]);

        return [string1 compare:string2 options:comparisonOptions range:string1Range locale:currentLocale];

    };

    NSLog(@"finderSort: %@",[stringsArray sortedArrayUsingComparator:finderSort]);

结果:finderSort:(

    "string 1",

    "String 02",

    "String 11",

    "string 12",

    "String 21"

)

Top
收藏
关注
评论

之前简单的纪录过关于block的一些知识点,最近有人在回帖问了个问题。顺便温习了下,感觉内容放在现在有点单薄。

于是结合提问,把相关的东西整理一下。

问题简单的说:block内局部变量无法修改,但为什么可以添加数组?比如:

NSMutableArray *mArray = [NSMutableArray arrayWithObjects:@"a",@"b",@"abc",nil];
NSMutableArray *mArrayCount = [NSMutableArray arrayWithCapacity:1];
[mArray enumerateObjectsWithOptions:NSEnumerationConcurrent usingBlock: ^(id obj,NSUInteger idx, BOOL *stop){
        [mArrayCount addObject:[NSNumber numberWithInt:[obj length]]];
    }];

我觉得这个问题和block关系不大,根本是概念没有理清:

  1. OC中数组等对象,是一个指针
  2. 数组添加/删除对象,指针本身并没有变化

因此,除非在block里对数组进行赋值,否则任何操作都是可行的。

下面总结下,block下变量的访问权限:

  1. 相同作用域下,局部变量在block内是只读的
  2. 相同作用域下,带__block修饰的变量,在block内是可读写的
  3. 静态变量和全局变量在block内是可读写的。

当block内使用了局部变量时,block会在栈上保存一份局部变量(block都是存储在栈上的),保存的变量在block里是一个常量,所以不能修改。

若是OC中的对象,blcok会retain,等执行完毕后再release。

如果有带__block的变量,那么block就可以对此变量进行修改。由此可见,带__block的变量不是线程安全的。iOS中,我们经常通过设置request的completionBlock来简化代码时,就需要注意到这一点。

block保存相同作用域下局部变量的能力和JS中匿名函数的闭包特性有点类似,看一个例子:

typedef void (^TestBlock) (void);
    int val = 20;
    TestBlock block1 = ^{ NSLog (@"%d", val); };
    val = 50;
    TestBlock block2 = ^{ NSLog (@"%d", val); };
    val = 5;
    TestBlock block3 = ^{ NSLog (@"%d", val); };
    block1();
    block2();
    block3();
    //output: 20 50 5

仿照大多数js书上会举的例子,我们还有:

TestBlock block[10];
    for (int i = 0; i < 10; i ++)
    {
        block[i] = ^{NSLog(@"the %d",i);};
        block[i]();
    }
    NSLog(@"After:\n");
    for (int i = 0; i < 10; i++)
    {
        block[i]();
    }

所以要注意block的作用域。

block本质上是对象,所以在OC中不得不提到内存管理。

int localInt = 100;
    __block int blockInt = 0;
    TestBlock blockPtr = ^{
        blockInt += localInt;

    };

如上的代码,所有的变量都存储在栈上。假如我们复制block:

TestBlock blockCopy = block_copy(blockPtr);

对于blockCopy,它也保存了局部变量localInt,但是localInt被“复制”后存储在堆里。同样的,blockInt也被“复制”存储在堆里。

但是在栈上的blockInt会生成一个指针,指向新复制到堆上的blockInt。换言之,blockInt此时是一个“共享”变量。虽然使用copy的场景并不多见,但也是需要注意的地方。

另外,Apple的文档里还提到:

如果block访问到了类的实例变量,那么block会retain self本身。

因为:

var : self->var

所以self会被retain,这种情况下有可能发生循环引用而使得内存不能释放,需要小心。

 

有不对的地方,欢迎指正。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值