Block

block的基础知识

block修饰是用strong还是copy

对于现在而言,这两种都可以了,因为在ARC的模式下,它会把block移动到堆上

block的分类
//ARC 模式下
        // Global:没有访问auto变量:__NSGlobalBlock__
                void (^block1)(void) = ^{
                    NSLog(@"block1---------");
                };
                // Stack:访问了auto变量: __NSStackBlock__
                int a = 10;
                void (^block2)(void) = ^{
                    NSLog(@"block2---------%d", a);
                };
                NSLog(@"%@ %@", [block1 class], [block2 class]);
                // __NSStackBlock__调用copy : __NSMallocBlock__
                NSLog(@"%@ %@", [[block2 copy] class],[^{
                    NSLog(@"block2---------%d", a);
                } class]);
        
        //MRC 模式下
        // Global:没有访问auto变量:__NSGlobalBlock__
                void (^block4)(void) = ^{
                    NSLog(@"block4---------");
                };
                // Stack:访问了auto变量: __NSStackBlock__
                int a1 = 10;
                void (^block5)(void) = ^{
                    NSLog(@"block5---------%d", a1);
                };
                NSLog(@"MAC %@ %@", [block4 class], [block5 class]);
                // __NSStackBlock__调用copy : __NSMallocBlock__
                NSLog(@"%@ %@", [[block5 copy] class],[^{
                    NSLog(@"block2---------%d", a);
                } class]);
        
        /*
       2020-03-20 16:51:43.250229+0800 block解读[6703:829455] __NSGlobalBlock__ __NSMallocBlock__
2020-03-20 16:51:43.251585+0800 block解读[6703:829455] __NSMallocBlock__ __NSStackBlock__
         2020-03-20 16:34:07.418258+0800 block解读[6611:820683] mac __NSGlobalBlock__ __NSStackBlock__
         2020-03-20 16:34:07.418335+0800 block解读[6611:820683] __NSMallocBlock__ __NSStackBlock__
         */
  • NSGlobalBlock 全局block
  void (^myBlock) (void) = ^(void){
      
        NSLog(@"this is edison ");
    };
    //能用%@ 说明block是对象 可打印
    NSLog(@"%@",myBlock);
    /*
     <__NSGlobalBlock__: 0x10c36b088>
     */
  • NSMallocBlockblock
 int a = 9;
    void (^myBlock) (void) = ^(void){

        NSLog(@"this is edison %d",a);
    };
    NSLog(@"%@",myBlock);
    /*
     <<__NSMallocBlock__: 0x604000446390>
        一个栈的变量 进入block之后就变成了malloc block 
     */

一个栈的变量 进入block之后就变成了malloc block ????黑人问好??? 后面会解释

  • NSMallocBlockblock
NSLog(@"%@",^(void){
        
        //NSLog(@"this is edison %d",a);
        NSLog(@"this is edison ");
    });
    /*
     <__NSGlobalBlock__: 0x10a927080>

     引入a的是NSStackBlock 没有引入a的是NSGlobalBlock
     */

block的底层探讨

__block
image.png

如上图所示,当我们需要在block里引用局部变量(引用全局变量不会出现这样的错误),就会报错,当然我们都知道这种解决报错的方式就是使用__block修饰局部变量,但是为什么要这么解决呢

带着问题我们来探讨

首先用终端创建一个.c的文件

 touch blockTest.c
 vim blockTest.c

.c文件里写入如下代码,其实就是c语言的main

#include "stdio.h"

int main(){

void (^block)(void) = ^(void){

printf("this is edison block \n");
}

block();

return 0 ;
}

然后编译.c文件

gcc blockTest.c

就会产生一个 a.out 的可执行文件

image.png

继续执行这个 a.out 的可执行文件

./a.out blockTest.c
/*
结果:
this is edison block
*/

这个只是执行一下 a.out 的可执行文件

重点来了,我们继续
clang命令

clang  -rewrite-objc blockTest.c

结果就会产生一个blockTest.cpp
blockTest.c变成了blockTest.cppc++文件
,用c++的原理探讨block

打开blockTest.cpp文件,吓一跳讲真,我们拖到最底下,找到

int main(){

void (*block)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA));

((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);

return 0 ;
}

对比blockTest.c

int main(){

void (^block)(void) = ^(void){

printf("this is edison block \n");
}

block();

return 0 ;
}

现在改变.C

#include "stdio.h"
  
int main(){

int a = 0;
void (^block)(void) = ^(void){

printf("this is edison block %d\n",a);
};

block();

return 0 ;
}

blockTest.cpp

static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
  int a = __cself->a; // bound by copy


printf("this is edison block %d\n",a);
}

static struct __main_block_desc_0 {
  size_t reserved;
  size_t Block_size;
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};
int main(){

int a = 0;
void (*block)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, a));

((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);

return 0 ;
}

image.png

就是c文件的a是在栈里的没问题吧,block被拷贝进了堆了这个也没问题吧,blockTest.cpp文件这个如上图标示出来的这段代码

int a = __cself->a; // bound by copy  --> int a 表示重新定义了一个a 去接收传进来的__cself->a的值

这里传的是a的值
再先引进一个代码解释

 int a = 9;
    NSLog(@"a=%p",&a);
    void (^myBlock) (void) = ^(void){

        NSLog(@"this is edison %p",&a);
    };
    myBlock();
/*
2018-08-06 21:27:41.239550+0800 BlockTest[909:63152] a=0x7ffeed15bbdc
2018-08-06 21:27:41.239748+0800 BlockTest[909:63152] this is edison 0x604000253070
*/

你会发现外面的a和里面的a根本不是一个地址,说明两个a根本不一样

 __block int a = 9;//底层会做了把 栈/常量  等copy到堆区里去,并且开辟一个堆的空间 这里传的是a的指针地址
    NSLog(@"a=%p",&a);
    void (^myBlock) (void) = ^(void){

        NSLog(@"this is edison %p",&a);
    };
    myBlock();

__block修饰的传的是a的地址
所以如果a++这是可以的,因为a++其实修改的是地址++来达到修改外部变量的效果

循环引用

1

关于block里的属性,如果是带下划_name线操作的而不是self.name的操作一样会引起循环引用,因为selfname进行了强引用

2
__block ViewController * weSelf = self;
    self.block3 = ^(NSString *name) {
        NSLog(@"---%@",weSelf);
    };

这样能解决循环引用嘛。答案是不能
__block的作用是把当前的内存拷贝到堆里去,那么可以手动释放

__block ViewController * weSelf = self;
    self.block3 = ^(NSString *name) {
        NSLog(@"---%@",weSelf);
      weSelf= nil;
    };

这样就可以了 ,把指向的地址置空

3

在block的参数里把self传进去

self.block3 = ^(ViewController *vc) {
        NSLog(@"name=%@",vc.name);
    }
4

__weak __strong 先弱后强

__weak __typeof(self)weakSelf = self;
    AFNetworkReachabilityStatusBlock callback = ^(AFNetworkReachabilityStatus status) {
        __strong __typeof(weakSelf)strongSelf = weakSelf;

        strongSelf.networkReachabilityStatus = status;
        if (strongSelf.networkReachabilityStatusBlock) {
            strongSelf.networkReachabilityStatusBlock(status);
        }

    };

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,651评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,468评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,931评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,218评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,234评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,198评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,084评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,926评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,341评论 1 311
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,563评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,731评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,430评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,036评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,676评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,829评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,743评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,629评论 2 354

推荐阅读更多精彩内容