NSString 遇到的坑

根本停不下來發表於2018-08-03

參考文章

小談NSString的記憶體分配

ObjC中怎麼判斷可變和不可變的坑

我遇到的問題

知識補充:以字面量形式或者 initWithString: 建立出來的字串是在常量區的,不會釋放。以 stringWithFormat: 建立出來的是在堆上。

NSString 遇到的坑
在這個截圖中可以看出來的問題:

  1. string1 與 string3 是 __NSCFConstantString 型別的,它們是在常量區的。
  2. string4 是 __NSCFString 型別的,它的地址比 string1 與 string3 高的多,它是在堆上的。
  3. string2 是 NSTaggedPointerString 型別的。它的地址的第一位位是 a (十六進位制),如果在二進位制下,這個地址的首位為 1。地址首位為 1,在 iOS 平臺下,就是 TaggedPointer 處理過的(看原始碼可以知道)。

問題一

@property (nonatomic, copy) NSString * name;
for (int i = 0; i < 1000; i++) {
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
            self.name = [NSString stringWithFormat:@"abcdefghij"];
        });
}
複製程式碼
for (int i = 0; i < 1000; i++) {
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
            self.name = [NSString stringWithFormat:@"abcdefghi"];
        });
}
複製程式碼

第一段程式碼會崩潰,因為在 - setName: 方法中多次釋放 _name。
第二段程式碼不會崩潰,它與第一個不同的是,這個字串比較短,採用的是 taggedpointer 技術。 它為什麼不崩潰,暫時不太理解?我打上斷點發現每次都會進入- setName: 方法,那麼每次進來都會有 release 才對。

問題二

for (int i = 0; i < 1000; i++) {
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
            self.name = @"abcdefghij";
        });
}
複製程式碼

這段程式碼是使用的比更長的那個字串。
這段程式碼也不會崩潰。
它是建立在常量區的。
它為什麼不崩潰,我也不知道。

問題三

NSString *string = [NSString stringWithFormat:@"abcdefghij"];
for (int i = 0; i < 1000; i++) {
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        self.name = string;
    });
}
複製程式碼

這段程式碼也是使用的比較長的那個字串。在第一段程式碼中,它崩了,在這段裡面,它沒崩。為什麼?

相關文章