NSString *str1 = [NSString stringWithFormat:@"test"];
NSString *str2 = [str1 copy];
NSMutableString *str3 = [str1 mutableCopy];
指针指向情况:
深拷贝:内容拷贝,有产生新的对象
浅拷贝:指针拷贝,没有产生新对象
NSMutableString *str1 = [NSString stringWithFormat:@"test"];
NSString *str2 = [str1 copy]; // 类型不同,产生新对象,深拷贝
NSMutableArray * arr1 = [[NSMutableArray alloc] initWithObjects:@"b",@"ab", nil];
NSArray *arr2 = [arr1 copy]; // 产生新类型的对象,深拷贝
NSMutableArray *arr3 = [arr1 mutableCopy]; // 深拷贝
总结:
不可变对象(NSString,NSArray,NSDictionary),调用copy,都是浅拷贝;
对象只要是调用mutableCopy,都是深拷贝;
下面这句代码有什么问题?为什么?
@property (copy, nonatomic) NSMutableArray *array;
问题:使用copy修饰的,不应该是可变对象,因为底层生成的set方法会使用copy,返回的对象就是不可变对象了。
底层set方法如下:
- (void)setArray:(NSMutableArray *)array {
if (_array != array) {
[_array release];
_array = [array copy];
}
}
一般都用strong修饰:
@property (strong, nonatomic) NSMutableArray *array;
1、遵守NSCopying协议
#import
NS_ASSUME_NONNULL_BEGIN
@interface Dog : NSObject
@property (assign, nonatomic) int age;
@property (assign, nonatomic) double weight;
@end
NS_ASSUME_NONNULL_END
2、需要实现- (id)copyWithZone:(NSZone *)zone方法
#import "Dog.h"
@implementation Dog
- (id)copyWithZone:(NSZone *)zone {
Dog *dog = [[Dog allocWithZone:zone] init];
dog.age = self.age;
dog.weight = self.weight;
return dog;
}
- (NSString *)description {
return [NSString stringWithFormat:@"age = %d weight = %f", self.age, self.weight];
}
@end
5、补充weak原理
weak指针实现原理
将弱引用对象存到一个哈希表里面,到时候当这个对象要销毁的时候,就从这个哈希表里面取出这个对象,将这个对象置为nil
ARC:
LLVM + runtime
1.LLVM自动给代码生成retain,release,autorelease *** 作;
2.弱引用的指针通过runtime进行 *** 作
这个关键字是在MRC下使用
自动释放池的主要底层数据结构是:__AtAutoreleasePool、AutoreleasePoolPage
调用了autorelease的对象最终都是通过AutoreleasePoolPage对象来管理的
1.每个AutoreleasePoolPage对象占用4096个字节内存,除了用来存放它内部的成员变量,剩下的空间用来存放autorelease对象地址
2.所有的AutoreleasePoolPage对象通过双向链表的形式连接在一起
每个autorelease内部都是先push,然后执行完再pop
extern void _objc_autoreleasePoolPrint(void); // 打印release情况
int main(int argc, const char * argv[]) {
@autoreleasepool { // r1 = push()
NSLog(@"111");
@autoreleasepool { // r2 = push()
Dog *d1 = [[[Dog alloc] init] autorelease];
Dog *d2 = [[[Dog alloc] init] autorelease];
NSLog(@"22222");
_objc_autoreleasePoolPrint();
@autoreleasepool { // r3 = push()
Dog *d3 = [[[Dog alloc] init] autorelease];
Dog *d4 = [[[Dog alloc] init] autorelease];
NSLog(@"3333");
_objc_autoreleasePoolPrint();
@autoreleasepool { // r4 = push()
Dog *d5 = [[[Dog alloc] init] autorelease];
Dog *d6 = [[[Dog alloc] init] autorelease];
for (int i = 0; i < 1000; i ++) {
Dog *d6 = [[[Dog alloc] init] autorelease];
}
NSLog(@"444");
_objc_autoreleasePoolPrint();
} // r4 = pop()
NSLog(@"555");
_objc_autoreleasePoolPrint();
} // r3 = pop()
} // r2 = pop()
NSLog(@"22");
} // r1 = pop()
return 0;
}
autorelease的调用时机:
所处的Runloop即将休眠的时候调用
1、ARC下,局部变量一执行完毕,就会释放,因为编译器会自动添加释放方法
- (void)viewDidLoad {
[super viewDidLoad];
Person *p = [[Person alloc] init];
// [p release] //这一行,编译器会自动加上
}
2、MRC下,局部变量一执行完,不一定会马上释放,会在Runloop即将休眠的时候释放
- (void)viewDidLoad {
[super viewDidLoad];
Person *p = [[[Person alloc] init] autorelease];
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)