返回

assign、weak 及 unowned 的对比

见解分享

在编写 Objective-C 程序时,我们常常会遇到循环引用(retain cycle)的问题。为了避免这种问题,我们可以使用 assignweakunowned 这三种属性修饰符来修饰对象属性。

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 中,循环引用可能会导致内存泄漏。为了避免循环引用,我们可以使用 weakunowned 属性修饰符来修饰对象属性。

// 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 属性。

总结

assignweakunowned 都是 Objective-C 中常用的属性修饰符。它们可以帮助我们避免循环引用,提高程序的性能和稳定性。