oc block 测试

http://blog.parse.com/learn/engineering/objective-c-blocks-quiz/



Do you really know how blocks work in Objective-C? Take this quiz to find out.

All of these examples have been verified with this version of LLVM:

Apple clang version 4.1 (tags/Apple/clang-421.11.66) (based on LLVM 3.1svn)
Target: x86_64-apple-darwin11.4.2
Thread model: posix

Example A

void exampleA() {
  char a = 'A';
  ^{
    printf("%cn", a);
  }();
}

This example

That's correct. This always works. The stack for exampleA doesn't go away until after the block has finished executing. So whether the block is allocated on the stack or the heap, it will be valid when it is executed.

Example B

void exampleB_addBlockToArray(NSMutableArray *array) {
  char b = 'B';
  [array addObject:^{
    printf("%cn", b);
  }];
}

void exampleB() {
  NSMutableArray *array = [NSMutableArray array];
  exampleB_addBlockToArray(array);
  void (^block)() = [array objectAtIndex:0];
  block();
}

This example

That's correct. Without ARC, the block is an NSStackBlock allocated on the stack of exampleB_addBlockToArray. By the time it executes in exampleB, the the block is no longer valid, because that stack has been cleared.

With ARC, the block is properly allocated on the heap as an autoreleased NSMallocBlock to begin with.

Example C

void exampleC_addBlockToArray(NSMutableArray *array) {
  [array addObject:^{
    printf("Cn");
  }];
}

void exampleC() {
  NSMutableArray *array = [NSMutableArray array];
  exampleC_addBlockToArray(array);
  void (^block)() = [array objectAtIndex:0];
  block();
}

This example

That's correct. Since the block doesn't capture any variables in its closure, it doesn't need any state set up at runtime. it gets compiled as an NSGlobalBlock. It's neither on the stack nor the heap, but part of the code segment, like any C function. This works both with and without ARC.

Example D

typedef void (^dBlock)();

dBlock exampleD_getBlock() {
  char d = 'D';
  return ^{
    printf("%cn", d);
  };
}

void exampleD() {
  exampleD_getBlock()();
}

This example

That's correct. This is similar to example B. Without ARC, the block would be created on the stack of exampleD_getBlock and then immediately become invalid when that function returns. However, in this case, the error is so obvious that the compiler will fail to compile, with the error error: returning block that lives on the local stack.

With ARC, the block is correctly placed on the heap as an autoreleased NSMallocBlock.

Example E

typedef void (^eBlock)();

eBlock exampleE_getBlock() {
  char e = 'E';
  void (^block)() = ^{
    printf("%cn", e);
  };
  return block;
}

void exampleE() {
  eBlock block = exampleE_getBlock();
  block();
}

This example

That's correct. This is just like example D, except that the compiler doesn't recognize it as an error, so this code compiles and crashes. Even worse, this particular example happens to work fine if you disable optimizations. So watch out for this working while testing and failing in production.

With ARC, the block is correctly placed on the heap as an autoreleased NSMallocBlock.

Conclusions

So, what's the point of all this? The point is always use ARC. With ARC, blocks pretty much always work correctly. If you're not using ARC, you better defensively block = [[block copy] autorelease] any time a block outlives the stack frame where it is declared. That will force it to be copied to the heap as an NSMallocBlock.

Haha! No, of course it's not that simple. According to Apple:


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值