1:捕获

2:block类型

2.1:问题 :mrc环境下  下面讲的都是mrc环境下,会真实很多

2.2:在arc下,block 自动加上copy的情况---:返回block。

2.3:在arc下,block 自动加上copy的情况---:强指针__block;

2.4:arc环境下:方法名中有usingBlock的方法参数时,也会进行copy操作。

2.5:在arc下,block 自动加上copy的情况---:block作为GCD的方法参数。

3:对象类型的auto变量

3.1:假设在mrc环境下

3.2:arc:对上面做一个原因解释

4:如何修改block内部的变量:__block、static、全局、指针

4.1:__block的内存管理

4.2:__forwarding指针原理

4.3:问题:blok内部会对下面两个对象有什么不同么

4.4:被__block修饰的对象类型:arc环境下

5:循环引用

下面以一个简单的例子开始讲起

int main(int argc, char * argv[]) {@autoreleasepool {int age = 10;void (^ block)(void) = ^{
// age的值捕获进来,(capture)NSLog(@"block:%d",age);};age = 20;block();return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));}
}

通过 (这里解释一下,编译如果xcode路径出问题可能导致编译失败,结果办法点击)

xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m

把main.m -> main.cpp文件。

查看上面block的源码

int main(int argc, char * argv[]) {/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; int age = 10;void (* block)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, age));age = 20;((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);return UIApplicationMain(argc, argv, __null, NSStringFromClass(((Class (*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("AppDelegate"), sel_registerName("class"))));}
}

整理一下就是

int main(int argc, char * argv[]) {/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;int age = 10; // 自动变量auto,离开作用域便自动销毁 c语言特性// 定义block变量void (* block)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, age));// 上面相当于是void (* block)(void) = &__main_block_impl_0(__main_block_func_0,&__main_block_desc_0_DATA, age);age = 20;// 执行block内部的代码((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);// 上面相当于是:block->FuncPtr(block);return UIApplicationMain(argc, argv, __null, NSStringFromClass(((Class (*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("AppDelegate"), sel_registerName("class"))));}
}

__main_block_impl_0这个函数。


struct __main_block_impl_0 {struct __block_impl impl;struct __main_block_desc_0* Desc;int age;// 构造函数(类似oc的init方法),返回结构体对象 这个也就是block指向的 c++的特性 传进来的_age会自动赋值给age__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _age, int flags=0) : age(_age) {impl.isa = &_NSConcreteStackBlock;impl.Flags = flags;impl.FuncPtr = fp;Desc = desc;}
};
// 封装了block执行逻辑的函数:block里面的函数
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {int age = __cself->age; // bound by copy 取出block里面的ageNSLog((NSString *)&__NSConstantStringImpl__var_folders_27_tr3mg74j3nq_zxgdyg1rj6480000gn_T_main_ff1ca7_mi_0,age);}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)};struct __block_impl {void *isa;int Flags;int Reserved;void *FuncPtr;
};

1:捕获

捕获:block内部会专门新增一个成员来外面变量的值,这个操作称之为捕获。

auto只存在于局部变量里,不能存在于全局变量中,因为它出了作用域就会被销毁。值传递,相当于把10传递进去。(auto是自动销毁的,所以必须要传值。)

static,址传递。看下面

int main(int argc, char * argv[]) {@autoreleasepool {int age = 10;static int height = 10;void (^ block)(void) = ^{NSLog(@"block:%d  height:%d",age,height);};age = 20;height = 20;block();return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));}
}

所以上面的age捕获的是值,所以block内部的age跟外面的int age并不是一个,block里面的age是重新创建的,只是这里是把int age的值赋值给了block里面的age。只是因为这种情况下age无法在block里面进行赋值操作,所以age是不是改变的就不重要了但是也要注意,这种在block里面操作取值,长时间的操作,会有不准确性。(这种情况是局部变量age情况下)

上面的static height 跟block里面的*height是一个,因为__main_block_impl_0()这个函数传进去的是height指针,所以,这里block里面的*height修改了,同样外面的值也就修改了。

如果是全局变量


int age = 10;
static int height = 10;int main(int argc, char * argv[]) {@autoreleasepool {void (^ block)(void) = ^{NSLog(@"block:%d  height:%d",age,height);};age = 20;height = 20;block();return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));}
}

这个打印出来

2018-08-16 22:44:17.640 newxc[16609:5312874] block:20  height:20

源码

因为是全局变量,所以不论在哪里都能够访问,所以没有必要捕获。

(这种情况下,block内部的height和age,就是拿的全局变量的指针进行操作的,这本就是一个数据进行的操作。)

局部变量需要捕获,是因为局部变量的作用域只仅限在当前函数作用域,如果block函数和调用不在一个函数作用域,那么就会跨函数访问局部变量,所以需要捕获。

总结如下。

问:如果block内部调用self,会捕获么

#import "Person.h"@implementation Person- (void)test
{void (^ block)(void) = ^{NSLog(@"self:%p",self);};block();}
@end

答案会捕获。

因为test在c语言中的写法是

参数就是局部变量,所以会被捕获。

person的test的c语言函数就是下面这样,Person * self, SEL _cmd这两个参数是默认必传的参数。

static void _I_Person_test(Person * self, SEL _cmd) {void (* block)(void) = ((void (*)())&__Person__test_block_impl_0((void *)__Person__test_block_func_0, &__Person__test_block_desc_0_DATA, self, 570425344));((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);}// 看这里还有load方法
static void _C_Person_load(Class self, SEL _cmd) {}

看一下上面的源码

// 看这里,里面有一个Person *self 参数里的self就会自动赋值给*self。
struct __Person__test_block_impl_0 {struct __block_impl impl;struct __Person__test_block_desc_0* Desc;Person *self;__Person__test_block_impl_0(void *fp, struct __Person__test_block_desc_0 *desc, Person *_self, int flags=0) : self(_self) {impl.isa = &_NSConcreteStackBlock;impl.Flags = flags;impl.FuncPtr = fp;Desc = desc;}
};// 这里是block内部函数,在访问self。
static void __Person__test_block_func_0(struct __Person__test_block_impl_0 *__cself) {Person *self = __cself->self; // bound by copyNSLog((NSString *)&__NSConstantStringImpl__var_folders_27_tr3mg74j3nq_zxgdyg1rj6480000gn_T_Person_4d5a32_mi_0,self);}
static void __Person__test_block_copy_0(struct __Person__test_block_impl_0*dst, struct __Person__test_block_impl_0*src) {_Block_object_assign((void*)&dst->self, (void*)src->self, 3/*BLOCK_FIELD_IS_OBJECT*/);}static void __Person__test_block_dispose_0(struct __Person__test_block_impl_0*src) {_Block_object_dispose((void*)src->self, 3/*BLOCK_FIELD_IS_OBJECT*/);}static struct __Person__test_block_desc_0 {size_t reserved;size_t Block_size;void (*copy)(struct __Person__test_block_impl_0*, struct __Person__test_block_impl_0*);void (*dispose)(struct __Person__test_block_impl_0*);
} __Person__test_block_desc_0_DATA = { 0, sizeof(struct __Person__test_block_impl_0), __Person__test_block_copy_0, __Person__test_block_dispose_0};// 这里是test函数 __Person__test_block_impl_0这个函数传的值是self,上面是__Person__test_block_impl_0函数可以看到函数内部创建了一个person,来保存这个self指针。
static void _I_Person_test(Person * self, SEL _cmd) {void (* block)(void) = ((void (*)())&__Person__test_block_impl_0((void *)__Person__test_block_func_0, &__Person__test_block_desc_0_DATA, self, 570425344));// 调用block((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);}struct __block_impl {void *isa;int Flags;int Reserved;void *FuncPtr;
};

问题:如果是访问_name呢?


- (void)test
{void (^ block)(void) = ^{NSLog(@"self:%p",_name);};block();}

答案是会捕获,这个相当于是self->_age; 这个self是在block的局部的,这个捕获的是self,然后访问的self里面的_age成员变量。并不是单独对_age进行捕获,而是对self进行捕获。看源码

问题:如果是[self name];

这个也是捕获的,因为先要拿到self,才能发消息

这里需要知道一个问题:self 是局部变量,不是全局变量!!!!

2:block类型

从下面代码的isa可以看出block是有类型的

struct __Person__test_block_impl_0 {struct __block_impl impl;struct __Person__test_block_desc_0* Desc;Person *self;__Person__test_block_impl_0(void *fp, struct __Person__test_block_desc_0 *desc, Person *_self, int flags=0) : self(_self) {impl.isa = &_NSConcreteStackBlock; // block的类型impl.Flags = flags;impl.FuncPtr = fp;Desc = desc;}
};

block就是一个oc对象。我们可以通过[block class] 来查看一下它的类型。

我们来打印一下 这里是arc环境下的,跟mrc还是不一样的

int main(int argc, char * argv[]) {@autoreleasepool {void (^ block)(void) = ^{};block();NSLog(@"%@", [block class]);NSLog(@"%@", [[block class] superclass]);NSLog(@"%@", [[[block class] superclass] superclass]);NSLog(@"%@", [[[[block class] superclass] superclass] superclass]);return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));}
}

结果 :印证了 block是一个oc对象,isa本质上来说是从NSObject对象中来的。

// __NSGlobalBlock__ : __NSGlobalBlock : NSBlock : NSObject

2018-08-17 20:04:39.088 newxc[17439:5526253] __NSGlobalBlock__
2018-08-17 20:04:39.089 newxc[17439:5526253] __NSGlobalBlock
2018-08-17 20:04:39.090 newxc[17439:5526253] NSBlock
2018-08-17 20:04:39.090 newxc[17439:5526253] NSObject

block到底有哪几种呢 MRC环境下

        // Global:没有访问auto变量。包括static 都是globalvoid (^ block)(void) = ^{NSLog(@"self:");};// Stack:访问了auto变量。 :这个需要把arc关掉。int ne = 10;void (^ block1)(void) = ^{NSLog(@"self:%d",ne);};static int ne2 = 10;void (^ block2)(void) = ^{NSLog(@"self:%d",ne2);};static int ne3 = 10;void (^ block3)(void) = [^{NSLog(@"self:%d",ne3);} copy];int ne4 = 10;void (^ block4)(void) = [^{NSLog(@"self:%d",ne4);} copy];NSLog(@"block:%@  block1:%@ block2:%@ block3:%@ block4:%@  %@",[block class], [block1 class],[block2 class],[block3 class], [block4 class],[^{NSLog(@"%d",ne);} class]);block();
2018-08-17 20:12:12.046 newxc[17492:5539840] block:__NSGlobalBlock__  block1:__NSStackBlock__ block2:__NSGlobalBlock__ block3:__NSGlobalBlock__ block4:__NSMallocBlock__  __NSStackBlock__

但是通过编译到.cpp文件中查看跟上面的类型不一致。isa都是_NSConcreteStackBlock类型:需注意,以后会看到cpp文件中都是stack类型

struct __main_block_impl_0 {struct __block_impl impl;struct __main_block_desc_0* Desc;__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0) {impl.isa = &_NSConcreteStackBlock;impl.Flags = flags;impl.FuncPtr = fp;Desc = desc;}
};struct __main_block_impl_1 {struct __block_impl impl;struct __main_block_desc_1* Desc;int ne;__main_block_impl_1(void *fp, struct __main_block_desc_1 *desc, int _ne, int flags=0) : ne(_ne) {impl.isa = &_NSConcreteStackBlock;impl.Flags = flags;impl.FuncPtr = fp;Desc = desc;}
};struct __main_block_impl_2 {struct __block_impl impl;struct __main_block_desc_2* Desc;int ne;__main_block_impl_2(void *fp, struct __main_block_desc_2 *desc, int _ne, int flags=0) : ne(_ne) {impl.isa = &_NSConcreteStackBlock;impl.Flags = flags;impl.FuncPtr = fp;Desc = desc;}
};

上面只截取了部分 但是都是stack

不一致原因:

一切以运行时结果为准。

有时候通过clang 转成的c++代码,有时候并不是真正转成的c++代码。(苹果的llvm1.0不再是生成c++文件,而是生成中间代码,但是大致上相同,只有少数不同。llvm编译器的一部分就是clang,就是clang属于llvm编译器里面的一部分)从上到下是高地址到低地址。

2.1:问题 :mrc环境下  下面讲的都是mrc环境下,会真实很多

先看一下block的类型

看下面的问题

void (^block)(void);void test() {// stackint age = 10;block = ^ {NSLog(@"block------%d",age);};
}int main(int argc, char * argv[]) {@autoreleasepool {test();block();return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));}
}

显然:这个block的结果会有问题

2018-08-18 20:50:15.110 newxc[18572:6009580] block------272632489

那为什么会这样呢? 是因为这个block函数在栈上,block在全局变量区,但是这个block代码块内的所有包括这个age都是在栈上,栈有一个特点就是随时可能就会被释放,所以,这个打印的结果是不确定的。那如何解决呢?把这个block放在堆里。也即是把这个block变成malloc类型。调用copy。下面这个就是在堆上的就是block。

void test() {// stackint age = 10;block = [^{NSLog(@"block------%d",age);} copy];}

那如果是global类型调用copy呢 是什么类型呢

      block = [^{//NSLog(@"block------%d",age);} copy];block();NSLog(@"block:%@",[block class]);

答案还是global类型

2018-08-18 21:04:59.322 newxc[18618:6028439] block:__NSGlobalBlock__

那上面stack调用两次copy呢?(调用一次在堆上,再调用一次呢)

 block = [[^{NSLog(@"block------%d",age);} copy] copy];

答案还是malloc:也即是malloc调用copy还是在堆区,但是并不会再开辟内存了,而是引用计数器+1,但是这种的记住要自己管理内存。

2018-08-18 21:07:08.597 newxc[18641:6032580] block:__NSMallocBlock__

2.2:在arc下,block 自动加上copy的情况---:返回block。


typedef void (^block)(void);block test() {// stackint age = 19;return ^{NSLog(@"block------%d",age);};
}int main(int argc, char * argv[]) {@autoreleasepool {block bloc = test();bloc();return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));}
}

因为test函数内return的block是栈上的block,一旦函数作用域消失,那这个block就消失了,所以不是很妥当。如果是arc环境下,会自动给返回的这个block加了一个copy操作。在你函数作用域消失的时候,会自动给你加上release操作。

2.3:在arc下,block 自动加上copy的情况---:强指针__block;

在arc环境下,只要被强指针持有,就是malloc。就会自动给你这个block加copy。

        int age = 10;block bloccc = ^{NSLog(@"---%d",age);};NSLog(@"%@",[bloccc class]);
2018-08-19 17:10:03.248 newxc[19403:6283487] __NSMallocBlock__

但是在mrc环境下 就是

2018-08-19 17:12:09.420 newxc[19450:6287484] __NSStackBlock__

2.4:arc环境下:方法名中有usingBlock的方法参数时,也会进行copy操作。

NSArray *array = @[];[array enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {}];

有usingBlock 这个“^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { }”block也会搬到堆上面去。

2.5:在arc下,block 自动加上copy的情况---:block作为GCD的方法参数。

  static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{});

只要是CGD里面的block,“ ^{ }”这个block就会自动添加copy操作。

so:小总结

在mrc下一定要用copy,在arc下可以用strong也可以用copy,用strong是因为有强指针,就会被自动添加copy,但是为了项目在哪里都能用,所以建议用copy。

3:对象类型的auto变量

arc环境

int main(int argc, char * argv[]) {@autoreleasepool {Person *person = [[Person alloc] init];person.age = 10;block bloccc = ^{NSLog(@"---%d",person.age);};NSLog(@"-----=====");return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));}
}

源码是

struct __main_block_impl_0 {struct __block_impl impl;struct __main_block_desc_0* Desc;Person *person;__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, Person *_person, int flags=0) : person(_person) {impl.isa = &_NSConcreteStackBlock;impl.Flags = flags;impl.FuncPtr = fp;Desc = desc;}
};

这里是auto变量是什么捕捉的就是什么。如果是 static Person *person; 那么源码中捕捉到的就是Person **person.

因为整个block在堆上,而内部是对person的指针指引,所以只要block不释放,对person的指针就不会释放,person也就不会被释放。

3.1:假设在mrc环境下

typedef void (^block)(void);#import <Foundation/Foundation.h>
#import "Pepole.h"
int main(int argc, const char * argv[]) {@autoreleasepool {block blo;{Pepole *person = [[Pepole alloc] init];blo = [^{NSLog(@"block内部---%f",person.age);} copy];[person release];blo();}NSLog(@"栈%@----",[blo class]);}return 0;
}#import "Pepole.h"
@implementation Pepole- (void)dealloc
{[super dealloc];NSLog(@"person-dealloc----");
}
@end
2021-07-07 09:03:55.078425+0800 test[59310:7817290] block内部---0.000000
2021-07-07 09:03:55.079040+0800 test[59310:7817290] 栈__NSMallocBlock__----

block在堆上,pepole即使提前释放也无所谓,已经被block捕获到内部了。

但如果去掉copy,block在栈上,就会崩溃,因为没有强引用

假设在arc环境下----------这里2.1.1会做详细解释,从这里做案例开始.

nt main(int argc, char * argv[]) {@autoreleasepool {block blo;{Person *person = [[Person alloc] init];person.age = 10;blo = ^{NSLog(@"---%d",person.age);};}NSLog(@"========");}return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));}
2018-08-19 18:12:54.016 newxc[19963:6373020] ========
2018-08-19 18:12:54.017 newxc[19963:6373020] person-dealloc----

会先出了作用域,block释放,然后block对其person的指针也没了,所以person释放。

假设用__weak来修饰person实例

int main(int argc, char * argv[]) {@autoreleasepool {block blo;{Person *person = [[Person alloc] init];person.age = 10;__weak Person *wekaPerson = person;blo = ^{NSLog(@"---%d",wekaPerson.age);};}NSLog(@"========");}return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));}
2018-08-19 18:15:29.656 newxc[19986:6377817] person-dealloc----
2018-08-19 18:15:29.660 newxc[19986:6377817] ========

看结果不一样了,为啥呢,

3.2:arc:对上面做一个原因解释

弱引用:需要运行时的支持的。

            Person *person = [[Person alloc] init];person.age = 10;__weak Person *wekaPerson = person;blo = ^{NSLog(@"---%d",wekaPerson.age);};

你会发现,当你写了__weak,在去调用下面的命令时会报错

xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m
/var/folders/27/tr3mg74j3nq_zxgdyg1rj6480000gn/T/main-6a8820.mi:47464:28: error: cannot create __weak reference because the current deployment target doesnot support weak references__attribute__((objc_ownership(weak))) Person *wekaPerson = person;^
1 error generated.

你会发现上述报错,只是静态的编译会报错,所以需要我们指定是runtime并且指定arc环境。

xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc -fobjc-arc -fobjc-runtime=ios-8.0.0 main.m

发现,不一样的地方,就是person弱引用了

struct __main_block_impl_0 {struct __block_impl impl;struct __main_block_desc_0* Desc;Person *__weak wekaPerson;__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, Person *__weak _wekaPerson, int flags=0) : wekaPerson(_wekaPerson) {impl.isa = &_NSConcreteStackBlock;impl.Flags = flags;impl.FuncPtr = fp;Desc = desc;}
};

那如果是不加__weak呢 ,这里注意要接着用上面的指令编译,发现结果,是strong.

typedef void (*Block)(void);struct __main_block_impl_0 {struct __block_impl impl;struct __main_block_desc_0* Desc;Person *__strong per;  //注意这里,是strong类型,这是没有加__weak的情况,同样也没有加__strong__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, Person *__strong _per, int flags=0) : per(_per) {impl.isa = &_NSConcreteStackBlock;impl.Flags = flags;impl.FuncPtr = fp;Desc = desc;}
};

那如果是加了__strong的情况呢?接着使用上指令 结果可以看到依然是__strong修饰

          Block blo;{__strong Person *per = [[Person alloc] init];per.age = 100;blo = ^{NSLog(@"---%d",per.age);};};
struct __block_impl {void *isa;int Flags;int Reserved;void *FuncPtr;
};typedef void (*Block)(void);struct __main_block_impl_0 {struct __block_impl impl;struct __main_block_desc_0* Desc;Person *__strong per;  // 主要看这里,是用__strong来修饰的__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, Person *__strong _per, int flags=0) : per(_per) {impl.isa = &_NSConcreteStackBlock;impl.Flags = flags;impl.FuncPtr = fp;Desc = desc;}
};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {Person *__strong per = __cself->per; // bound by copyNSLog((NSString *)&__NSConstantStringImpl__var_folders_27_tr3mg74j3nq_zxgdyg1rj6480000gn_T_main_a9de8d_mi_0,((int (*)(id, SEL))(void *)objc_msgSend)((id)per, sel_registerName("age")));}
static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->per, (void*)src->per, 3/*BLOCK_FIELD_IS_OBJECT*/);}static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->per, 3/*BLOCK_FIELD_IS_OBJECT*/);}static struct __main_block_desc_0 {size_t reserved;size_t Block_size;void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*);void (*dispose)(struct __main_block_impl_0*);
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0), __main_block_copy_0, __main_block_dispose_0};

好总结一下,

static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->per, (void*)src->per, 3/*BLOCK_FIELD_IS_OBJECT*/);}static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->per, 3/*BLOCK_FIELD_IS_OBJECT*/);}

同样可以看到这个函数也有赋值

static struct __main_block_desc_0 {size_t reserved;size_t Block_size;void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*);void (*dispose)(struct __main_block_impl_0*);
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0), __main_block_copy_0, __main_block_dispose_0};

__main_block_copy_0赋值给copy函数,__main_block_dispose_0赋值给dispose函数。

也就是说,上面的blo一旦进行copy操作,要copy到堆上,就会自动调用copy函数,这个函数会调用里面的_Block_object_assign函数,这个函数做的事情是:会根据外部auto变量传进来的是strong还是weak,来对__main_block_impl_0里面的Person指针进行对外部的person对象是strong还是weak。如果是传进来的是strong,则__main_block_impl_0里面的person指针会强引用着外部的person对象,如果是weak也是一样。

那dispose什么时候调用呢? 当堆上的blo 进行销毁时,就会自动调用block内部的dispose,就会释放引用的那些函数

看总结图:

代码总结:

mrc:

1:全局

NSLog(@"全局%@----",[^(){NSLog(@"TestObj::");} class]);2021-04-12 15:35:34.323975+0800 COmitTest[18564:11421858] 全局__NSGlobalBlock__----
#pragma clang assume_nonnull endstruct __main_block_impl_0 {struct __block_impl impl;struct __main_block_desc_0* Desc;__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0) {impl.isa = &_NSConcreteStackBlock;impl.Flags = flags;impl.FuncPtr = fp;Desc = desc;}
};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
NSLog((NSString *)&__NSConstantStringImpl__var_folders_qv_pfhwg_1d2690c6px22m4vc540000gn_T_main_c6fac7_mi_1);}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 argc, const char * argv[]) {/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; NSLog((NSString *)&__NSConstantStringImpl__var_folders_qv_pfhwg_1d2690c6px22m4vc540000gn_T_main_c6fac7_mi_0,((Class (*)(id, SEL))(void *)objc_msgSend)((id)((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA)), sel_registerName("class")));}return 0;
}

2:栈 :auto类型

        int age = 0;NSLog(@"栈%@----",[^(){NSLog(@"TestObj::%d",age);} class]);
2021-04-12 15:40:18.743841+0800 COmitTest[18612:11424588] 栈__NSStackBlock__----
#pragma clang assume_nonnull end
struct __main_block_impl_0 {struct __block_impl impl;struct __main_block_desc_0* Desc;int age;__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _age, int flags=0) : age(_age) {impl.isa = &_NSConcreteStackBlock;impl.Flags = flags;impl.FuncPtr = fp;Desc = desc;}
};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {int age = __cself->age; // bound by copy
NSLog((NSString *)&__NSConstantStringImpl__var_folders_qv_pfhwg_1d2690c6px22m4vc540000gn_T_main_0f08b9_mi_1,age);}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 argc, const char * argv[]) {/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; int age = 0;NSLog((NSString *)&__NSConstantStringImpl__var_folders_qv_pfhwg_1d2690c6px22m4vc540000gn_T_main_0f08b9_mi_0,((Class (*)(id, SEL))(void *)objc_msgSend)((id)((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, age)), sel_registerName("class")));}return 0;
}

3:栈:对象类型 :没有强引用

Person *obj = [[Person alloc] init];
NSLog(@"栈%@----:%ld",[^(){NSLog(@"TestObj::%@",obj);} class],[obj arcDebugRetainCount]);
NSLog(@"栈---:%lu",(unsigned long)[obj arcDebugRetainCount]);
2021-04-12 15:43:03.388236+0800 COmitTest[18641:11426151] 栈__NSStackBlock__----:1
2021-04-12 16:25:20.396813+0800 COmitTest[19176:11453104] 栈---:1
#pragma clang assume_nonnull endstruct __main_block_impl_0 {struct __block_impl impl;struct __main_block_desc_0* Desc;Pepole *obj;__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, Pepole *_obj, int flags=0) : obj(_obj) {impl.isa = &_NSConcreteStackBlock;impl.Flags = flags;impl.FuncPtr = fp;Desc = desc;}
};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {Pepole *obj = __cself->obj; // bound by copy
NSLog((NSString *)&__NSConstantStringImpl__var_folders_qv_pfhwg_1d2690c6px22m4vc540000gn_T_main_bdf7b0_mi_1,obj);}
static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->obj, (void*)src->obj, 3/*BLOCK_FIELD_IS_OBJECT*/);}static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->obj, 3/*BLOCK_FIELD_IS_OBJECT*/);}static struct __main_block_desc_0 {size_t reserved;size_t Block_size;void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*);void (*dispose)(struct __main_block_impl_0*);
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0), __main_block_copy_0, __main_block_dispose_0};
int main(int argc, const char * argv[]) {/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; {Pepole *obj = ((Pepole *(*)(id, SEL))(void *)objc_msgSend)((id)((Pepole *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Pepole"), sel_registerName("alloc")), sel_registerName("init"));NSLog((NSString *)&__NSConstantStringImpl__var_folders_qv_pfhwg_1d2690c6px22m4vc540000gn_T_main_bdf7b0_mi_0,((Class (*)(id, SEL))(void *)objc_msgSend)((id)((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, obj, 570425344)), sel_registerName("class")),((NSInteger (*)(id, SEL))(void *)objc_msgSend)((id)obj, sel_registerName("retainCountjisuan")));NSLog((NSString *)&__NSConstantStringImpl__var_folders_qv_pfhwg_1d2690c6px22m4vc540000gn_T_main_bdf7b0_mi_2,(unsigned long)((NSInteger (*)(id, SEL))(void *)objc_msgSend)((id)obj, sel_registerName("retainCountjisuan")));}}return 0;
}
static struct IMAGE_INFO { unsigned version; unsigned flag; } _OBJC_IMAGE_INFO = { 0, 2 };

3:堆:对象类型 :引用计数+1

        Person *obj = [[Person alloc] init];NSLog(@"堆%@---:%ld",[[^(){NSLog(@"TestObj对象地址:%@",obj);} copy] class],[obj arcDebugRetainCount]);NSLog(@"堆---:%lu",(unsigned long)[obj arcDebugRetainCount]);2021-07-07 09:23:22.212923+0800 test[59563:7831976] 堆__NSMallocBlock__----:2
2021-07-07 09:23:22.213336+0800 test[59563:7831976] 堆---:2
#pragma clang assume_nonnull endstruct __main_block_impl_0 {struct __block_impl impl;struct __main_block_desc_0* Desc;Pepole *obj;__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, Pepole *_obj, int flags=0) : obj(_obj) {impl.isa = &_NSConcreteStackBlock;impl.Flags = flags;impl.FuncPtr = fp;Desc = desc;}
};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {Pepole *obj = __cself->obj; // bound by copy
NSLog((NSString *)&__NSConstantStringImpl__var_folders_qv_pfhwg_1d2690c6px22m4vc540000gn_T_main_8759ba_mi_1,obj);}
static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->obj, (void*)src->obj, 3/*BLOCK_FIELD_IS_OBJECT*/);}static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->obj, 3/*BLOCK_FIELD_IS_OBJECT*/);}static struct __main_block_desc_0 {size_t reserved;size_t Block_size;void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*);void (*dispose)(struct __main_block_impl_0*);
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0), __main_block_copy_0, __main_block_dispose_0};
int main(int argc, const char * argv[]) {/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; {Pepole *obj = ((Pepole *(*)(id, SEL))(void *)objc_msgSend)((id)((Pepole *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Pepole"), sel_registerName("alloc")), sel_registerName("init"));NSLog((NSString *)&__NSConstantStringImpl__var_folders_qv_pfhwg_1d2690c6px22m4vc540000gn_T_main_8759ba_mi_0,((Class (*)(id, SEL))(void *)objc_msgSend)((id)((id (*)(id, SEL))(void *)objc_msgSend)((id)((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, obj, 570425344)), sel_registerName("copy")), sel_registerName("class")),((NSInteger (*)(id, SEL))(void *)objc_msgSend)((id)obj, sel_registerName("retainCountjisuan")));NSLog((NSString *)&__NSConstantStringImpl__var_folders_qv_pfhwg_1d2690c6px22m4vc540000gn_T_main_8759ba_mi_2,(unsigned long)((NSInteger (*)(id, SEL))(void *)objc_msgSend)((id)obj, sel_registerName("retainCountjisuan")));}}return 0;
}
static struct IMAGE_INFO { unsigned version; unsigned flag; } _OBJC_IMAGE_INFO = { 0, 2 };

4:栈:对象类型__block :引用计数没有增加

            Pepole *obj = [[Pepole alloc] init];__block Pepole *obg = obj;NSLog(@"栈%@----:%ld",[^(){NSLog(@"TestObj::%@",obg);} class],[obg retainCountjisuan]);NSLog(@"栈---:%lu",(unsigned long)[obg retainCountjisuan]);2021-07-07 09:24:57.269143+0800 test[59588:7833235] 栈__NSStackBlock__----:1
2021-07-07 09:24:57.269546+0800 test[59588:7833235] 栈---:1
#pragma clang assume_nonnull end
struct __Block_byref_obg_0 {void *__isa;
__Block_byref_obg_0 *__forwarding;int __flags;int __size;void (*__Block_byref_id_object_copy)(void*, void*);void (*__Block_byref_id_object_dispose)(void*);Pepole *obg;
};struct __main_block_impl_0 {struct __block_impl impl;struct __main_block_desc_0* Desc;__Block_byref_obg_0 *obg; // by ref__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_obg_0 *_obg, int flags=0) : obg(_obg->__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_obg_0 *obg = __cself->obg; // bound by ref
NSLog((NSString *)&__NSConstantStringImpl__var_folders_qv_pfhwg_1d2690c6px22m4vc540000gn_T_main_cfb8db_mi_1,(obg->__forwarding->obg));}
static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->obg, (void*)src->obg, 8/*BLOCK_FIELD_IS_BYREF*/);}static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->obg, 8/*BLOCK_FIELD_IS_BYREF*/);}static struct __main_block_desc_0 {size_t reserved;size_t Block_size;void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*);void (*dispose)(struct __main_block_impl_0*);
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0), __main_block_copy_0, __main_block_dispose_0};
int main(int argc, const char * argv[]) {/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; {Pepole *obj = ((Pepole *(*)(id, SEL))(void *)objc_msgSend)((id)((Pepole *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Pepole"), sel_registerName("alloc")), sel_registerName("init"));__attribute__((__blocks__(byref))) __Block_byref_obg_0 obg = {(void*)0,(__Block_byref_obg_0 *)&obg, 33554432, sizeof(__Block_byref_obg_0), __Block_byref_id_object_copy_131, __Block_byref_id_object_dispose_131, obj};NSLog((NSString *)&__NSConstantStringImpl__var_folders_qv_pfhwg_1d2690c6px22m4vc540000gn_T_main_cfb8db_mi_0,((Class (*)(id, SEL))(void *)objc_msgSend)((id)((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, (__Block_byref_obg_0 *)&obg, 570425344)), sel_registerName("class")),((NSInteger (*)(id, SEL))(void *)objc_msgSend)((id)(obg.__forwarding->obg), sel_registerName("retainCountjisuan")));NSLog((NSString *)&__NSConstantStringImpl__var_folders_qv_pfhwg_1d2690c6px22m4vc540000gn_T_main_cfb8db_mi_2,(unsigned long)((NSInteger (*)(id, SEL))(void *)objc_msgSend)((id)(obg.__forwarding->obg), sel_registerName("retainCountjisuan")));}}return 0;
}
static struct IMAGE_INFO { unsigned version; unsigned flag; } _OBJC_IMAGE_INFO = { 0, 2 };

4:堆:对象类型__block :没有+1

            Pepole *obj = [[Pepole alloc] init];__block Pepole *obg = obj;NSLog(@"栈%@----:%ld",[[^(){NSLog(@"TestObj::%@",obg);} copy] class],[obg retainCountjisuan]);NSLog(@"栈---:%lu",(unsigned long)[obg retainCountjisuan]);NSLog(@"堆---:%lu",(unsigned long)[obj arcDebugRetainCount]);
2021-07-07 09:26:46.227738+0800 test[59609:7834687] 堆__NSMallocBlock__----:1
2021-07-07 09:26:46.228127+0800 test[59609:7834687] 堆---:1
#pragma clang assume_nonnull end
struct __Block_byref_obg_0 {void *__isa;
__Block_byref_obg_0 *__forwarding;int __flags;int __size;void (*__Block_byref_id_object_copy)(void*, void*);void (*__Block_byref_id_object_dispose)(void*);Pepole *obg;
};struct __main_block_impl_0 {struct __block_impl impl;struct __main_block_desc_0* Desc;__Block_byref_obg_0 *obg; // by ref__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_obg_0 *_obg, int flags=0) : obg(_obg->__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_obg_0 *obg = __cself->obg; // bound by ref
NSLog((NSString *)&__NSConstantStringImpl__var_folders_qv_pfhwg_1d2690c6px22m4vc540000gn_T_main_cc3361_mi_1,(obg->__forwarding->obg));}
static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->obg, (void*)src->obg, 8/*BLOCK_FIELD_IS_BYREF*/);}static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->obg, 8/*BLOCK_FIELD_IS_BYREF*/);}static struct __main_block_desc_0 {size_t reserved;size_t Block_size;void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*);void (*dispose)(struct __main_block_impl_0*);
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0), __main_block_copy_0, __main_block_dispose_0};
int main(int argc, const char * argv[]) {/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; {Pepole *obj = ((Pepole *(*)(id, SEL))(void *)objc_msgSend)((id)((Pepole *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Pepole"), sel_registerName("alloc")), sel_registerName("init"));__attribute__((__blocks__(byref))) __Block_byref_obg_0 obg = {(void*)0,(__Block_byref_obg_0 *)&obg, 33554432, sizeof(__Block_byref_obg_0), __Block_byref_id_object_copy_131, __Block_byref_id_object_dispose_131, obj};NSLog((NSString *)&__NSConstantStringImpl__var_folders_qv_pfhwg_1d2690c6px22m4vc540000gn_T_main_cc3361_mi_0,((Class (*)(id, SEL))(void *)objc_msgSend)((id)((id (*)(id, SEL))(void *)objc_msgSend)((id)((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, (__Block_byref_obg_0 *)&obg, 570425344)), sel_registerName("copy")), sel_registerName("class")),((NSInteger (*)(id, SEL))(void *)objc_msgSend)((id)(obg.__forwarding->obg), sel_registerName("retainCountjisuan")));NSLog((NSString *)&__NSConstantStringImpl__var_folders_qv_pfhwg_1d2690c6px22m4vc540000gn_T_main_cc3361_mi_2,(unsigned long)((NSInteger (*)(id, SEL))(void *)objc_msgSend)((id)(obg.__forwarding->obg), sel_registerName("retainCountjisuan")));}}return 0;
}
static struct IMAGE_INFO { unsigned version; unsigned flag; } _OBJC_IMAGE_INFO = { 0, 2 };

5:堆:对象类型__weak :引用计数不加,在block内部+1,出了作用域-1 在arc环境下的,这个在mrc环境下测的有误

Person *obj = [[Person alloc] init];
__weak Person *oongg = obj;
NSLog(@"堆%@---:%ld",[[^(){NSLog(@"TestObj对象地址:%@",oongg);} copy] class],[oongg arcDebugRetainCount]);
NSLog(@"堆---:%lu",(unsigned long)[obj arcDebugRetainCount]);2021-04-12 15:56:54.278349+0800 COmitTest[18819:11436001] 堆__NSMallocBlock__---:2
2021-04-12 16:29:58.469736+0800 COmitTest[19286:11456782] 堆---:1
#pragma clang assume_nonnull end
struct __main_block_impl_0 {struct __block_impl impl;struct __main_block_desc_0* Desc;Person *__weak oongg;__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, Person *__weak _oongg, int flags=0) : oongg(_oongg) {impl.isa = &_NSConcreteStackBlock;impl.Flags = flags;impl.FuncPtr = fp;Desc = desc;}
};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {Person *__weak oongg = __cself->oongg; // bound by copy
NSLog((NSString *)&__NSConstantStringImpl__var_folders_qv_pfhwg_1d2690c6px22m4vc540000gn_T_main_185e12_mi_1,oongg);}
static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->oongg, (void*)src->oongg, 3/*BLOCK_FIELD_IS_OBJECT*/);}static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->oongg, 3/*BLOCK_FIELD_IS_OBJECT*/);}static struct __main_block_desc_0 {size_t reserved;size_t Block_size;void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*);void (*dispose)(struct __main_block_impl_0*);
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0), __main_block_copy_0, __main_block_dispose_0};
int main(int argc, const char * argv[]) {/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; Person *obj = ((Person *(*)(id, SEL))(void *)objc_msgSend)((id)((Person *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Person"), sel_registerName("alloc")), sel_registerName("init"));__attribute__((objc_ownership(weak))) Person *oongg = obj;NSLog((NSString *)&__NSConstantStringImpl__var_folders_qv_pfhwg_1d2690c6px22m4vc540000gn_T_main_185e12_mi_0,((Class (*)(id, SEL))(void *)objc_msgSend)((id)((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, oongg, 570425344)), sel_registerName("class")),((NSUInteger (*)(id, SEL))(void *)objc_msgSend)((id)oongg, sel_registerName("arcDebugRetainCount")));}return 0;
}

上方总结

位置 变量

引用计数

(强引用)

mrc下

是否捕获变量

引用计数

dispose和copy

包装捕获变量

内置dispose

和copy,共2份

全局 × × × × ×
auto × × × ×
auto × ✔️ × ×
对象 +0 ✔️ ✔️ ×
对象 +1 ✔️ ✔️ ×
__block auto × ✔️ ✔️ ×
__block 对象 +0 ✔️包装的对象 ✔️ ✔️
__block 对象 +0 ✔️包装的对象 ✔️ ✔️
__weak 对象

arc下

+1 出了

作用域就-1

✔️ ✔️ ×

这里捕获变量 是什么就捕获的什么,例如单个对象,就捕获的是对象,也就是对象的指针

一旦block内部访问的是对象类型的,就会出现copy和dispose函数,因为访问的是对象,想拥有这个对象,所以就会有内存对象管理。

看题

苹果会认为block内部有强引用的时候,不会释放,等到强引用释放完了才会释放。弱引用没有影响。

4:如何修改block内部的变量:__block、static、全局、指针

如果我们想对block里面的变量进行修改,怎么做?

a:static

b:弄成全局变量

c:用__block.

d:数据类型用指针指向(参考static使用的block内部原理)

1:先看d也就是static使用的block的内部原理

typedef void(^Block)(void);int main(int argc, const char * argv[]) {@autoreleasepool {static int height = 10;Block bl = ^{height = 199;};bl();}return 0;
}
typedef void(*Block)(void);struct __main_block_impl_0 {struct __block_impl impl;struct __main_block_desc_0* Desc;int *height;__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int *_height, int *__newhei, int flags=0) : height(_height){impl.isa = &_NSConcreteStackBlock;impl.Flags = flags;impl.FuncPtr = fp;Desc = desc;}};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {int *height = __cself->height; // bound by copy(*height) = 199;}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 argc, const char * argv[]) {static int height = 10;Block bl = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, &height));((void (*)(__block_impl *))((__block_impl *)bl)->FuncPtr)((__block_impl *)bl);}return 0;
}

从上面可以看出来 传进去的是height的指针,从__main_block_impl_0对象结构体中也可以知道,是拿int *height;来接收的,在__main_block_func_0函数中可以看到赋值时候用的是int *_newhei = __cself->_newhei;   *_newhei = 20; .所以我们可以这么做

typedef void(^Block)(void);
int main(int argc, const char * argv[]) {@autoreleasepool {int age = 10;int *_hei = &age;int *_newhei = _hei;*_newhei = 304;Block bl = ^{*_newhei = 20;};bl();NSLog(@"在这里打印的话会发现age已经变为20 了 并且*_newhei 也是20")}return 0;}

当然 这种方式是麻烦了点,而且只针对基本数据类型,对于对象类型不适用。那为什么不适用呢,请看下面

        Person *per = [[Person alloc] init];static int lage = 100;Block bl = ^{lage = 300;NSLog(@"%@",per.name);};bl();

这个底层源码是 我们只看这一段

static void __main_block_func_0(struct __main_block_impl_0 *__cself) {int *lage = __cself->lage; // bound by copyPerson *per = __cself->per; // bound by copy(*lage) = 300;NSLog((NSString *)&__NSConstantStringImpl__var_folders_70_0rj_h7dx3zv20xx9ln3x0d8h0000gn_T_main_3efd6b_mi_0,((NSString *(*)(id, SEL))(void *)objc_msgSend)((id)per, sel_registerName("name")));}

注意到,对于基本数据类型,这里取值都用的是*lage 而不是lage,也就是这是取值,并不是取的指针。

但是对于对象来说,取的是per,也就是(id)per,而不是*per,(这个*per在oc中也不代表什么)。所以对于oc对象来说,同样跟c语言一样有指针,但是方式却不一样。 所以oc对象来说 应该方式都是这样的下面包装一层的方式

2:看一个例子 用__block

typedef void (^Block)(void);
int main(int argc, char * argv[]) {@autoreleasepool {__block int age = 10;Block blo = ^{NSLog(@"---%d",age);};}return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));}
struct __block_impl {void *isa;int Flags;int Reserved;void *FuncPtr;
};typedef void (*Block)(void);struct __Block_byref_age_0 {void *__isa;
__Block_byref_age_0 *__forwarding; // 看下面的引用知道,这个指向自己int __flags;int __size;int age;
};struct __main_block_impl_0 {struct __block_impl impl;struct __main_block_desc_0* Desc;__Block_byref_age_0 *age; // by ref__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_age_0 *_age, int flags=0) : age(_age->__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_age_0 *age = __cself->age; // bound by ref(age->__forwarding->age) = 20;NSLog((NSString *)&__NSConstantStringImpl__var_folders_27_tr3mg74j3nq_zxgdyg1rj6480000gn_T_main_0dc06e_mi_0,(age->__forwarding->age));}
// 要对__main_block_impl_0对象进行内存管理,所有有copy和dispose
static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->age, (void*)src->age, 8/*BLOCK_FIELD_IS_BYREF*/);}static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->age, 8/*BLOCK_FIELD_IS_BYREF*/);}static struct __main_block_desc_0 {size_t reserved;size_t Block_size;void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*);void (*dispose)(struct __main_block_impl_0*);
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0), __main_block_copy_0, __main_block_dispose_0};
int main(int argc, char * argv[]) {/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; // 这里是 __block int age = 10; 是下面的这个__attribute__((__blocks__(byref))) __Block_byref_age_0 age = {
(void*)0,
(__Block_byref_age_0 *)&age,
0,
sizeof(__Block_byref_age_0),
10
};Block blo = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, (__Block_byref_age_0 *)&age, 570425344));}return UIApplicationMain(argc, argv, __null, NSStringFromClass(((Class (*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("AppDelegate"), sel_registerName("class"))));}
static struct IMAGE_INFO { unsigned version; unsigned flag; } _OBJC_IMAGE_INFO = { 0, 2 };

// 要对__Block_byref_age_0对象进行内存管理,所以有copy和dispose

看这个结构体 这个是调用age,能看出来第二个(__Block_byref_age_0 *)&age赋值给了__Block_byref_age_0结构体的forwarding指针,也就是把自己的地址赋值给了自己结构体中的forwarding。

__attribute__((__blocks__(byref))) __Block_byref_age_0 age = {(void*)0,(__Block_byref_age_0 *)&age, 0, sizeof(__Block_byref_age_0),10};  
struct __Block_byref_age_0 {void *__isa;
__Block_byref_age_0 *__forwarding;int __flags;int __size;int age;
};

接着看这个,看blo这个结构体把age的地址:&age 传进去了,赋值给了第三个 __Block_byref_age_0 *age; // by ref

Block blo = (
(void (*)())&__main_block_impl_0((void *)__main_block_func_0,
&__main_block_desc_0_DATA,
(__Block_byref_age_0 *)&age,
570425344));
struct __main_block_impl_0 {struct __block_impl impl;struct __main_block_desc_0* Desc;__Block_byref_age_0 *age; // by ref__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_age_0 *_age, int flags=0) : age(_age->__forwarding) {impl.isa = &_NSConcreteStackBlock;impl.Flags = flags;impl.FuncPtr = fp;Desc = desc;}
};

所以,block内部会有一个指针(这里是*age)指向__Block_byref_age_0结构体,这个结构体内部又有age这个值,存储这个值,那是如何修改这个值的呢?

static void __main_block_func_0(struct __main_block_impl_0 *__cself) {__Block_byref_age_0 *age = __cself->age; // bound by ref(age->__forwarding->age) = 20;NSLog((NSString *)&__NSConstantStringImpl__var_folders_27_tr3mg74j3nq_zxgdyg1rj6480000gn_T_main_acce32_mi_0,(age->__forwarding->age));}

看这个__cself从__main_block_impl_0这个结构体中拿到age也就是__Block_byref_age_0结构体,然后用这个结构体先访问自己内部的forwarding,因为forwarding指向的就是自己,所以再拿age,再赋值,就赋值成功啦。那到此肯定有疑问,这个改变的不就是block内部的age这个值么,而且这个age是在内部创建的,验证。打印一下

   __block int age = 10;Block blo = ^{age = 20;NSLog(@"---%d",age);};blo();NSLog(@"外面:%d",age);
2018-09-07 22:01:44.772 newxc[31713:10543714] ---20
2018-09-07 22:02:16.602 newxc[31713:10543714] 外面:20

那是为啥呢?看这个,不加block,只用__block修饰,再看源码

int main(int argc, char * argv[]) {@autoreleasepool {__block int age = 10;NSLog(@"外面:%d",age);}return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
struct __Block_byref_age_0 {void *__isa;
__Block_byref_age_0 *__forwarding;int __flags;int __size;int age;
};
int main(int argc, char * argv[]) {/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; __attribute__((__blocks__(byref))) __Block_byref_age_0 age = {(void*)0,(__Block_byref_age_0 *)&age, 0, sizeof(__Block_byref_age_0), 10};NSLog((NSString *)&__NSConstantStringImpl__var_folders_27_tr3mg74j3nq_zxgdyg1rj6480000gn_T_main_80e809_mi_0,(age.__forwarding->age));}return UIApplicationMain(argc, argv, __null, NSStringFromClass(((Class (*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("AppDelegate"), sel_registerName("class"))));}

请看,有__Block_byref_age_0结构体,就是说只要加上__block,就会被包装秤这个对象结构体.在nslog中访问的就是__Block_byref_age_0结构体中的age,所以是能修改的,这个原来船进入的是10,并不是10的地址,而是这个结构体中的age是新生成的age变量,这只是造成了一个假象,显示这个age被修改了,其实是修改的这个__Block_byref_age_0结构体对象里面的age变量,验证如下 (就如同,外面是一个person变量,有一个age的属性,在block内部给age赋值,是修改成功的)。

当使用了__block之后,age的地址就发生了变化,这里因为arc环境下,block已经copy到堆上,但是原来__block修饰的age的那个对象还在栈上,而最后age= 20,这个age,是访问的堆上的age,(因为已经从栈到堆了。)

总结

那如果再加上一个person对象呢用__block修饰?

typedef void(^Block)(void);int main(int argc, const char * argv[]) {@autoreleasepool {__block Person *per = [[Person alloc] init];__block int age = 10;Block bl = ^{NSString *a =  per.name;per.name = @"34";age = 300;};bl();}return 0;
}
struct __block_impl {void *isa;int Flags;int Reserved;void *FuncPtr;
};typedef void(*Block)(void);struct __Block_byref_per_0 {void *__isa;
__Block_byref_per_0 *__forwarding;int __flags;int __size;void (*__Block_byref_id_object_copy)(void*, void*);void (*__Block_byref_id_object_dispose)(void*);Person *per;
};
struct __Block_byref_age_1 {void *__isa;
__Block_byref_age_1 *__forwarding;int __flags;int __size;int age;
};struct __main_block_impl_0 {struct __block_impl impl;struct __main_block_desc_0* Desc;__Block_byref_per_0 *per; // by ref__Block_byref_age_1 *age; // by ref__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_per_0 *_per, __Block_byref_age_1 *_age, int flags=0) : per(_per->__forwarding), age(_age->__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_per_0 *per = __cself->per; // bound by ref__Block_byref_age_1 *age = __cself->age; // bound by refNSString *a = ((NSString *(*)(id, SEL))(void *)objc_msgSend)((id)(per->__forwarding->per), sel_registerName("name"));((void (*)(id, SEL, NSString *))(void *)objc_msgSend)((id)(per->__forwarding->per), sel_registerName("setName:"), (NSString *)&__NSConstantStringImpl__var_folders_70_0rj_h7dx3zv20xx9ln3x0d8h0000gn_T_main_b0ec3f_mi_0);(age->__forwarding->age) = 300;}
static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->per, (void*)src->per, 8/*BLOCK_FIELD_IS_BYREF*/);_Block_object_assign((void*)&dst->age, (void*)src->age, 8/*BLOCK_FIELD_IS_BYREF*/);}static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->per, 8/*BLOCK_FIELD_IS_BYREF*/);_Block_object_dispose((void*)src->age, 8/*BLOCK_FIELD_IS_BYREF*/);}static struct __main_block_desc_0 {size_t reserved;size_t Block_size;void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*);void (*dispose)(struct __main_block_impl_0*);
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0), __main_block_copy_0, __main_block_dispose_0};
int main(int argc, const char * argv[]) {/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; __attribute__((__blocks__(byref))) __Block_byref_per_0 per = {(void*)0,(__Block_byref_per_0 *)&per, 33554432, sizeof(__Block_byref_per_0), __Block_byref_id_object_copy_131, __Block_byref_id_object_dispose_131, ((Person *(*)(id, SEL))(void *)objc_msgSend)((id)((Person *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Person"), sel_registerName("alloc")), sel_registerName("init"))};__attribute__((__blocks__(byref))) __Block_byref_age_1 age = {(void*)0,(__Block_byref_age_1 *)&age, 0, sizeof(__Block_byref_age_1), 10};Block bl = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, (__Block_byref_per_0 *)&per, (__Block_byref_age_1 *)&age, 570425344));((void (*)(__block_impl *))((__block_impl *)bl)->FuncPtr)((__block_impl *)bl);}return 0;
}
static struct IMAGE_INFO { unsigned version; unsigned flag; } _OBJC_IMAGE_INFO = { 0, 2 };

看上面就会生成两个__main_block_impl_结构体,并且最后nslog里,访问的也是__main_block_impl_结构体里面的forwarding里的per或者age。

4.1:__block的内存管理

(如果是对象修饰用__block的话,记住两个copy是不同的,__main_block_copy_0和__Block_byref_id_object_copy。作用对象也不同)

强引用__Block_byref_age_0 *age; 对象,对这个强引用(copy)

销毁对__Block_byref_age_0 *age;对象进行release。

(这个内存管理对没有修饰的对象类型的copy是一样的,如果加上了__block, 那么就是再加上一层内存管理,也就是__block变量内部对对象类型的内存管理。)

4.2:__forwarding指针原理

那上面间接的可以解释为什么有__forwarding指针,而不是age直接指向age

(age->__forwarding->age) = 20;

因为这个__Block_byref_age_0对象刚开始都是在栈上,当block被copy到堆上的时候,自动也就copy了一份__Block_byref_age_0对象,这个时候,第一个age是栈上的,而它的__forwarding指针是指向堆上的它自己,所以需要用__forwarding的age来取值或者赋值,但是如果block是在栈上,那么这些都不会被copy到堆上,所以__forwarding还是指向自己,所以,这不论是在栈还是再堆都实现了指向自己,所以可以赋值或者取值。(copy到堆上了,地址肯定就发生变化了。)

4.3:问题:blok内部会对下面两个对象有什么不同么

Person *per = [[Person alloc] init];__block int age = 10;

不同点在这里

static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {
_Block_object_assign((void*)&dst->age, (void*)src->age, 8/*BLOCK_FIELD_IS_BYREF*/);
_Block_object_assign((void*)&dst->per, (void*)src->per, 3/*BLOCK_FIELD_IS_OBJECT*/);}

一旦用__block,这个assign函数就会对这个对象产生强引用,而没有用__block的对象,会根据是strong还是weak来修饰的,再对它产生强或者弱引用。

那相同点是什么呢?

4.4:被__block修饰的对象类型:arc环境下

这里着重看一下下面两个

        __block  Person *weakPerson = per;__block  __weak Person *weakPerson = per;

这两个在代码上有需要注意的地方,先看下__block  Person *weakPerson = per;的源码

typedef void (^Block)(void);int main(int argc, char * argv[]) {@autoreleasepool {Person *per = [[Person alloc] init];__block  Person *weakPerson = per;Block blok = ^{weakPerson.age = 20;};blok();}return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));}

struct __block_impl {void *isa;int Flags;int Reserved;void *FuncPtr;
};#define __OFFSETOFIVAR__(TYPE, MEMBER) ((long long) &((TYPE *)0)->MEMBER)
static void __Block_byref_id_object_copy_131(void *dst, void *src) {_Block_object_assign((char*)dst + 40, *(void * *) ((char*)src + 40), 131);
}   // 看这里assign 对 person这个对象进行copy,也就是进行131,根据外面传进来的操作。static void __Block_byref_id_object_dispose_131(void *src) {_Block_object_dispose(*(void * *) ((char*)src + 40), 131);
}typedef void (*Block)(void);struct __Block_byref_weakPerson_0 {void *__isa;
__Block_byref_weakPerson_0 *__forwarding;int __flags;int __size;void (*__Block_byref_id_object_copy)(void*, void*);void (*__Block_byref_id_object_dispose)(void*);Person *__strong weakPerson;
};struct __main_block_impl_0 {struct __block_impl impl;struct __main_block_desc_0* Desc;__Block_byref_weakPerson_0 *weakPerson; // by ref__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_weakPerson_0 *_weakPerson, int flags=0) : weakPerson(_weakPerson->__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_weakPerson_0 *weakPerson = __cself->weakPerson; // bound by ref((void (*)(id, SEL, int))(void *)objc_msgSend)((id)(weakPerson->__forwarding->weakPerson), sel_registerName("setAge:"), 20);}
static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->weakPerson, (void*)src->weakPerson, 8/*BLOCK_FIELD_IS_BYREF*/);}static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->weakPerson, 8/*BLOCK_FIELD_IS_BYREF*/);}static struct __main_block_desc_0 {size_t reserved;size_t Block_size;void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*);void (*dispose)(struct __main_block_impl_0*);
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0), __main_block_copy_0, __main_block_dispose_0};
int main(int argc, char * argv[]) {/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; Person *per = ((Person *(*)(id, SEL))(void *)objc_msgSend)((id)((Person *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Person"), sel_registerName("alloc")), sel_registerName("init"));__attribute__((__blocks__(byref))) __Block_byref_weakPerson_0 weakPerson = {
(void*)0,
(__Block_byref_weakPerson_0 *)&weakPerson,
33554432,
sizeof(__Block_byref_weakPerson_0),
__Block_byref_id_object_copy_131,
__Block_byref_id_object_dispose_131,
per};   // 这里的封装好的weakPerson放在下面里面.Block blok = (
(void (*)())&__main_block_impl_0((void *)__main_block_func_0,
&__main_block_desc_0_DATA,
(__Block_byref_weakPerson_0 *)&weakPerson,
570425344));((void (*)(__block_impl *))((__block_impl *)blok)->FuncPtr)((__block_impl *)blok);}return UIApplicationMain(argc, argv, __null, NSStringFromClass(((Class (*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("AppDelegate"), sel_registerName("class"))));}

看这个用__block修饰的对象跟__block修饰的普通数据类型不一样的地方,在__Block_byref_weakPerson_0对象里多了两个参数, void (*__Block_byref_id_object_copy)(void*, void*);和 void (*__Block_byref_id_object_dispose)(void*);那这两个的作用是什么呢?就是管理__Block_byref_per_0中_Person *__strong weakPerson;的内存的,也就是是对象就需要的内存管理。

接着分析这个过程,刚开始把weakPerson封装好给blok赋值,从__Block_byref_weakPerson_0结构中可以看到,赋值的内容:isa是指针,

__forwarding是赋值的地址&weakPerson,

__flags赋值的是33554432,

__size赋值的是sizeof(__Block_byref_weakPerson_0),

__Block_byref_id_object_copy赋值的是 __Block_byref_id_object_copy_131,

__Block_byref_id_object_dispose赋值的是__Block_byref_id_object_dispose_131,

Person *__strong weakPerson;赋值的是per。

所以__forwarding指向的就是自己。而__Block_byref_id_object_copy_131看这个函数内是这个_Block_object_assign((char*)dst + 40, *(void * *) ((char*)src + 40), 131); 这个是这个结构体指针的地址加40,也就是__Block_byref_weakPerson_0的地址加40 就是 Person *__strong weakPerson;,对它进行的copy和dispose操作。

所以 过程是:

当block被copy到堆上的时候,(arc环境下),block会调用__main_block_copy_0函数,来对__main_block_impl_0对象内部的 __Block_byref_weakPerson_0 *weakPerson;进行copy,进行强指针引用。同时__Block_byref_weakPerson_0对象也被拷贝到堆上,在这个copy的时候,__Block_byref_weakPerson_0对象就会调用自己内部的__Block_byref_id_object_copy对自己内部的对象 Person *__strong weakPerson进行copy;根据前面的修饰符进行强引用还是弱引用,这里因为是strong,所以是强引用。同时注意一下,如果是mrc环境下,那么这个对person的引用就永远不会是强引用。

好下面看

typedef void (^Block)(void);int main(int argc, char * argv[]) {@autoreleasepool {Person *per = [[Person alloc] init];__block __weak Person *weakPerson = per;Block blok = ^{weakPerson.age = 20;};blok();}return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));}
struct __block_impl {void *isa;int Flags;int Reserved;void *FuncPtr;
};typedef void (*Block)(void);struct __Block_byref_weakPerson_0 {void *__isa;
__Block_byref_weakPerson_0 *__forwarding;int __flags;int __size;void (*__Block_byref_id_object_copy)(void*, void*);void (*__Block_byref_id_object_dispose)(void*);Person *__weak weakPerson;
};struct __main_block_impl_0 {struct __block_impl impl;struct __main_block_desc_0* Desc;__Block_byref_weakPerson_0 *weakPerson; // by ref__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_weakPerson_0 *_weakPerson, int flags=0) : weakPerson(_weakPerson->__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_weakPerson_0 *weakPerson = __cself->weakPerson; // bound by ref((void (*)(id, SEL, int))(void *)objc_msgSend)((id)(weakPerson->__forwarding->weakPerson), sel_registerName("setAge:"), 20);}
static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->weakPerson, (void*)src->weakPerson, 8/*BLOCK_FIELD_IS_BYREF*/);}static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->weakPerson, 8/*BLOCK_FIELD_IS_BYREF*/);}static struct __main_block_desc_0 {size_t reserved;size_t Block_size;void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*);void (*dispose)(struct __main_block_impl_0*);
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0), __main_block_copy_0, __main_block_dispose_0};
int main(int argc, char * argv[]) {/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; Person *per = ((Person *(*)(id, SEL))(void *)objc_msgSend)((id)((Person *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Person"), sel_registerName("alloc")), sel_registerName("init"));__attribute__((__blocks__(byref))) __attribute__((objc_ownership(weak))) __Block_byref_weakPerson_0 weakPerson = {(void*)0,(__Block_byref_weakPerson_0 *)&weakPerson, 33554432, sizeof(__Block_byref_weakPerson_0), __Block_byref_id_object_copy_131, __Block_byref_id_object_dispose_131, per};Block blok = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, (__Block_byref_weakPerson_0 *)&weakPerson, 570425344));((void (*)(__block_impl *))((__block_impl *)blok)->FuncPtr)((__block_impl *)blok);}return UIApplicationMain(argc, argv, __null, NSStringFromClass(((Class (*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("AppDelegate"), sel_registerName("class"))));}

跟上面不同的点就在于__Block_byref_weakPerson_0里面的 Person *__weak weakPerson;这里是weak修饰,同样形象化的以下图解释

证明是强指针:

证明有弱指针

在mrc环境下,证明copy也不会产生强指针。

arc下不论block里经过几层对person对象,都会有强弱指针。

block的内存管理,调用_Block_object_assign的时候传进去的值要么是3要么是8,但是__block修饰的 传进去的是__Block_byref_id_object_copy_131  这个 是131,这个管理的还是不同的。

总结:   这里在栈上不会强引用,不代表在栈上,内部引用对象,不会产生copy和dispose函数

5:循环引用

typedef void (^Block)(void);int main(int argc, char * argv[]) {@autoreleasepool {Person *per = [[Person alloc] init];per.age = 10;per.block = ^{NSLog(@"-----%d",per.age);};}NSLog(@"-----000000000");return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
// 我们只看这一节struct __main_block_impl_0 {struct __block_impl impl;struct __main_block_desc_0* Desc;Person *__strong per;  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, Person *__strong _per, int flags=0) : per(_per) {impl.isa = &_NSConcreteStackBlock;impl.Flags = flags;impl.FuncPtr = fp;Desc = desc;}
};

看到上面是__strong,也就是下面这个图

导致最后person对Person这个类的指针释放了,上面两个却一直相互引用,无法释放。

5.1:解决循环引用问题

arc:

(

一般情况下,只使用__weak就能满足大部分的需求了,只有在多线程处理的时候,需要在Block使用下__strong修饰对象,因为,单个线程,要么执行Block的时候对象还没有被置为nil,那么直到Block被执行完毕,这个对象都不会被释放(释放也是需要线程调用函数的不是?),但是在多线程的情况下,就可能造成,在执行上半部分代码的时候,对象还在,而在执行下半部代码的时候对象已经被释放https://www.jianshu.com/p/fe772a3536ca

)

__weak __unsafe_unretained解决  和__block

        Person *per = [[Person alloc] init];__weak typeof(per) weakPer = per;per.age = 10;per.block = ^{NSLog(@"-----%d",weakPer.age);};
Person *per = [[Person alloc] init];// __weak 不会产生强引用// __unsafe_unretained 不会产生强引用 不安全__unsafe_unretained typeof(per) weakPer = per;per.age = 10;per.block = ^{NSLog(@"-----%d",weakPer.age);};

weak会把指向的对象销毁时会自动置让指针为nil,所以weak是安全的。

__block

int main(int argc, char * argv[]) {@autoreleasepool {__block Person *per = [[Person alloc] init];// __weak 不会产生强引用// __unsafe_unretained 不会产生强引用 不安全per.age = 10;per.block = ^{NSLog(@"-----%d",per.age);per = nil;  // 这两个必须要写};per.block();   // 这两个必须要写 可能有内存泄漏,}NSLog(@"-----000000000");return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}

mrc环境下

__unsafe_unretained 和__block

mrc不支持__weak。

int main(int argc, char * argv[]) {@autoreleasepool {__unsafe_unretained Person *per = [[Person alloc] init];per.age = 10;per.block = [^{NSLog(@"-----%d",per.age);} copy];[per release];}NSLog(@"-----000000000");return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
2018-09-10 19:42:27.889 newxc[34540:11722615] person-dealloc----
2018-09-10 19:42:27.890 newxc[34540:11722615] -----000000000

__block在mrc下不会产生强引用对立面的对象。

__block Person *per = [[Person alloc] init];per.age = 10;per.block = [^{NSLog(@"-----%d",per.age);} copy];[per release];

大总结:面试

1:block的原理是怎样的,本质是什么?

封装了函数调用以及调用环境OC对象。

2:__block的作用?有什么使用的注意点?

封装成了一个对象,在mrc环境下,不会产生强引用对立面的对象

3:block的属性修饰词为什么是copy?使用block有哪些使用注意?

block没有copy,就不会在堆上,copy到堆上,就可以进行内存管理了,使用注意:循环引用

4:block在修改NSMUtablearray,需不需要添加__block?

不需要,

- (void)test
{__weak typeof(self) weakSelf = self;self.age = 10;self.block = ^{        NSLog(@"-----%d",weakSelf->_age);};}

这个会报错,可能是会空值,不能产生强引用,可能会空值

所以就要用一个强指针,来骗编译器,这是编译器行为

- (void)test
{__weak typeof(self) weakSelf = self;self.age = 10;self.block = ^{__strong typeof(weakSelf) myself = weakSelf;NSLog(@"-----%d",myself->_age);};}

另外 用这个强指针 可以确保不会保住这个对象。

ios Block底层详解、框架结构:捕获、对象类型、__block、__forwarding、循环引用相关推荐

  1. iOS runtime 底层详解、内部原理、场景应用

    前言学:位域和共用体 一:isa指针--runtime之前的学习 1.1:苹果应用的按位或.按位与 二:类对象信息 2.1:类对象信息:rw_t 2.2:类对象信息:方法缓存(很关键) 2.2:类对象 ...

  2. IOS 多线程04-GCD详解 底层并发 API

    IOS 多线程04-GCD详解 底层并发 API 注:本人是翻译过来,并且加上本人的一点见解. 前言 想要揭示出表面之下深层次的一些可利用的方面.这些底层的 API 提供了大量的灵活性,随之而来的是大 ...

  3. 【转】iOS Memory 内存详解

    0. 前言 本文以 iOS Memory 的相关内容作为主题,主要从一般操作系统的内存管理.iOS 系统内存.app 内存管理等三个层面进行了介绍,主要内容的目录如下: iOS 是基于 BSD 发展而 ...

  4. iOS Memory 内存详解

    Python实战社群 Java实战社群 长按识别下方二维码,按需求添加 扫码关注添加客服 进Python社群▲ 扫码关注添加客服 进Java社群▲ 作者丨Rickey 来源丨一瓜技术(tech_gua ...

  5. Redis五种基本数据类型底层详解(原理篇)

    Redis五种基本数据类型底层详解 详细介绍Redis用到的数据结构 简单动态字符串 SDS和C字符串的区别 总结 链表 字典 哈希表 字典 哈希算法 解决键冲突 rehash(重点) 渐进式reha ...

  6. iOS 2D绘图详解(Quartz 2D)之路径(点,直线,虚线,曲线,圆弧,椭圆,矩形)

    前言:一个路径可以包含由一个或者多个shape以及子路径subpath,quartz提供了很多方便的shape可以直接调用.例如:point,line,Arc(圆弧),Curves(曲线),Ellip ...

  7. watch深度监听数组_vue watch普通监听和深度监听实例详解(数组和对象)

    vue watch普通监听和深度监听实例详解(数组和对象) 下面通过一段代码给大家介绍vue watch的普通监听和深度监听,具体代码如下所示: var vm=new Vue({ data:{ num ...

  8. iOS核心动画详解swift版----基础动画

    2019独角兽企业重金招聘Python工程师标准>>> iOS核心动画详解swift版---基础动画 创建工程,添加2个ViewController,通过rootViewContro ...

  9. jq的插件 vue中引用_详解如何在 vue 项目里正确地引用 jquery 和 jquery-ui的插件

    本篇文章主要介绍了详解如何在 vue 项目里正确地引用 jquery 和 jquery-ui的插件,具有一定的参考价值,有兴趣的可以了解一下 使用vue-cli构建的vue项目,webpack的配置文 ...

最新文章

  1. ApacheCN 数据科学/人工智能/机器学习知识树 2019.2
  2. Web.config配置访问权限
  3. 客户主数据冻结与删除标记位汇总
  4. 转:如何求出grid图像每个cell对应的x,y坐标?
  5. QT Creator应用程序开发——QT程序设计基本知识
  6. java中bean的定义有哪些_详解Java的Spring框架中bean的定义以及生命周期
  7. 怎么卸载python 旧版本_Python 如何移除旧的版本特性,如何迎接新的特性?
  8. 互联网日报 | 爱奇艺会员宣布11月13日起涨价;淘宝特价版月活用户破7000万;我国成功发射一箭十三星...
  9. Java工作笔记-使用Hibernate连接mysql数据库并进行增、删、改、查!
  10. 安装office2010出现了错误,提示要安装MSXML6.10.1129.0解决方法
  11. matlab计算macd_matlab计算MACD指标
  12. vue element-ui只有一条信息时默认选中按钮,且不能取消,多条信息时可以手动选择
  13. 工程实践:基于C/C++的学生账目管理系统(个人账本管理系统)
  14. Apache Tomcat7.0 Tomcat7启动不了的解决问题
  15. 联想启动Kind City项目:交互式全球合作鼓励同理心,共创建立于善意之上的未来
  16. 仿Excel冻结单元格效果
  17. 三亚旅游_原水_新浪博客
  18. html5网页制作代码-我的班级网页 HTML期末大作业 学校班级网页制作模板
  19. RTOS 任务间互斥的问题
  20. 擦窗机器人不用时怎么收纳_擦窗机器人如何保证不会高空掉落,这些措施必不可少...

热门文章

  1. 法国计划2020起征收数字税
  2. 为什么大公司一定要使用微服务?微服务杂谈(1),推荐学习
  3. 企业网站新闻显示页面(HTML+CSS)
  4. 如何快速访问StackOverFlow
  5. java生成一条唯一的邀请码_如何实现用户id生成一个唯一邀请码
  6. 汽车早讯丨庞大集团董事长回应高管降薪;一嗨租车达成新私有化协议
  7. 整理弱网测试时碰到的问题和解决方案
  8. IO Active将工业机器人变为“杀手”,以警示各大机器人公司
  9. pptv首页导航效果
  10. Eclipse开发Android各种怪病