文档章节

__block的作用和功能

余成海
 余成海
发布于 2016/08/30 10:36
字数 679
阅读 56
收藏 0

哈,好久没写博客了,oschina的编辑器变漂亮啦!!!!!

int val = 0;
void (^blk)(void) =  ^{
    ++val;
};

先看代码,代码这么写的话会编译失败,提示错误:

原因在于,栈上的局部变量无法在block中编辑,block只做了只读拷贝,解决的办法当然是__block修饰啦,但是__block到底有什么作用,编译器遇到__block做了什么处理,这也是面试中常问的问题。

插个问题,考下大家,看看下面的代码输出的结果是什么.大家可以试下

int val = 0;
void (^blkk)(void) =  ^{
    NSLog(@"~~~~~~~%d", val);
};
val++;
blkk();

----------------------------凌乱分割线--------------------------------

上面的结果当然是0,因为在val++之前,block已经对val做了只读拷贝,所以后来修改val和block中的val无关了,再看下下面的代码

__block int val = 0;
void (^blkk)(void) =  ^{
    NSLog(@"~~~~~~~%d", val);
};
val++;
blkk();

结果就变成1了,所以可以看出__block的作用,__block修饰的变量在block中使用时,block不会对变量只读拷贝操作。

简单说,__block说明符类似static、auto、register一样,作用是改变变量的存储区域,它会使得修饰的变量结构化到block的自动变量中去,解释下这句话,就是说val会被存储到block结构中去。看看编译结果就很清楚了

__block int val = 0;
void ^(blk)(void) = ^(val = 1);

上面这段代码通过编译器编译后出来的结果是这样的:

struct __Block_byref_val_0 {
    void *__isa;
    __Block_byref_val_0 *__forwarding;
    int __flags;
    int __size;
    int val;
};

struct __main_block_impl_0 {
    struct __block_impl  impl;
    struct __main_block_desc_0 *Desc;
    __Block_byref_val_0 *val;

    __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_val_0 *_val, int flags=0) : val(_val->__forwarding) {
        impl.isa = &_NSConcreteStackBlock;
        impl.Flags = flags;
        impl.FuncPtr = fp;
        Desc = desc;
    }
}

static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
    __Block_byref_val_0 *val = __cself->val;
    (val->__forwarding->val) == 1;
}

........

int main()
{
    __Block_byref_val_0 val = {
        0,
        &val,
        0,
        sizeof(__Blcok_byref_val_0),
        0
    };

    blk = &__main_block_impl_0(__main_block_func_0, &__main_block_desc_0_DATA, &val, 0x2200000);

    return 0;
}

c的代码也是比较好看懂的,可以看到,int val 变成一个结构体了__Block_byref_val_0,在block的结构体中还包含了val。

 

当然大家会想到一个问题,如果有多个block会出现什么情况,同时用到val。会不会出现两个block中的val不一样呢,我们看下代码

__block int val = 0;
void (^blk0)(void) = ^{val = 1};
void (^blk1)(void) = ^{val = 2};

看下转换后的代码:

__Block_byref_val_0 val = {0, 
&val,
0,
sizeof(__block_byref_val_0, 
0)
};

blk0 = &__main_block_impl_0(__main_block,func_0, &__main_block_desc_0_DATA, &val, 0x22000000);
blk1 = &__main_block_impl_1(__main_block,func_0, &__main_block_desc_0_DATA, &val, 0x22000000);

可以看到block赋值了val结构的地址,所以两个block,拥有的是同一块val的数据。这也是编译器把val的结构体定义单独提出来,而不是放到block结构中定义的原因

© 著作权归作者所有

共有 人打赏支持
余成海
粉丝 61
博文 57
码字总数 29577
作品 0
杭州
iOS工程师
OC中的block基础知识

// 1.函数指针专门用来指向C语言的函数的指针(专门用来存储函数名的地址) // 2.选择器是用来存储OC中方法,(存的也是方法名) // 3.block也是专门用来存储方法 (存的是函数体-实现函数功...

鹿微微鹿
2016/03/29
14
0
OC block的第二个作用:协议代理

YTStaff.h #import <Foundation/Foundation.h> //拥有某种能力的对象 @interface YTStaff : NSObject //需要一个block属性 //问:block为什么要使用copy? //答:因为block变量默认是存储在栈...

鹿微微鹿
2016/03/29
21
0
OC中block的作用

Math.h #import <Foundation/Foundation.h> @interface Math : NSObject{ // NSString * _name; } @property(nonatomic, copy) NSString * name; //_name //按给定的方式去计算两个整型数据的......

鹿微微鹿
2016/03/29
96
0
Objective-C中 Block 在iOS在4.0版本的使用

Objective-C中 Block 在iOS在4.0版本的使用 了解何谓block。 了解block的使用方法。 Block 是iOS在4.0版本之后新增的程序语法. 在iOS SDK 4.0之后,Block几乎出现在所有新版的API之中,换句话...

浩浩老师
2015/09/11
228
0
Oracle Internal Event:10200 Consistent Read诊断事件

10200(consistent read buffer status)内部诊断事件可以用于探测一致性读CR(consistent read)块的访问情况,虽然cr读的统计信息可以从v$sysstat或AWR/statspack中获取,但是10200 event还是我...

科技小能手
2017/11/12
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

idea新建springCloud项目(5)- 订单服务

1.创建订单api,如下: 2.创建订单实现逻辑 3.新建订单、订单商品表 -- 订单 create table `order_master` ( `order_id` varchar(32) not null, `buyer_name` varchar(32) not null comment......

monroeCode
2分钟前
0
0
游戏开发经验谈(二):对战类全球服游戏的设计与实现

上篇文章《游戏开发经验谈(一):游戏架构里隐藏的五个坑及其应对方案》,我们主要讲解了游戏架构设计当中隐藏的一些坑及其应对方案,错过的小伙伴可以回溯之前的内容。本期内容,将会重点介...

UCloudTech
12分钟前
0
0
Mysql基本语法

一.联合主键 drop table CONTENT_AND_CATALOG;CREATE TABLE `tobebetter`.`CONTENT_AND_CATALOG` ( `ID` VARCHAR(120) NOT NULL , `CONTENT_ID` VARCHAR(120) , `CA......

我是菜鸟我骄傲
13分钟前
0
0
179. centos7 安装mariadb

1. centos7 中安装mariadb 1.1 执行安装 centos7 自带了mariadb yum -y install mariadb mariadb-server 1.2 启动mariadb systemctl start mariadb 1.3 设置开机启动 systemctl enable maria......

Lucky_Me
20分钟前
0
0
【AI实战】动手训练自己的目标检测模型(YOLO篇)

在前面的文章中,已经介绍了基于SSD使用自己的数据训练目标检测模型(见文章:手把手教你训练自己的目标检测模型),本文将基于另一个目标检测模型YOLO,介绍如何使用自己的数据进行训练。 ...

雪饼
26分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部