NSSting 詳解

NSSting 類族

NSSting 是一個類族(Class Clusters),最后生成的對象類型,取決于我們調(diào)用的初始化方法(Toll-free bridgin橋接機(jī)制 來實現(xiàn))

Toll-free bridgin橋接機(jī)制

Toll-free bridging,簡稱為TFB,是一種允許某些ObjC類與其對應(yīng)的CoreFoundation類(Core Foundation框架 (CoreFoundation.framework) 是一組C語言接口,它們?yōu)閕OS應(yīng)用程序提供基本數(shù)據(jù)管理和服務(wù)功能)之間可以互換使用的機(jī)制。比如 NSString與CFString是橋接(bridged)的, 這意味著可以將任意NSString當(dāng)做CFString使用,也可以將任意的CFString當(dāng)做NSString使用。

原理(拿NSString舉例)大概是:NSString是一個抽象類,每當(dāng)你創(chuàng)建一個NSString實例,實際上是創(chuàng)建的NSString的一個私有子類實例。其中一個私有子類就是NSCFString,其是CFString類的在ObjC中的對應(yīng)類。NSCFString實現(xiàn)了作為NSString需要的所有方法。
我的理解:總之,你知道有Toll-Free Bridging橋接機(jī)制,然后NSCFString是NSString的私有子類,實現(xiàn)了它的所有方法。

iOS 支持Toll-free bridgin的類
iOS 支持Toll-free bridgin的類

NSSting 類型:

NSCFConstantString:常量類型,保存在常量區(qū),有時候也在棧區(qū),引用計數(shù)同樣為-1
NSCFString:堆區(qū), 引用計數(shù)同樣為 1
NSTaggedPointerString:優(yōu)化的NSCFString,引用計數(shù)同樣為-1

NSTaggedPointerString (0-9位是taggedpointer類型)
對于64位程序,為了節(jié)省內(nèi)存和提高運行速度,蘋果引入了 Tagged Point 技術(shù)。
NSTaggedPointerString是對NSCFString優(yōu)化后的存在,在運行時創(chuàng)建時對字符串的內(nèi)容和長度做出判斷,若字符串內(nèi)容是由ASCII字符構(gòu)成且長度較?。ù蟾攀畟€字符以內(nèi)),這時候創(chuàng)建的字符串就是NSTaggedPointerString類型,字符串直接存儲在指針里,引用計數(shù)同樣為-1,不適用對象的內(nèi)存管理策略。

//類型=__NSCFConstantString, 地址=0x101d1a098
static NSString *a = @"a";
- (void)test {

    //類型=__NSCFConstantString, 地址=0x101d1a0d8
    NSString *a0 = @"aaa";
    NSString *a1 = [[NSString alloc] init];
    a0 = @"a0";
    NSString *a2 = [[NSString alloc] initWithString:a0];
    
    //類型=NSTaggedPointerString, 地址=0x89a6aa09cd52cc1f
    NSString *a3 = [NSString stringWithFormat:@"%s", "str2"];
    NSString *a4 = [NSString stringWithFormat:@"%d", 123];
    NSString *a5 = [NSString stringWithFormat:@"%d", YES];
    
    //類型=__NSCFString, 地址=0x60000032a5a0
    NSString *a6 = [[NSString alloc] initWithFormat:@"aaa"];
    //類型=__NSCFString, 地址=0x60000032a520,
    NSString *a7 = [NSString stringWithFormat:@"%@", @"aaa"];
    //類型=NSTaggedPointerString, 地址=0x89a6aa09cd52cc1f
    NSString *a8 = [NSString stringWithFormat:@"%@", a3];
    
    //類型=__NSCFString, 地址=0x600000d70de0
    NSMutableString *a9 = [NSMutableString stringWithFormat:@"%@", a0];
    NSMutableString *a10 = [NSMutableString stringWithFormat:@"%@", a3];
    NSMutableString *a11 = [NSMutableString stringWithFormat:@"%@", a6];
}

結(jié)論:

  1. 普通創(chuàng)建的字符串和 static 字符串都是 NSCFConstantString類型,如:a0 ~ a2。
  2. 使用 initWithFormat 方法創(chuàng)建,參數(shù)為基礎(chǔ)數(shù)據(jù)類型(如:char、boolint等等)或 NSTaggedPointerString 類型, 字符串都是 NSTaggedPointerString類型,如:a3~a5,a8。
  3. 使用initWithFormat 方法創(chuàng)建,參數(shù)為對象類型的,字符串是NSCFString 類型。如 a6~a7 和 a9 ~ a11

Tagged Pointer

Tagged Pointer專門用來存儲小的對象,例如NSNumberNSDate
Tagged Pointer指針地址保存的其實是(對象地址+值)。所以,實際上它不再是一個對象了,它只是一個披著對象皮的普通變量而已。所以,它的內(nèi)存并不存儲在堆中,也不需要mallocfree。
在內(nèi)存讀取上有著3倍的效率,創(chuàng)建時比以前快106倍。
由此看來,NSTaggedPointerString根本不是對象,是分配在棧區(qū)的

copy and mutableCopy

@property (nonatomic, strong) NSString *str;
@property (nonatomic, strong) NSString *str1;

@property (nonatomic, copy) NSString *str2;
@property (nonatomic, copy) NSString *str3;

- (void)test {

    //類型=__NSCFConstantString, 地址=0x10ca08098
    self.str = @"aaa";
    self.str1 = self.str;

    //str   類型=__NSCFConstantString, 地址=0x10ca08098
    //str1  類型=__NSCFConstantString, 地址=0x10ca08138
    self.str1 = @"bbb";

    //類型=__NSCFConstantString, 地址=0x10ca08158
    self.str2 = @"ccc";
    self.str3 = self.str2;

    //類型=__NSCFConstantString, 地址=0x10ca08158
    //類型=__NSCFConstantString, 地址=0x10ca081b8
    self.str3 = @"ddd";
}

- (void)test1 {

    //類型=__NSCFConstantString, 地址=0x10ca08098
    self.str = @"aaa";
    self.str1 = [self.str copy];

    //str   類型=__NSCFConstantString, 地址=0x10ca08098
    //str1  類型=__NSCFConstantString, 地址=0x10ca08138
    self.str1 = @"bbb";

    //類型=__NSCFConstantString, 地址=0x10ca08158
    self.str2 = @"ccc";
    self.str3 = [self.str2 copy];

    //類型=__NSCFConstantString, 地址=0x10ca08158
    //類型=__NSCFConstantString, 地址=0x10ca081b8
    self.str3 = @"ddd";
}

- (void)test2 {

    //類型=__NSCFConstantString, 地址=0x10ca08098
    self.str = @"aaa";
    //類型=__NSCFString, 地址=0x600003a60e70
    self.str1 = [self.str mutableCopy];

    //str   類型=__NSCFConstantString, 地址=0x10ca08098
    //str1  類型=__NSCFConstantString, 地址=0x10b926138
    self.str1 = @"bbb";

    //類型=__NSCFConstantString, 地址=0x10ca08158
    self.str2 = @"ccc";
    //類型= NSTaggedPointerString, 地址=0xaec7592a59dc294c
    self.str3 = [self.str2 mutableCopy];

    //類型=__NSCFConstantString, 地址=0x10ca08158
    //類型=__NSCFConstantString, 地址=0x10b9261b8
    self.str3 = @"ddd";
}

總結(jié):

  1. 不管是 strong 還是 copy 修飾字符串屬性,使用 = 賦值 和 copy 都會出現(xiàn) swift 的 寫時復(fù)制 的效果(而原來學(xué)習(xí)的時候,這2個關(guān)鍵字是深拷貝淺拷貝的區(qū)別,估計是系統(tǒng)在新版本給做了優(yōu)化)。
  2. 使用mutableCopy 全部按照深拷貝去實現(xiàn)。
  3. 如果是局部變量,呈現(xiàn)的效果和屬性是一樣的。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容