设为首页 加入收藏

TOP

OC高级编程――深入block,如何捕获变量,如何存储在堆上(一)
2015-01-22 20:57:45 来源: 作者: 【 】 浏览:43
Tags:高级 编程 深入 block 如何 捕获 变量 存储

首先先看几道block相关的题目

这是一篇比较长的博文,前部分是block的测试题目,中间是block的语法、特性,block讲解block内部实现和block存储位置,请读者耐心阅读。具备block基础的同学,直接调转到block的实现

下面列出了五道题,看看能否答对两三个。主要涉及block栈上、还是堆上、怎么捕获变量。答案在博文最后一行

//-----------第一道题:--------------
void exampleA() {
  char a = 'A';
  ^{ printf("%c\n", a);};
}
A.始终能够正常运行          B.只有在使用ARC的情况下才能正常运行
C.不使用ARC才能正常运行     D.永远无法正常运行
//-----------第二道题:答案同第一题--------------
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();
}
//-----------第三道题:答案同第一题--------------
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();
}
//-----------第四道题:答案同第一题--------------
typedef void (^dBlock)(); 
dBlock exampleD_getBlock() {
  char d = 'D';
  return ^{printf("%c\n", d);};
}
void exampleD() {
  exampleD_getBlock()();
}
//-----------第五道题:答案同第一题--------------
typedef void (^eBlock)(); 
eBlock exampleE_getBlock() {
  char e = 'E';
  void (^block)() = ^{printf("%c\n", e);};
  return block;
}
void exampleE() {
  eBlock block = exampleE_getBlock();
  block();
}

注:以上题目摘自:CocoaChina论坛点击打开链接

block概要

什么是block

Blocks是C语言的扩充功能。可以用一句话来表示Blocks的扩充功能:带有自动变量(局部变量)的匿名函数。命名就是工作的本质,函数名、变量名、方法名、属性名、类名和框架名都必须具备。而能够编写不带名称的函数对程序员来说相当有吸引力。 例如:我们要进行一个URL的请求。那么请求结果以何种方式通知调用者呢?通常是经过代理(delegate)但是,写delegate本身就是成本,我们需要写类、方法等等。 这时候,我们就用到了block。block提供了类似由C++和OC类生成实例或对象来保持变量值的方法。像这样使用block可以不声明C++和OC类,也没有使用静态变量、静态全局变量或全局变量,仅用编写C语言函数的 源码量即可使用带有自动变量值的匿名函数。 其他语言中也有block概念。

block的实现

block的语法看上去好像很特别,但实际上是作为极为普通的C语言代码来处理的。这里我们借住clang编译器的能力:具有转化为我们可读源代码的能力。 控制台命令是: clang -rewrite-objc 源代码文件名。
int main(){
    void (^blk)(void) = ^{printf("block\n");};
    blk();
    return 0;
}
经过 clang -rewrite-objc 之后,代码 编程这样了(简化后代码,读者可以搜索关键字在生成文件中查找):
struct __block_impl{
    void *isa;
    int Flags;
    int Reserved;
    void *FuncPtr;
};
static struct __main_block_desc_0{
    unsigned long reserved;
    unsigned long Block_size
}__main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};

struct __main_block_impl_0{
    struct __block_impl impl;
    struct __main_block_desc_0 *Desc;
}
static struct __main_block_func_0(struct __main_block_impl_0 *__cself)
{
    printf("block\n");
}
int main(){
    struct __main_block_impl_0 *blk =  &__main_block_impl_0(__main_block_func_0,&__main_block_desc_0_DATA);
    (*blk->impl.FuncPtr)(blk);
}
很多结构体,很多下划线的变量和函数名。我们一个个来: __block_impl:更像一个block的基类,所有block都具备这些字段。
__main_block_impl_0:block变量。
__main_block_func_0:虽然,block叫,匿名函数。但是,这个函数还是被编译器起了个名字。
__main_block_desc_0:block的描述,注意,他有一个实例__main_block_desc_0_DATA 上述命名是有规则的:main是block所在函数的名字,后缀0则是这个函数中的第0个block。由于上面是C++的代码,可以将__main_block_impl_0的结构体总结一下,得到如下形式:
__main_block_impl_0{
    void *isa;
    int Flags;
    int Reserved;
    void *FuncPtr;
    struct __main_block_desc_0 *Desc;
}
总结:所谓block就是Objective-C的对象

截获自动变量值

int val = 10;
void (^blk)(void) = ^{printf("val=%d\n",val);};
val = 2;
blk();

上面这段代码,输出值是:val = 10.而不是2.block截获自动变量的瞬时值。因为block保存了自动变量的值,所以在执行bloc

首页 上一页 1 2 3 下一页 尾页 1/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇简述C疑难杂症_序列点(二) 下一篇C语言其实不简单:sizeof

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: