NSSting 详解

2021-11-24  本文已影响0人  Ray_lawq

NSSting 类族

NSSting 是一个类族(Class Clusters),最后生成的对象类型,取决于我们调用的初始化方法(Toll-free bridgin桥接机制 来实现)

Toll-free bridgin桥接机制

Toll-free bridging,简称为TFB,是一种允许某些ObjC类与其对应的CoreFoundation类(Core Foundation框架 (CoreFoundation.framework) 是一组C语言接口,它们为iOS应用程序提供基本数据管理和服务功能)之间可以互换使用的机制。比如 NSString与CFString是桥接(bridged)的, 这意味着可以将任意NSString当做CFString使用,也可以将任意的CFString当做NSString使用。

原理(拿NSString举例)大概是:NSString是一个抽象类,每当你创建一个NSString实例,实际上是创建的NSString的一个私有子类实例。其中一个私有子类就是NSCFString,其是CFString类的在ObjC中的对应类。NSCFString实现了作为NSString需要的所有方法。
我的理解:总之,你知道有Toll-Free Bridging桥接机制,然后NSCFString是NSString的私有子类,实现了它的所有方法。

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

NSSting 类型:

NSCFConstantString:常量类型,保存在常量区,有时候也在栈区,引用计数同样为-1
NSCFString:堆区, 引用计数同样为 1
NSTaggedPointerString:优化的NSCFString,引用计数同样为-1

NSTaggedPointerString (0-9位是taggedpointer类型)
对于64位程序,为了节省内存和提高运行速度,苹果引入了 Tagged Point 技术
NSTaggedPointerString是对NSCFString优化后的存在,在运行时创建时对字符串的内容和长度做出判断,若字符串内容是由ASCII字符构成且长度较小(大概十个字符以内),这时候创建的字符串就是NSTaggedPointerString类型,字符串直接存储在指针里,引用计数同样为-1,不适用对象的内存管理策略。

//类型=__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];
}

结论:

  1. 普通创建的字符串和 static 字符串都是 NSCFConstantString类型,如:a0 ~ a2。
  2. 使用 initWithFormat 方法创建,参数为基础数据类型(如:charboolint等等)或 NSTaggedPointerString 类型, 字符串都是 NSTaggedPointerString类型,如:a3~a5,a8。
  3. 使用initWithFormat 方法创建,参数为对象类型的,字符串是NSCFString 类型。如 a6~a7 和 a9 ~ a11

Tagged Pointer

Tagged Pointer专门用来存储小的对象,例如NSNumberNSDate
Tagged Pointer指针地址保存的其实是(对象地址+值)。所以,实际上它不再是一个对象了,它只是一个披着对象皮的普通变量而已。所以,它的内存并不存储在堆中,也不需要mallocfree
在内存读取上有着3倍的效率,创建时比以前快106倍。
由此看来,NSTaggedPointerString根本不是对象,是分配在栈区的

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";
}

总结:

  1. 不管是 strong 还是 copy 修饰字符串属性,使用 = 赋值 和 copy 都会出现 swift 的 写时复制 的效果(而原来学习的时候,这2个关键字是深拷贝浅拷贝的区别,估计是系统在新版本给做了优化)。
  2. 使用mutableCopy 全部按照深拷贝去实现。
  3. 如果是局部变量,呈现的效果和属性是一样的。
上一篇下一篇

猜你喜欢

热点阅读