和往常一样提出问题:
1.ARC 环境下中__block 这个关键字做了什么事情
2.ARC 环境下中__weak 这个关键字做了什么事情
3.block 捕获block 外部的变量的时候,对外部变量做了什么事情
4.为什么在block 里无法修改外部变量
5 为什么加上了__block 修饰变量以后 又可以改变了
带着这几个问题,我们来看一段代码
NSString *str =@"12345";
NSLog(@"--1-->%p",str);
void(^block1)() =^{
NSLog(@"---2->%p",str);
};
NSLog(@"--3-->%p",str);
str = @"134";
NSLog(@"--4-->%p",str);
block1();
2017-02-22 16:57:58.500 HZCache[84338:2708224] --1-->0x106281250
2017-02-22 16:57:58.500 HZCache[84338:2708224] --3-->0x106281250
2017-02-22 16:57:58.500 HZCache[84338:2708224] --4-->0x1062812d0
2017-02-22 16:57:58.501 HZCache[84338:2708224] ---2->0x106281250
NSString *str = @"12345";
NSLog(@"--1-->%p",&str);
void(^block1)() =^{
NSLog(@"---2->%p",&str);
};
NSLog(@"--3-->%p",&str);
str = @"134";
NSLog(@"--4-->%p",&str);
block1();
这段代码输出的是str 所在的位置各位猜想一下,这时候哪些相同哪些不同(废话不多讲我们直接上结果)2017-02-22 17:03:33.066 HZCache[84430:2712719] --1-->0x7fff5cc9ab48
2017-02-22 17:03:33.066 HZCache[84430:2712719] --3-->0x7fff5cc9ab48
2017-02-22 17:03:33.066 HZCache[84430:2712719] --4-->0x7fff5cc9ab48
2017-02-22 17:03:33.067 HZCache[84430:2712719] ---2->0x60000004f020
上面结果表明1,3,4 相同2不同。这是不是可以猜想出来一下的内容
NSString *str = @"12345"; 这句话在内存分配上做了三件事情,为str 分配一块内存,为@"12345"分配一块内存,将@"12345"内存地址放入到str 的内存中。那么针对block 做了什么事情,我们可以猜想block 捕捉外部变量的时候,其实只是在block 里声明了一个与外部同名的同类型的变量,而这个变量值指向的就是@"12345"的内存地址,所以当str 被赋值@“134”的时候,block 输出的值还是@"12345",因为它指向的内存地址并没有改变!至于结果是不是我猜想的那样我们看一下代码来验证一下
NSString *str =@"12345";
NSLog(@"--1-->%@",str);
void(^block1)() =^{
NSLog(@"---2->%@",str);
};
NSLog(@"--3-->%@",str);
str = @"134";
NSLog(@"--4-->%@",str);
block1();
输出结果
2017-02-22 17:29:38.396 HZCache[84841:2731851] --1-->12345
2017-02-22 17:29:38.396 HZCache[84841:2731851] --3-->12345
2017-02-22 17:29:38.396 HZCache[84841:2731851] --4-->134
2017-02-22 17:29:38.396 HZCache[84841:2731851] ---2->12345
这个例子是不是支持了我们的猜想了呢,那又有一个问题为什么在block 无法对str进行重新赋值呢?
下面我再看一个例子:
NSMutableString *str = [[NSMutableStringalloc] initWithString:@"12345"];
NSLog(@"--1-->%@",str);
void(^block1)() =^{
str =
[[NSMutableString alloc] initWithString:@"12345"];
[str appendString:@"134"];
NSLog(@"---2->%@",str);
};
block1();
NSLog(@"--3-->%@",str);
str = [[NSMutableStringalloc] initWithString:@"123"];
NSLog(@"--4-->%@",str);
block1();
你们这代码有问题吗?如果有问题出现在哪?如果没问题请问输出结果是啥?下面就是结果了
2017-02-22 17:48:58.647 HZCache[85177:2744586] --1-->12345
2017-02-22 17:48:58.647 HZCache[85177:2744586] ---2->12345134
2017-02-22 17:48:58.647 HZCache[85177:2744586] --3-->12345134
2017-02-22 17:48:58.647 HZCache[85177:2744586] --4-->123
2017-02-22 17:48:58.647 HZCache[85177:2744586] ---2->12345134134
会出现这个结果的原因其实很好解释
[str appendString:@"134"]; 这句操作的是str 指向的地址里面的内容,而不是str 地址的内容所以它就不会有问题,从而也可以解释上面的输出结果,那么还有一个程序
NSMutableString *str = [[NSMutableStringalloc] initWithString:@"12345"];
NSLog(@"--1-->%@",str);
void(^block1)() =^{
str = [[NSMutableString alloc] initWithString:@"123"];
NSLog(@"---2->%@",str);
};
block1();
NSLog(@"--3-->%@",str);
str = [[NSMutableStringalloc] initWithString:@"123"];
NSLog(@"--4-->%@",str);
block1();
请问上面的会报错吗,结果肯定会报错啊,因为你在block 里修改了是 str 指针,而不是修改str指针指向的内存。我们可以猜想一下,blcok 其实给我们隐藏了一行代码如下
累死的代码呢NSMutableString *const str = str;实际上它真的是添加了累死的代码!有写人会说这不就是浅copy吗?只是copy 指针不copy内容,怎么说呢?它确实这样的,但是它真的没有调用对象copy 方法,我用下面的例子来证明这个问题
NSMutableString *str = [[NSMutableStringalloc] initWithString:@"12345"];
NSLog(@"--1-->%p",[strcopy]);
void(^block1)() =^{
NSLog(@"---2->%p",str);
};
NSLog(@"--3-->%p",str);
str = [[NSMutableStringalloc] initWithString:@"123"];
NSLog(@"--4-->%p",str);
block1();
输出结果是
2017-02-22 18:03:32.838 HZCache[85475:2756246] --1-->0xa000035343332315
2017-02-22 18:03:32.838 HZCache[85475:2756246] --3-->0x600000078a80
2017-02-22 18:03:32.838 HZCache[85475:2756246] --4-->0x60800007b680
2017-02-22 18:03:32.839 HZCache[85475:2756246] ---2->0x600000078a80
这个问题例子告诉我们 NSMutableString copy 操作也是深度复制所以我是不是可以说blcok 捕捉外部变量并没有对外部变量执行copy操作,那么有人也会说你这是验证了字符串,有没有验证NSArray 这种结合,下面我通过下面的例子来验证一下NSArray 和 NSMutableArray 来验证我的想法
NSString *str1 = @"123456";
NSString *str2 = @"123";
NSArray *array = [[NSArray alloc] initWithObjects:str1,str2, nil];
void(^block)() = ^{
NSLog(@"---1-->%p",array);
NSLog(@"---4-->%p",&array);
};
NSLog(@"---2-->%p",array);
NSLog(@"---5-->%p",&array);
block();
NSLog(@"---3-->%p",array);
NSLog(@"---6-->%p",&array);
结果是
2017-02-23 09:47:48.097 HZCache[87003:2826674] ---2-->0x600000034340
2017-02-23 09:47:48.097 HZCache[87003:2826674] ---5-->0x7fff56439b38
2017-02-23 09:47:48.097 HZCache[87003:2826674] ---1-->0x600000034340
2017-02-23 09:47:48.097 HZCache[87003:2826674] ---4-->0x60000004bd20
2017-02-23 09:47:48.098 HZCache[87003:2826674] ---3-->0x600000034340
2017-02-23 09:47:48.098 HZCache[87003:2826674] ---6-->0x7fff56439b38
NSString *str1 = @"123456";
NSString *str2 = @"123";
NSArray *array = [[NSArray alloc] initWithObjects:str1,str2, nil];
void(^block)() = ^{
NSString *tempStr = array[0];
NSLog(@"---1-->%p",tempStr);
};
NSLog(@"---2-->%p",str1);
block();
NSLog(@"---3-->%p",str1);
}
结果是2017-02-23 09:52:16.514 HZCache[87094:2830177] ---2-->0x10e64a250
2017-02-23 09:52:16.515 HZCache[87094:2830177] ---1-->0x10e64a250
2017-02-23 09:52:16.515 HZCache[87094:2830177] ---3-->0x10e64a250
__block NSString *str1 = @"123456";
NSLog(@"-str1指向的内存地址1--->%p",str1);
NSLog(@"---str1的内存地址5--->%p",&str1);
void(^block)() = ^{
NSLog(@"--str1指向的内存地址2--->%p",str1);
NSLog(@"---str1的内存地址6--->%p",&str1);
};
NSLog(@"-str1指向的内存地址3--->%p",str1);
NSLog(@"----str1的内存地址7-->%p",&str1);
block();
NSLog(@"--str1指向的内存地址4--->%p",str1);
NSLog(@"----str1的内存地址8-->%p",&str1);
大家可以猜想一下结果,结果真的无法想象的!
2017-02-23 10:08:41.142 HZCache[87431:2845147] -str1指向的内存地址1--->0x103f1c270
2017-02-23 10:08:41.142 HZCache[87431:2845147] ---str1的内存地址5--->0x7fff5bce7b48
2017-02-23 10:08:41.143 HZCache[87431:2845147] -str1指向的内存地址3--->0x103f1c270
2017-02-23 10:08:41.143 HZCache[87431:2845147] ----str1的内存地址7-->0x6080000505b8
2017-02-23 10:08:41.143 HZCache[87431:2845147] --str1指向的内存地址2--->0x103f1c270
2017-02-23 10:08:41.143 HZCache[87431:2845147] ---str1的内存地址6--->0x6080000505b8
2017-02-23 10:08:41.143 HZCache[87431:2845147] --str1指向的内存地址4--->0x103f1c270
2017-02-23 10:08:41.143 HZCache[87431:2845147] ----str1的内存地址8-->0x6080000505b8