Block面试题解析

 


Block是iOS4.0+ 和Mac OS X 10.6+ 引进的对C语言的扩展,用来实现匿名函数的特性。他在是一个仿对象,也可以说是一种特殊的对象,他有三种类型:

 

1.NSGlobalBlock:类似函数,位于text段

2.NSStackBlock:位于栈内存,函数返回后Block将无效;

3.NSMallocBlock:位于堆内存。

 

第一种类型:说简单一点,就是不使用外部的变量的block块就是NSGlobalBlock,可以把他看待成一个静态block,他在内存中和初始化后的全局变量,静态变量处于同一区域,日常中很少用到、因为没有意义。

第二种类型:和第一种相反,block块如果使用了auto变量,也就是局部变量,那么他就会变成NSStackBlock,他在内存中处于栈内存。在其声明的函数执行完后会被释放掉。

第三种类型:和第二种是进阶的关系,但是要分两种情况下去说明它

1.在MRC下

   NSMallocBlock只有在对NSStackBlock进行了copy操作之后,才会得到。别无他法

2.在ARC下

   原理跟MRC下差不多,只是在ARC下编译器帮你做了很多 copy 操作 如下:

  1.    当block作为函数返回值返回的时候
  2. 将block赋值给__strong指针时
  3. block作为Cocoa API中方法名含有usingBlock的方法参数时

  4. block作为GCD API的方法参数时

用一张图

 

  对于三类Block做copy、retain、release操作,结果如下

下图直观的展示了三种类型的block的内存管理:

 

 

直接上题目:

 

Example A

void exampleA() {
    char a = 'A';
    ^{
        printf("%c\n", a);
    }();
}
A:always work
B:only work with ARC
C:always workout ARC
A:never work

 

 

 

Example B
void exampleB_addBlockToArray(NSMutableArray *array) {
    char b = 'B';
    [array addObject:^{
        printf("%c\n", b);
    }];
}
void exampleB() {
    NSMutableArray *array = [NSMutableArray array];
    exampleB_addBlockToArray(array);
    void (^block)() = [array objectAtIndex:0];
    block();
}
A:always work
B:only work with ARC
C:always workout ARC
A:never work


各位看官慢慢思考!  

 

附上福利图:

最后揭晓答案。

 

 

Example C

void exampleC_addBlockToArray(NSMutableArray *array) {
    [array addObject:^{
        printf("C\n");
    }];
}
void exampleC() {
    NSMutableArray *array = [NSMutableArray array];
    exampleC_addBlockToArray(array);
    void (^block)() = [array objectAtIndex:0];
    block();
}
A:always work
B:only work with ARC
C:always workout ARC
A:never work
 

 

Example D
typedef void (^dBlock)();

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

void exampleD() {
    exampleD_getBlock()();
}
A:always work
B:only work with ARC
C:always workout ARC
A:never work

 

Example E
typedef void (^eBlock)();

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

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

A:always work
B:only work with ARC
C:always workout ARC
A:never work

 

Example F

    int multiplier = 7 ;
     void (^myBlock)( void ) = ^()
    {
            multiplier=7;
        };
printf ( "%d" , myBlock( ));
问:上面代码有问题吗?有则指出。


福利图! 答案马上揭晓

 

 

 

 

 

 

 

Example A

在arc和mrc下都可以完美运行。

 

Example B

在arc下可以运行, 这个block使用了外部变量,他的类型NSStackBlock,位于栈内存,方法结束后本应该无效,然而在arc,block会自动转成mallocblock。所以在方法结束后不会有问题。

mrc:  在这个下面,block被加入到array中,方法结束,block无效,数组中的block成了野指针,在取出时就会报错,所在在mrc下需要这么写  :  

 

 
    void (^block)() = ^{
        printf("%c\n", b);
    };
     [ array addObject:[[block copy ] autorelease]];


Example C:

 

在arc和mrc下都可以运行

 

Example D:

在arc下可以完美运行。

在mrc下,连编译都通过不了,因为编译器不允许返回一个localstack ,位于本地栈中的block

 

Exampe E:

这一题,在arc和mrc下都可以运行,但是与我的想法是不符合的,同理于Example D,应该也会报错

 

  char e = 'E';
   void (^block)() = ^{
        printf("%c\n", e);
    };
    
 2.   NSLog(@"%@",^{
        printf("%c\n", e);
    });
    
    NSLog(@"%@",block);
    
    return block;
 }

void exampleE() {
    eBlock block = exampleE_getBlock();
    NSLog(@"%@",block);
     block();

打印如下:

 

 

2014-08-02 12:41:19.356 Block_test[1054:303] <__NSStackBlock__: 0x7fff5fbff7c0>

2014-08-02 12:41:19.358 Block_test[1054:303] <__NSStackBlock__: 0x7fff5fbff7e8>

2014-08-02 12:41:19.359 Block_test[1054:303] <__NSStackBlock__: 0x7fff5fbff7e8>

 

这里如果换成return 2  这个block的话 就会报错,  这里我也不太懂。。。我想区别就在于这两种声明方法的不同,百度了也找了一些 , 没有看到很好的解释,如果有大神在看,希望能给出答案.

 

 

 

Example F:不管在arc 或者 mdc下都会报错.

错误1: block引用局部变量时,只能读不能写。否则会报错,对于static变量和全局变量都可以随意使用.

错误2:   argument type ‘void’ is incomplete 会报这个错,意思是返回参赛是void,是不完整的。所以没有返回值的block不能直接打印。

 

 

 

大概就这些! 希望能队读者有帮助,另外如果笔者有不对的地方,请无情的指正吧!~~

后面还会找一些block循环引用的面试题和分析。 尽情期待!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值