NSArray 对 ARC 下对象的弱引用 (__unsafe_unretained)

作者:编程家 分类: objective 时间:2025-05-29

使用 __unsafe_unretained 对象的弱引用在 ARC 下是一种常见的技术,它可以用于解决循环引用的问题。在本文中,我们将探讨 __unsafe_unretained 引用的概念、使用场景以及如何在代码中实现。

在 ARC(Automatic Reference Counting)下,对象的内存管理由编译器自动处理,不再需要手动调用 retain 和 release 方法。然而,这种自动化管理有时会导致循环引用的问题,即两个或多个对象互相引用,导致它们无法被释放。这种情况下,就需要使用弱引用来打破循环引用,以避免内存泄漏。

__unsafe_unretained 是一种弱引用修饰符,它告诉编译器不要自动增加被引用对象的引用计数,也不会在引用对象释放时自动将引用置为 nil。这意味着,如果被引用对象被释放,那么 __unsafe_unretained 引用将变成野指针,可能导致访问已经无效的内存地址而引发崩溃。

那么,在哪些情况下我们需要使用 __unsafe_unretained 引用呢?

1. 在某个对象持有另一个对象的强引用时,如果被持有的对象也需要持有对持有者的引用,就会形成循环引用。这时,我们可以使用 __unsafe_unretained 引用来解决这个问题。

让我们来看一个示例代码,假设有两个类:Person 和 Car。Person 类持有一个 Car 对象作为成员变量,而 Car 类则需要持有对 Person 的引用。为了避免循环引用,我们可以使用 __unsafe_unretained 来声明 Car 类对 Person 类的引用:

objective-c

@interface Person : NSObject

@property (nonatomic, strong) Car *car;

@end

@interface Car : NSObject

@property (nonatomic, __unsafe_unretained) Person *owner;

@end

@implementation Person

@end

@implementation Car

@end

int main() {

Person *person = [[Person alloc] init];

Car *car = [[Car alloc] init];

person.car = car;

car.owner = person;

// 打破循环引用

person.car = nil;

car.owner = nil;

return 0;

}

在上面的代码中,Person 类持有一个强引用 car,而 Car 类使用 __unsafe_unretained 来持有对 owner 的引用。当需要打破循环引用时,我们只需要将 car.owner 和 person.car 设置为 nil 即可。

2. 在使用 block 时,如果 block 内部引用了外部对象,也会导致循环引用的问题。这时,我们可以使用 __unsafe_unretained 引用来解决。

让我们继续以之前的 Person 和 Car 类为例,假设我们在 Person 类中定义了一个方法,在该方法中使用了一个 block,并且在 block 内部引用了 person 对象。为了避免循环引用,我们需要在 block 内部使用 __unsafe_unretained 引用 person 对象:

objective-c

@interface Person : NSObject

@property (nonatomic, strong) NSString *name;

@end

@implementation Person

- (void)sayHello {

void (^block)(void) = ^{

// 使用 __unsafe_unretained 引用外部对象

__unsafe_unretained Person *unsafePerson = self;

NSLog(@"Hello, %@", unsafePerson.name);

};

block();

}

@end

int main() {

Person *person = [[Person alloc] init];

person.name = @"John";

[person sayHello];

return 0;

}

在上面的代码中,我们在 sayHello 方法中定义了一个 block,并在 block 内部使用 __unsafe_unretained 引用 person 对象。这样就避免了循环引用的问题。

使用 __unsafe_unretained 对象的弱引用在 ARC 下是一种常见的技术,可以用于解决循环引用的问题。我们可以在持有对象的类中使用 __unsafe_unretained 修饰符来声明对另一个对象的弱引用,以避免循环引用导致的内存泄漏。在使用 __unsafe_unretained 引用时,需要注意被引用对象被释放时可能会导致野指针的问题,因此需要在合适的时机将引用置为 nil。

需要注意的是,__unsafe_unretained 只是一种弱引用修饰符,它并不会自动将引用置为 nil,也不会自动增加被引用对象的引用计数。因此,在使用 __unsafe_unretained 引用时,需要确保被引用对象的生命周期大于或等于引用对象的生命周期,以避免访问已经释放的对象。