不会开机的男孩

如何问问题

| Comments

如何问问题,这是一个非常有意思的问题.恩.事实上,对很多初学者来说,特别是在工作中,遇到最多的就是,不会问问题.

同样, 对于”自己”,这个独特的领域下,如何去问问题,依然是一个非常头疼的问题.

这个可能听上去很奇怪,不过却是一个很常见的问题.就是,我们常常问自己问题.比如,当我们的一段感情出现了问题.一段工作合作经历不愉快,我们总是在问,”what’s wrong, what’s not working, how can I improve it” 恩,事实上这个没有任何问题.特别是对那些拥有强大驱动力的家伙们,喜欢打鸡血的家伙们,总是愿意从任何角度去思考如何能够做的更好,这个问题在那里. 呵呵, 有时候真的非常讽刺, 写到这里我脑子里在想什么? “下午的扑克牌,我出的牌还是有问题,如果blah blah blah, 那么yadda yadda yadda”, 恩,这个本来没有任何问题.但是,如果问自己的问题或是思考的问题,只是这个,那么这个,就是一个很大的问题.

一个很简单的例子, 如果有人问我 “你的缺点是什么”, “固执,自闭,不好沟通,懒惰”. 但如果问题,”你的优点是什么”, 好吧,我真的一下子回答不上来,我需要思考很久,而且,似乎,恩,直到现在我也没有一个让自己信服的答案.

为什么会出现这种问题. 有很大原因,这个问题是出在了思考问题的方式中, 有时候,或是,在大多数时候,注意力过于集中了.恩. 这是一个好的习惯, 能够更好的集中注意力, 能够在嘈杂的环境下学习, 能够抵抗大家娱乐时,冷静思考. 因为,这个世界有太多的诱惑, 太多的噪音, 不管是真的生活环境, 还是别人的建议. 一点点动作,都会分心会降低很大的效率, 但是,如果总是,恩,我指的是总是,那么,会导致一个非常严重的问题,就是, 你关注的,只是你想关注的事情,而并不关注那些已经存在,甚至就在眼前的事情,这样,同一件事情,所获得的经历,或是事物的看法,会受到非常大的自己注意力的约束.

一个简单的例子,就拿下午和同事们一起打牌放松, 其实现在想来应该是一个很放松的一个环境.但显然有点被我搞糟了,至少大家的情绪受到了影响.呼, 也许我太过在意打牌输赢的这个结果, 总是会去埋怨队友不该这么出牌,而对手出错了则会很开心的去”讥笑”, 幸灾乐祸. 因为我的脑瓜子里面塞的全是,如何能够获胜,我需要教会我的队友如何出牌,然后我需要用我的情绪影响我的队手,这样他们会犯更多的错误,我会去不由自主的去记忆出牌的每一个环节,而其他人更多的只是一个娱乐的心态,因为并不是一个竞争的事情,大家不去care 这个结果,所以不会像我那样废脑子记忆之前的一些动作 ,而是开心一起玩的过程.而我显然只是关注于比赛的输赢.恩,只是注意这个结果,甚至细节到每一轮出牌,是否能够做的更好.更纠结的是,完了,我还会反思.有些地方,可以做的更好.

同样,在面对一段失败的经历时,同样, 看到的也会全部聚焦在如何解决问题,如何提高效率,如何能够更快.更好. 等等, 而并没有去在意收获到什么.也不去在意自己的优点而只是在意自己的缺点, 恩,如何改正.

这是一个道理的.

因为,如果你在一个团队工作, 如果你说出来的只是,”what’s wrong, how can we improve it”, 会打击到更多人的积极性.人们会感到失落.会感到更多的压力,当然,不同的人会喜欢不同的环境,我不排除有人喜欢高压力,高动力. 但如果全部都是这些话,那么这个就是一个非常严重的问题.

当然,这个不仅仅在工作中,生活中,特别是和家庭成员的关系,更是这样子的.想想一直说你不行,不行, 别人家的孩子,怎怎怎的老妈吧, 那个永远处在高处藐视你一切努力成果的别人家的孩子. 好吧,我这里不想去讨论过多这些东西.要不我妈又要给我打电话了. 这个东西毕竟还是准备在空间发的: ), 好吧,不能要求父母太多,因为他们有他们的教育背景, 和生活背景.80后父母的他们那一代,能够做到这些,能够了解自己情绪的实在是太难了.

如何问问题, 其实这个不是问问题,而是如何思考问题.思考的方式,决定了现实.

又是一轮成长

| Comments

从搬到新办公室到现在差不多半年了,有些东西,本来是想,在年终总结的时候写,但想想,还是现在记录最合适,毕竟那些只是一个形式.重要的还是自己最近的思考,或是看过一些书后的感想吧.

每天花半个小时健身或游泳,体重成功减少10斤,稳定150,把肚子上的肉,部分转移到肩膀和胳膊,有人说我瘦了,而且,肩膀比之前展了,自然了 : ) 开心.

每周花4个小时上英语课,6-8个小时做英语题和复习,每天听写半个小时到1个小时.

每天注意饮食,少吃肉,多吃菜.多喝汤的生活,加上一个学习英语的好习惯,使自己从之前对英文的厌倦,到可以比较轻松的阅读计算机专业书籍,Apple产品发布会,WWDC dev video, 公开课.

当然,也干砸过事情,第一次创业的公司被我们搞砸了.经过2次融资后,还是和大部分创业公司一样最后不得不结束.但,不同的,就是我们team还没有散伙,也不能算是干砸,算是一个新的开始吧.

但我觉得最重要的收获不是这些技能.或是习惯.而是我第一次真正的能够面对自己的内心.意识到了心智成熟的重要,感觉到了长大的烦恼.

我忘记了是那本书上写的这样类似的内容.来形容人的成长.

在人还是婴儿的时候,人认为整个世界就是他自己或没有自己的概念但随着成长,慢慢有了我的概念,知道了,这是我的胳膊,我的眼睛,我的鼻子.我的妈妈. 再长大一点.开始更清楚的认识到自己,我的妈妈不是自己所能控制,人们通过哭闹来得到妈妈的照顾.再长大一点,认识到自己需要自己照顾自己.再长大了,我们发现我们周围的人和你的想法也不一样,他们都是不同的个体.等等

如果把自己的所能控制的范围,成为自我界限吧,个人成长似乎就是一个慢慢缩小,更清晰的一个过程.似乎是更倾向于科幻小说中,人类最后都会走向孤独.

但事实上,还有一种成长,就是爱.能够穿越这些自我界限,一开始人们只是知道对自己好,本能的逃避危险,有些时候,伤害别人也并不在意.再长大一点,我们会考虑到父母,再长大一点,会慢慢考虑更多的人.

就像太阳系诞生之初,各个天体随着引力作用下,不断坍缩,但最后都在彼此作用下,维持一个完美的平衡.互补侵犯.但谁都离不开谁的状态.

想想1年前的我的总结.http://www.cnblogs.com/studentdeng/archive/2012/01/13/2321813.html

很清楚的感觉出,当时我只是考虑到自己.意识到自己的发展,而没有或是几乎没有考虑到别人的感受,整个文章中,充满了’我’, ‘我的想法’, ‘我觉得’. 恩,当时的自己,还是挺自恋的 : ) 现在也是.呵呵, 记得,在创业的时候,算是我的一个大哥兼同事, 他对我说过, ‘我没有过多的考虑自己的发展和提高,而是在团队的角度去看,我需要做什么,如何才能让大家调动起来,而当大家都有很大收获,就是我的收获’,恩,当时在1年前,我真的没有当回事,觉不出来这里面的意思.现在看来,这个应该就是我所想的更大的爱,能够穿过自己的界限,来让自己得到成长.

其实,不仅仅是创业的过程, 玩游戏也一样, 在开始的时候,我们只能控制自己,做好自己.而当玩的越来越好时,我们需要更多的和队友配合,而到更高级,我们需要去思考对手最什么, 如何去欺骗对手,落入我们的圈套,落入我们的节奏,不知不觉中慢慢积累优势,最后成为不可逆转的胜势.

从本质来看,都是,自己的思维方式,思维角度,不能仅仅局限在自己的界限内,还需要拓展到更大的空间中,才能更好的把握自己,把握团队.因为现在的社会,不是小农经济的自给自足,需要更多的人协作,配合才能更高效的实现自己的梦想. 是的. 更高效, 因为现在小步慢跑已经是落后的.

现在来看,我真的要感谢那个我第一次喜欢上的女孩吧.要知道,如果你在人生的低潮,公司运营难度极大,大家每天都在煎熬,感觉什么事情都推动不下去, 但却侥幸拿到融资, 万事俱备,但却又失去发展方向,第一次非常严重的质疑自己能力时, 有一个女孩很有耐心的开导你,再呆的家伙也会对那个女孩动心.

虽然从心理学来讲,得不到的总是会觉得好,但这个过程让我真正的明白了,世界上的,每个人都有自己的想法,都是不同的个体,有自己不同的想法.很多时候,并不是你想怎么样,就可以怎么样.也第一次真正的意识到自己的心理问题或是思维习惯,虽然在过去的时光,我在这种习惯下,收获非常多.

怎么形容过去的习惯呢? 其实,每天坚持健身,跑步,游泳,同事还要保证满负荷工作,学习,真心的很累,很多时候,都希望躺在床上休息, 但最后都会坚持,因为只要想到有人也在坚持, 而自己没有做到,就觉得有严重的负罪感,当走到健身房,看到有人在运动,全身在疲倦都会像打了鸡血一样.而且,越是疲劳,做的越多.游泳的时候, 只要有人一起游泳,那么就要比他游的远,如果没有人,就心里构思一个人

长期的这种思维下,虽然会使得执行力非常高,但是对周围其他人的感受却是越来越少,同时又因为受到他人影响小,所以决断力又会凸显的很高.但这其实不是真正的执行力高,也不是决断力高,只是一个自私自利的表现,或至少是自己的效率极高,而不管他人.在前期的提升来说,的确是非常的高效.但当真正的需要和多人配合,甚至是去喜欢一个人时,就显得发育不平衡了. 就像锻炼肌肉, 不平衡,导致身体不协调一样,同样跑不快.因为大家都知道的木桶原理.

其实,我老早就有人说过我,但我的性格却是非常的固执,那种不撞南墙不会头的那种. 而那个女孩,算是第一堵墙,撞的我头破血流, 几个月无法全心工作,有大半个月甚至几乎不工作,只是抱着一本物理书看.因为我自己的一直赖以骄傲的价值观和思维方式被判了死刑,我感觉到了无与伦比的沦陷,而那本书,正好讲的是传统物理学在量子物理的冲击下,而摇摇欲坠, 这种沦陷,让我感到了放松,所以,真真正正的体会到了爱因斯坦在面对量子物理的无奈,甚至说出了”难道上帝也仍色子么?”这样无力的问题.因为我内心也有这样一个问题,我自己该怎么办,难道只能人云亦云,走那些很多人走的老路子么

我没有办法想清楚,但我唯一能清楚的是,我又要长大了. 如果说,创业的第一年主要是技术,工作经验的积累,那么,第二年,真的,没有太多技术的积累,更多的就是心智的成熟.如何能够不让你的消极心里,影响到自己和团队的其他人,如何做事情更靠谱等等.

这段时间,遇到了真的是,人生中的第一次重大的问题,人生观的修正.需要放弃之前已经根深蒂固的想法.真的是很难受,很难受.我的运气真的很好,整个创业的team给了我很多的时间去调整并开导我,而我也在豆瓣上认识了另一个女孩,一个非常博学的笔友,虽然比我还要小,但是却很睿智,看了非常多非常多的书,也给了我很多帮助,当然,最关键的还是自己.也许正是因为这个很难,很难,我的鸡血又开始打上了.开始正视自己的不足, 肯定自己的优点,开始学如何更好的控制自己的情绪,如何更好的思考周围的人.等等.

这是每一个低情商男孩们都会遇到的问题.特别是对geek们来说.

所以也就从这里开始吧,自己开始注意了解自己. 有时候,古人的话,还是很有道理的, “齐家治国平天下”,当然,这里并不是必须首先结婚,而是,要想成功,需要能够更了解自己,控制自己.更了解别人.自己的朋友, 甚至的你的对手.

说到这次创业,又不得不多扯几句, 前几个月,哥几个谈的时候,还说, 我们又要到一个关键时候了. 是啊, 每到一段时间都要做个困难的抉择.让我不禁想起当时家长们长长说的, 考上一个好的初中是人生转折点,好的高中是人生转折点,好的大学是人生转折点. 当时的想法是,这么多转折点也该回到原点了吧. 哈哈

现在不这么想了,每个这样的时候,都是成长的机会.

真的非常庆幸,自己在毕业时,选择创业这条路子.第一年磨练技术,第二年磨练心志,没有比这更完美的了,不是么 : )

想想去年定的目标,恩,今年算是达到了.无论从App Store的rank 还是推荐次数,都已经是翘楚了.第三年,不像第二年有投资人, 也不像第一年有备用金.但却是真正了解自己的开始.

也许真正的创业,才刚刚开始,同时,心智成熟的路也刚刚起步.

目标么,很简单,养活自己.养活团队,大家过的更好一点,认识更多朋友.好空泛啊, 来一点实际的吧, 雅思过7,月薪过万.

正好说到钱这个问题.虽然很沉重,但的确是一个问题,我还年轻,无所谓,但是对团队里的一些大哥们,快30 要不已经30了,本来年薪都是2,30W妥妥的安稳轻松的工作,而现在在这里苦逼,其实过程中,暗中,恩,包括我都放弃了很多很多次. 但最后都坚持下来,为啥呢, 也许都是一路人吧, 都是一些习惯打鸡血, 幼稚,固执的一帮人.

Orange‘s 一个操作系统的实现 配置问题

| Comments

最近在瞅《Orange‘s 一个操作系统的实现》,个人认为相当好的OS入门实践书籍,配合之前看过的大部分的理论书,容易理解那些抽象的概念(无代码无真相),

和《Linux内核完全注释》都是相当不错的入门书籍。

这里记录一下可能遇到的问题,主要是配置问题,实现逻辑书里面很详细,代码注释也很详细,仔细多想应该没啥问题。

我这里环境是ubuntu 10 64bit, 而书中代码是32bit的。这里在编译链接的时候出了一点小问题。这里记录下。

错误:

ld: i386 architecture of input file `kernel/kernel.o' is incompatible with i386:x86-64 output

需要修改makefile

CFLAGS          = -I include/ -c -fno-builtin -m32
LDFLAGS         = -m elf_i386 -s -Ttext $(ENTRYPOINT)

错误:

klib.c:(.text+0xe5): undefined reference to `__stack_chk_fail'

这里应该是少了c的标准库,还是需要修改makefile文件

LDFLAGS         = -m elf_i386 -s -Ttext $(ENTRYPOINT) -lc

Bochs-configure

| Comments

Bochs + freedos安装配置

sudo apt-get install build-essential

sudo apt-get install xorg-dev

sudo apt-get install libgtk2.0-dev

下载

bochshttp://bochs.sourceforge.net/cgi-bin/topper.pl?name=See+All+Releases&url=http://sourceforge.net/projects/bochs/files

$ tar vxaf bochs-2.5.1.tar.gz

$ cd bochs-2.5.1

$ ./configure –enable-debugger-enable-disasm

$ make

$ sudo make install

下载freedoshttp://bochs.sourceforge.net/diskimages.html 复制到工作目录下

Bochs 配置 先通过dos引导,我们的软件复制在B盘下

############################################################### 
# Configuration file for Bochs 
###############################################################

# how much memory the emulated machine will have 
megs: 32

# filename of ROM images 
romimage: file=/usr/share/bochs/BIOS-bochs-latest 
vgaromimage: file=/usr/share/vgabios/vgabios.bin

# what disk images will be used 
floppya: 1_44=freedos.img, status=inserted 
floppyb: 1_44=pm.img, status=inserted

# choose the boot disk. 
boot: a

# where do we send log messages? 
# log: bochsout.txt

# disable the mouse 
mouse: enabled=0

# enable key mapping, using US layout as default. 
keyboard_mapping: enabled=1, map=/usr/share/bochs/keymaps/x11-pc-us.map

#enabled debug using xchg bx, bx

magic_break:enabled=1

可以通过下面方式来部署程序,当然,写成makefile最省事

$ sudo mount –o loop pm.img /mnt/floppy

$ sudo cp test.com /mnt/floppy

$ sudo umount /mnt/floppy

bochs 调试

调试方法很多,这里介绍最简单的方式之一。bochs 配置中增加 magic_break:enabled=1

代码中增加xchg bx, bx,bochs会停在代码出。当然,前提是bochs需要支持debug

Objective-C Block

| Comments

block 有什么意义,特点等等,这些东西,实在是太复杂了,这里只是简单的总结一下block的内存管理。而且也仅仅限于objective-C的部分

Block memory

block 的内存管理,应该是最头疼的地方,就用这个来自WWDC的例子来解释一下吧。

alt text

当程序运行到这里时,stack 空间中有 shared 变量和 captured 变量。

这里可以看出,__block 变量开始是处于stack上的。

alt text

当程序运行到这里时,stack 空间中有 shared 变量,captured 变量和block1。

这里可以看出,block 类型的变量开始时也是处在stack上的。

alt text

当程序运行到这里时,stack 空间中有 shared 变量,captured 变量和block1。

这里值得注意的就是当我们直接修改stack 上的captured变量时,block1中的captured变量仍然是原来的数值10。事实上,从const 我们就可以看出,block1中的captured变量是不能被修改的而且是从stack原有变量的一个const 拷贝。在block1中访问的captured变量是const拷贝的,也就是说block1中captured = 10,而不是原有的stack上的值 20。当然,在block1中,我们也不能修改captured变量。

Copy block

block在一开始是处在stack上的,这是为了考虑到效率的原因,但是,有时候是需要block的生命周期长于一开始的stack,这时,我们就通过copy block 来将block复制到heap。

alt text

当程序执行完 block2 = [block1 copy];时,__block 类型变量shared,被复制到了heap中,很显然,shared变量需要被block和block2共享(当然还有stack也要共享),而block2被移动到heap中,很可能生命周期会长于stack,所以,shared也被复制到了heap中。而block2中的captured 也被复制到了heap中。

alt text

当程序执行完 block3 = [block2 copy];时, 我们看到的是,block2 和block3 其实指向的是同一片内存空间。事实上,block的数据结构中,保存了引用计数,而对于copy到heap中的block 再copy时,行为同普通对象retain一样,会使引用计数+1。那么如果我们对[block retain]会如何呢? 实际上什么都没有发生,至少在现在的runtime版本下。因为retain中,不仅有引用计数+1在,而且retain的返回值,必须同返回调用对象的地址一样,而block的地址是可能变化的(stack or heap),所以,这里retain的行为几乎是被忽略掉的。

当heap中的block变量先于stack被销毁时,如调用 [block2 release]; [block3 release];,heap中的block2,block3 由于引用计数为0 而被销毁,而 __block 变量shared则还在heap中,因为stack还要使用,block1 也要使用。

alt text

当heap中的block变量晚于stack时,显然,stack 被清除,function中也啥都没了。

alt text

最后,当block2 和block3 都被release之后。则恢复到最初状态

alt text

block details

当我们写出一个Block literal expression

^ { printf("hello world\n"); }

事实上,编译器为我们生成了如下结构

struct __block_literal_1 {
    void *isa;
    int flags;
    int reserved; 
    void (*invoke)(struct __block_literal_1 *);
    struct __block_descriptor_1 *descriptor;
};void __block_invoke_1(struct __block_literal_1 *_block) {
    printf("hello world\n");
}static struct __block_descriptor_1 {
    unsigned long int reserved;
    unsigned long int Block_size;
} __block_descriptor_1 = { 0, sizeof(struct __block_literal_1)}; 当Block literal expression 使用时 __block_literal_1 则会被初始化为:struct __block_literal_1 _block_literal = {
    &_NSConcreteStackBlock,
    (1<<29), <uninitialized>,
    __block_invoke_1,
    &__block_descriptor_1
   };

下一个例子

int x = 10;
void (^vv)(void) = ^{printf("x is %d\n", x);};
x = 11;
vv();
编译器会生成如下结构
struct __block_literal_2{
    void *isa;
    int flags;
    int reserved;
    void (*invoke)(struct __block_literal_2 *);
    struct __block_descriptor_2 *descriptor;
    const int x;
};
void __block_invoke_2(struct __block_literal_2 *_block){
    printf("x is %d\n", _block->x);
}
void struct __block_descriptor_2{
    unsigned long int reserved;
    unsigned long int block_size;
}__block_descriptor_2 = {0, sizeof(struct __block_literal_2)};
struct __block_literal_2 __block_literal_2 = {
    &NSConcreteStackBlock,
    (1<<29),
    __block_invoke_2,
    &__block_descriptor_2,
    x
};

block中使用的普通变量(int, char *)导入是const copy。普通对象则会retain。__block 类型变量则什么不做,只是保存一个指针,全局变量也只是保存一个简单的指针。

当然,block 可能也会嵌套block,那么又会是什么样子?其实不复杂,复杂的只是增加了复制函数,和释放函数,这一点很像C++的拷贝构造函数,在必要时生成。

void (^existingBlock)(void) = …;
void (^vv)(void) = ^{existingBlock();};
vv();
struct __block_literal_3{
    ...;//esisting block
};
struct __block_literal_4{
    void *isa;
    int flags;
    int reserved;
    void (*invoke)(struct __block_literal_4 *);
    struct __block_literal_3 *const existingBlock;
};
void __block_invoke_4(struct __block_literal_3 *__block) {
   __block->existingBlock->invoke(__block->existingBlock);
}
void __block_copy_4(struct __block_literal_4 *dst, struct __block_literal_4 *src) {
     //_Block_copy_assign(&dst->existingBlock, src->existingBlock, 0);
     _Block_object_assign(&dst->existingBlock, src->existingBlock, BLOCK_FIELD_IS_BLOCK);
}
void __block_dispose_4(struct __block_literal_4 *src) {
     // was _Block_destroy
     _Block_object_dispose(src->existingBlock, BLOCK_FIELD_IS_BLOCK);
}
static struct __block_descriptor_4 {
    unsigned long int reserved;
    unsigned long int Block_size;
    void (*copy_helper)(struct __block_literal_4 *dst, struct __block_literal_4 *src);
    void (*dispose_helper)(struct __block_literal_4 *);
} __block_descriptor_4 = {
    0,
    sizeof(struct __block_literal_4),
    __block_copy_4,
    __block_dispose_4,
};

初始化

  struct __block_literal_4 _block_literal = {
    &_NSConcreteStackBlock,
    (1<<25)|(1<<29), <uninitialized>
    __block_invoke_4,
    & __block_descriptor_4
        existingBlock,
   };


__block storage variables

__block  变量是一种很特殊的数据类型,有自己的特有的数据结构

struct _block_byref_xxxx {
    void *isa;
    struct _block_byref_xxxx *forwarding;
    int flags;   //refcount;
    int size;
    // helper functions called via Block_copy() and Block_release()
    void (*byref_keep)(void  *dst, void *src); //需要时被生成
    void (*byref_dispose)(void *);//需要时被生成
    typeof(marked_variable) marked_variable;
};

看看__block 类型变量的使用

int __block i = 10;
i = 11;
struct _block_byref_i {
    void *isa;
    struct _block_byref_i *forwarding;
    int flags;   //refcount;
    int size;
    int captured_i;
} i = { NULL, &i, 0, sizeof(struct _block_byref_i), 10 };
i.forwarding->captured_i = 11;

显然,当block中增加了block 类型变量之后,嵌套block 的拷贝函数也会增加对block 变量的复制。

__block void (voidBlock)(void) = blockA;
voidBlock = blockB;
struct _block_byref_voidBlock {
    void *isa;
    struct _block_byref_voidBlock *forwarding;
    int flags;   //refcount;
    int size;
    void (*byref_keep)(struct _block_byref_voidBlock *dst, struct _block_byref_voidBlock *src);
    void (*byref_dispose)(struct _block_byref_voidBlock *);
    void (^captured_voidBlock)(void);
};
void _block_byref_keep_helper(struct _block_byref_voidBlock *dst, struct _block_byref_voidBlock *src) {
    //_Block_copy_assign(&dst->captured_voidBlock, src->captured_voidBlock, 0);
    _Block_object_assign(&dst->captured_voidBlock, src->captured_voidBlock, BLOCK_FIELD_IS_BLOCK | BLOCK_BYREF_CALLER);
}
void _block_byref_dispose_helper(struct _block_byref_voidBlock *param) {
    //_Block_destroy(param->captured_voidBlock, 0);
    _Block_object_dispose(param->captured_voidBlock, BLOCK_FIELD_IS_BLOCK | BLOCK_BYREF_CALLER)}
struct _block_byref_voidBlock voidBlock = {( .forwarding=&voidBlock, .flags=(1<<25), .size=sizeof(struct _block_byref_voidBlock *),
      .byref_keep=_block_byref_keep_helper, .byref_dispose=_block_byref_dispose_helper,
      .captured_voidBlock=blockA )};
voidBlock.forwarding->captured_voidBlock = blockB;

block中,引入了__block 会是什么情况

int __block i = 2;
functioncall(^{ i = 10; });
struct _block_byref_i {
    void *isa;  // set to NULL
    struct _block_byref_voidBlock *forwarding;
    int flags;   //refcount;
    int size;
    void (*byref_keep)(struct _block_byref_i *dst, struct _block_byref_i *src);
    void (*byref_dispose)(struct _block_byref_i *);
    int captured_i;
};
struct __block_literal_5 {
    void *isa;
    int flags;
    int reserved; 
    void (*invoke)(struct __block_literal_5 *);
    struct __block_descriptor_5 *descriptor;
    struct _block_byref_i *i_holder;
};
void __block_invoke_5(struct __block_literal_5 *_block) {
   _block->i_holder->forwarding->captured_i = 10;
}
void __block_copy_5(struct __block_literal_5 *dst, struct __block_literal_5 *src) {
     _Block_object_assign(&dst->i_holder, src->i_holder, BLOCK_FIELD_IS_BYREF | BLOCK_BYREF_CALLER);
}
void __block_dispose_5(struct __block_literal_5 *src) {
     _Block_object_dispose(src->i_holder, BLOCK_FIELD_IS_BYREF | BLOCK_BYREF_CALLER);
}
static struct __block_descriptor_5 {
    unsigned long int reserved;
    unsigned long int Block_size;
    void (*copy_helper)(struct __block_literal_5 *dst, struct __block_literal_5 *src);
    void (*dispose_helper)(struct __block_literal_5 *);
} __block_descriptor_5 = { 0, sizeof(struct __block_literal_5) __block_copy_5, __block_dispose_5 };
struct _block_byref_i i = {( .forwarding=&i, .flags=0, .size=sizeof(struct _block_byref_i) )};
struct __block_literal_5 _block_literal = {
    &_NSConcreteStackBlock,
    (1<<25)|(1<<29), <uninitialized>,
    __block_invoke_5,
    &__block_descriptor_5,
        2,
   };

block 中的太多细节这里不做赘述,有兴趣的可以参考Block—ABI-Apple,也可以直接这里去看。