NSSting 详解
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的私有子类,实现了它的所有方法。
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];
}
结论:
- 普通创建的字符串和
static
字符串都是NSCFConstantString
类型,如:a0 ~ a2。- 使用
initWithFormat
方法创建,参数为基础数据类型(如:char
、bool
、int
等等)或NSTaggedPointerString
类型, 字符串都是NSTaggedPointerString
类型,如:a3~a5,a8。- 使用
initWithFormat
方法创建,参数为对象类型的,字符串是NSCFString
类型。如 a6~a7 和 a9 ~ a11
Tagged Pointer
Tagged Pointer
专门用来存储小的对象,例如NSNumber
和NSDate
Tagged Pointer
指针地址保存的其实是(对象地址+值)。所以,实际上它不再是一个对象了,它只是一个披着对象皮的普通变量而已。所以,它的内存并不存储在堆中,也不需要malloc
和free
。
在内存读取上有着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";
}
总结:
- 不管是
strong
还是copy
修饰字符串属性,使用=
赋值 和copy
都会出现 swift 的写时复制
的效果(而原来学习的时候,这2个关键字是深拷贝
和浅拷贝
的区别,估计是系统在新版本给做了优化)。- 使用
mutableCopy
全部按照深拷贝
去实现。- 如果是局部变量,呈现的效果和属性是一样的。