被__weak修饰的NSString

以下代码输出结果如何?

    NSString *name1 = [NSString stringWithFormat:@"haha"];
    __weak NSString *name2 = name1;
    NSLog(@"name1:%@", name1);
    NSLog(@"name2:%@", name2);
    name1 = nil;
    NSLog(@"name1:%@", name1);
    NSLog(@"name2:%@", name2);
    
    NSString *a1 = [[NSString alloc] initWithFormat:@"haha"];
    __weak NSString *a2 = a1;
    NSLog(@"a1:%@", a1);
    NSLog(@"a2:%@", a2);
    a1 = nil;
    NSLog(@"a1:%@", a1);
    NSLog(@"a2:%@", a2);
    
    NSString *b1 = @"haha";
    __weak NSString *b2 = b1;
    NSLog(@"b1:%@", b1);
    NSLog(@"b2:%@", b2);
    b1 = nil;
    NSLog(@"b1:%@", b1);
    NSLog(@"b2:%@", b2);

结果:

**2016-08-04 16:11:14.336 xxxxxxxx[677:238940] name1:haha**
**2016-08-04 16:11:14.337 xxxxxxxx[677:238940] name2:haha**
**2016-08-04 16:11:14.337 xxxxxxxx[677:238940] name1:(null)**
**2016-08-04 16:11:14.337 xxxxxxxx[677:238940] name2:haha**
****
****
**2016-08-04 16:11:14.338 xxxxxxxx[677:238940] a1:haha**
**2016-08-04 16:11:14.338 xxxxxxxx[677:238940] a2:haha**
**2016-08-04 16:11:14.338 xxxxxxxx[677:238940] a1:(null)**
**2016-08-04 16:11:14.339 xxxxxxxx[677:238940] a2:(null)**
****
****
**2016-08-04 16:11:14.339 xxxxxxxx[677:238940] b1:haha**
**2016-08-04 16:11:14.339 xxxxxxxx[677:238940] b2:haha**
**2016-08-04 16:11:14.340 xxxxxxxx[677:238940] b1:(null)**
**2016-08-04 16:11:14.340 xxxxxxxx[677:238940] b2:haha**

看到结果,有点匪夷所思,(name1, a1, b1)置空后,被__weak修饰的(name2, a2 b2)输出怎么还会有东西?难道和NSString类型有关,或者说和NSString的初始化方式有关?

如果是NSObject,输出结果正常:

    NSObject *obj1=[[NSObject alloc] init];
    __strong NSObject *obj2 = obj1;
    NSLog(@"%@,%@", obj1, obj2);
    obj1 = nil;
    NSLog(@"%@,%@", obj1, obj2);
    
    NSObject *obj3=[[NSObject alloc] init];
    __weak NSObject *obj4 = obj3;
    NSLog(@"%@,%@", obj3, obj4);
    obj3 = nil;
    NSLog(@"%@,%@", obj3, obj4);

输出结果正常,可看出strong与weak的区别:strong的对象会使retainCount+1,而weak不会。 所以第一个例子的retainCount为2,obj1 = nil之后retainCount为1,并不会对obj2造成影响;而第二个例子obj3 = nil后retainCount 为0了,内存也跟着释放了,所以obj2也为nil。

**2016-08-05 09:32:49.918 xxxxxxxx[766:298464] <NSObject: 0x170b4780>,<NSObject: 0x170b4780>**
**2016-08-05 09:32:49.918 xxxxxxxx[766:298464] (null),<NSObject: 0x170b4780>**
****
**2016-08-05 09:32:49.919 xxxxxxxx[766:298464] <NSObject: 0x15f5d9d0>,<NSObject: 0x15f5d9d0>**
**2016-08-05 09:32:49.919 xxxxxxxx[766:298464] (null),(null)**

NSString也是一个NSObject,为什么它就不一样?(同事的电脑输出结果和我的还不一样,如下图,不知什么原因)


tmp1a9fbb26.png
    NSString *str1 = @"q"; // 与[NSString stringWithString:@"q"];等价
    NSString *str2 = [NSString stringWithFormat:@"q"];
    NSString *str3 = [[NSString alloc] initWithFormat:@"q"];
    NSString *str4 = [[NSMutableString alloc] initWithString:@"q"];
    NSLog(@"str1:%@", [str1 class]);
    NSLog(@"str2:%@", [str2 class]);
    NSLog(@"str3:%@", [str3 class]);
    NSLog(@"str4:%@", [str4 class]);

    str1 = @"afdjfdfjle”;
**2016-08-05 16:08:05.302 xxxxxxxxx[875:375798] str1:__NSCFConstantString**
**2016-08-05 16:08:05.303 xxxxxxxxx[875:375798] str2:__NSCFString**
**2016-08-05 16:08:05.303 xxxxxxxxx[875:375798] str3:__NSCFString**
**2016-08-05 16:08:05.303 xxxxxxxxx[875:375798] str4:__NSCFString**
tmp2ed54bee.png

可看出:
1.除str1类型为NSCFString(NSCFConstantString)外,其他的类型都为NSMutableString;
2.给str1赋值后打一个断点,重新赋值后再打一个断点,观察str1的内存地址发现已经变了。有点意外吧?按照 C 语言的经验,初始化一个字符串之后,字符串的首地址就被确定下来,不管之后如何修改字符串内容,这个地址都不会改变。但此处第10行并不是对 str1 指向的内存地址重新赋值,因为赋值操作符左边的 str1 是一个指针,也就是说此处修改的是内存地址。 所以第10行应该这样理解:将@"afdjfdfjle”当做一个新的对象,将这段对象的内存地址赋值给str。


tmp6b54477b.png

tmp2179540e.png
    NSString __weak *string = [[NSString alloc] initWithFormat:@"First Name: %@", @"A"];
    NSLog(@"string:%@", string);
    
    NSString __weak *string2 = @"B";
    NSLog(@"string:%@", string2);
    
    NSString __weak *string3 = [[NSString alloc] initWithString:@"C"];
    NSLog(@"string:%@",string3);
**2016-08-05 09:55:50.923 Decoration[772:303138] string:(null)**
**2016-08-05 09:55:50.923 Decoration[772:303138] string:B**
**2016-08-05 09:55:50.923 Decoration[772:303138] string:C**

解释:
1.没有强引用的变量是会被立即释放的,所以打印的string会是nil。
2.下面两种情况(@""、initWithString)声明的是常量字符串,没有retainCount(引用计数),没有强指针指向它,存在内存静态区,不会被销毁,输出自然会有结果。


tmp1dc184fa.png

回到最开始的问题:


tmp58031aeb.png

分别在name1, a1, b1 置空前后打一个断点观察name2, a2, b2类型的变化,输出结果应该一目了然了吧。

**(lldb) p name2**
(__NSCFString *) $6 = 0x147c0210 @"haha"
**(lldb) p name2**
(__NSCFString *) $7 = 0x147c0210 @"haha"

**(lldb) p a2**
(__NSCFString *) $8 = 0x1581b480 @"haha"
**(lldb) p a2**
(NSString *) $9 = nil

**(lldb) p b2**
(__NSCFConstantString *) $10 = 0x00844fcc @"haha"
**(lldb) p b2**
(__NSCFConstantString *) $11 = 0x00844fcc @"haha"

NSString特性分析学习

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • __block和__weak修饰符的区别其实是挺明显的:1.__block不管是ARC还是MRC模式下都可以使用,...
    LZM轮回阅读 8,687评论 0 6
  • 多线程、特别是NSOperation 和 GCD 的内部原理。运行时机制的原理和运用场景。SDWebImage的原...
    LZM轮回阅读 6,091评论 0 12
  • ———————————————回答好下面的足够了---------------------------------...
    恒爱DE问候阅读 5,683评论 0 4
  • iOS面试小贴士 ———————————————回答好下面的足够了------------------------...
    不言不爱阅读 6,182评论 0 7
  • 最近胎动越来越明显 裘同学的准爸爸潜质终于被激发了 每天跟她对话 甚至还会联合起来欺负我 慢慢 踢妈妈 快踢 妈妈...
    PWong阅读 1,644评论 0 0