返回
assign、weak 及 unowned 的对比
见解分享
2023-12-19 01:31:47
在编写 Objective-C 程序时,我们常常会遇到循环引用(retain cycle)的问题。为了避免这种问题,我们可以使用 assign
、weak
或 unowned
这三种属性修饰符来修饰对象属性。
assign
assign
修饰符告诉编译器,这个属性是一个指针,它不会对所指向的对象进行引用计数。这意味着,当这个属性所指向的对象被释放时,这个属性不会自动置为 nil
。
// MyClass.h
@interface MyClass : NSObject
@property (nonatomic, assign) NSObject *object;
@end
// MyClass.m
@implementation MyClass
- (void)dealloc {
NSLog(@"MyClass dealloc");
}
@end
// ClientCode.m
MyClass *myClass = [[MyClass alloc] init];
myClass.object = [[NSObject alloc] init];
// 在这里,myClass 和 object 都有一个强引用。
// 当 myClass 被释放时,object 不会被释放,因为 myClass.object 是一个 assign 属性。
[myClass release];
// 在这里,myClass 已经被释放了,但 object 仍然存在,因为 myClass.object 是一个 assign 属性。
// object 现在是一个野指针,指向一块已经释放的内存。
weak
weak
修饰符告诉编译器,这个属性是一个弱引用,它不会增加所指向对象的引用计数。这意味着,当这个属性所指向的对象被释放时,这个属性会自动置为 nil
。
// MyClass.h
@interface MyClass : NSObject
@property (nonatomic, weak) NSObject *object;
@end
// MyClass.m
@implementation MyClass
- (void)dealloc {
NSLog(@"MyClass dealloc");
}
@end
// ClientCode.m
MyClass *myClass = [[MyClass alloc] init];
myClass.object = [[NSObject alloc] init];
// 在这里,myClass 和 object 都有一个强引用。
// 当 myClass 被释放时,object 会被释放,因为 myClass.object 是一个 weak 属性。
[myClass release];
// 在这里,myClass 已经被释放了,object 也被释放了,因为 myClass.object 是一个 weak 属性。
unowned
unowned
修饰符告诉编译器,这个属性是一个无主引用,它不会对所指向的对象进行引用计数,也不会自动置为 nil
。这意味着,当这个属性所指向的对象被释放时,这个属性仍然指向一块已经释放的内存。
// MyClass.h
@interface MyClass : NSObject
@property (nonatomic, unowned) NSObject *object;
@end
// MyClass.m
@implementation MyClass
- (void)dealloc {
NSLog(@"MyClass dealloc");
}
@end
// ClientCode.m
MyClass *myClass = [[MyClass alloc] init];
myClass.object = [[NSObject alloc] init];
// 在这里,myClass 和 object 都有一个强引用。
// 当 myClass 被释放时,object 不会被释放,因为 myClass.object 是一个 unowned 属性。
[myClass release];
// 在这里,myClass 已经被释放了,但 object 仍然存在,因为 myClass.object 是一个 unowned 属性。
// object 现在是一个野指针,指向一块已经释放的内存。
对比
属性修饰符 | 引用类型 | 引用计数 | 自动置为 nil |
---|---|---|---|
assign |
强引用 | 是 | 否 |
weak |
弱引用 | 否 | 是 |
unowned |
无主引用 | 否 | 否 |
何时使用
assign
:当我们需要一个强引用时,比如,当我们需要访问对象的实例变量时。weak
:当我们需要一个弱引用时,比如,当我们需要一个代理对象时。unowned
:当我们需要一个无主引用时,比如,当我们需要一个 block 对象时。
避免循环引用
循环引用是指两个或多个对象互相强引用。在 Objective-C 中,循环引用可能会导致内存泄漏。为了避免循环引用,我们可以使用 weak
或 unowned
属性修饰符来修饰对象属性。
// MyClass.h
@interface MyClass : NSObject
@property (nonatomic, weak) MyClass *delegate;
@end
// MyClass.m
@implementation MyClass
- (void)dealloc {
NSLog(@"MyClass dealloc");
}
@end
// ClientCode.m
MyClass *myClass = [[MyClass alloc] init];
myClass.delegate = myClass;
// 在这里,myClass 和 myClass.delegate 都互相强引用。
// 当 myClass 被释放时,myClass.delegate 不会被释放,因为 myClass.delegate 是一个 weak 属性。
[myClass release];
// 在这里,myClass 已经被释放了,myClass.delegate 也被释放了,因为 myClass.delegate 是一个 weak 属性。
总结
assign
、weak
和 unowned
都是 Objective-C 中常用的属性修饰符。它们可以帮助我们避免循环引用,提高程序的性能和稳定性。