返回

透过现象洞察本质,揭秘 Weak 的实现机制与运用精髓

IOS

前言

弱引用,顾名思义,是一种相对较弱的引用方式。它允许对象之间建立一种非强依赖的关系,当一个对象不再被强引用时,弱引用所指向的对象也不会被强引用,从而可以被系统回收。在 iOS 开发中,弱引用是一种非常重要的内存管理工具,它可以帮助我们避免循环引用,从而防止内存泄漏的发生。

Weak 的底层实现原理

在 Objective-C 中,Weak 引用是通过 __weak 来实现的。当我们使用 __weak 修饰一个对象变量时,编译器会将该变量的类型转换为一个特殊的指针类型,该类型被称为 __weak id

__weak id 指针与普通的 id 指针之间存在着本质的区别。普通 id 指针强引用指向的对象,当指向的对象被释放时,普通 id 指针也会被置为 nil。而 __weak id 指针则弱引用指向的对象,当指向的对象被释放时,__weak id 指针不会被置为 nil,而是会继续指向该对象。

这种弱引用的实现原理是通过一个称为 "弱引用表" 的数据结构来实现的。当一个对象被创建时,系统会在弱引用表中为该对象分配一个唯一的标识符。当一个 __weak id 指针指向该对象时,系统会在弱引用表中记录下该 __weak id 指针和该对象的唯一标识符之间的对应关系。

当指向该对象的最后一个强引用被释放时,系统会将该对象标记为可回收。当系统进行垃圾回收时,系统会遍历弱引用表,并释放所有指向可回收对象的 __weak id 指针。这样,指向该对象的最后一个 __weak id 指针也会被释放,该对象也就真正被释放了。

Weak 的运用精髓

Weak 引用在 iOS 开发中有着广泛的应用场景。以下是一些常见的应用场景:

  • 防止循环引用

循环引用是指两个或多个对象相互强引用,导致谁也无法被释放的情况。循环引用会导致内存泄漏,因为系统无法回收这些对象。Weak 引用可以用来打破循环引用,从而防止内存泄漏的发生。

  • 代理模式

代理模式是一种设计模式,它允许一个对象将某些任务委托给另一个对象。在代理模式中,委托对象通常使用 Weak 引用来持有代理对象,以避免循环引用。

  • 观察者模式

观察者模式是一种设计模式,它允许一个对象将自己的状态变化通知给其他对象。在观察者模式中,观察者通常使用 Weak 引用来持有被观察对象,以避免循环引用。

代码示例

以下是一些 Weak 引用的代码示例:

// 定义一个弱引用变量
__weak id weakObject;

// 将一个对象赋给弱引用变量
id strongObject = [[NSObject alloc] init];
weakObject = strongObject;

// 释放强引用变量
strongObject = nil;

// 此时,weakObject 指向的对象已经被释放,weakObject 的值已经为 nil
NSLog(@"%@", weakObject); // 输出 nil
// 代理模式示例

@protocol MyDelegate <NSObject>

- (void)doSomething;

@end

@interface MyViewController : UIViewController <MyDelegate>

@property (nonatomic, weak) id<MyDelegate> delegate;

@end

@implementation MyViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    // 将自己设置为代理
    self.delegate = self;
}

- (void)doSomething {
    // 代理方法实现
}

@end
// 观察者模式示例

@protocol MyObserver <NSObject>

- (void)update:(id)data;

@end

@interface MySubject : NSObject

@property (nonatomic, strong) NSMutableArray *observers;

- (void)addObserver:(id<MyObserver>)observer;
- (void)removeObserver:(id<MyObserver>)observer;
- (void)notifyObservers:(id)data;

@end

@implementation MySubject

- (instancetype)init {
    self = [super init];
    if (self) {
        self.observers = [NSMutableArray array];
    }
    return self;
}

- (void)addObserver:(id<MyObserver>)observer {
    [self.observers addObject:observer];
}

- (void)removeObserver:(id<MyObserver>)observer {
    [self.observers removeObject:observer];
}

- (void)notifyObservers:(id)data {
    for (id<MyObserver> observer in self.observers) {
        [observer update:data];
    }
}

@end

@interface MyObserverImpl : NSObject <MyObserver>

@end

@implementation MyObserverImpl

- (void)update:(id)data {
    // 观察者方法实现
}

@end

int main(int argc, char * argv[]) {
    @autoreleasepool {
        // 创建被观察者对象
        MySubject *subject = [[MySubject alloc] init];

        // 创建观察者对象
        MyObserverImpl *observer = [[MyObserverImpl alloc] init];

        // 将观察者对象添加到被观察者对象中
        [subject addObserver:observer];

        // 被观察者对象发出通知
        [subject notifyObservers:@"Hello, world!"];

        // 从被观察者对象中移除观察者对象
        [subject removeObserver:observer];
    }
    return 0;
}

总结

Weak 引用是一种非常重要的内存管理工具,它可以帮助我们避免循环引用,从而防止内存泄漏的发生。Weak 引用在 iOS 开发中有广泛的应用场景,包括防止循环引用、代理模式和观察者模式等。希望本文能够帮助您更好地理解 Weak 引用,并在您的开发实践中熟练运用它。