TPDWeakProxy 1.1.1

TPDWeakProxy 1.1.1

测试已测试
语言语言 Obj-CObjective C
许可证 MIT
发布上次发布2016年2月

Mark FerlatteMark Ferlatte 维护。



  • 作者
  • Mark Ferlatte 和 Jen Leech

一个 NSProxy 对象,可以将强引用转换为弱引用。

构建状态

使用方法

// Create a weak proxy to the object which you would like to be weakly referenced.
// For example, self.

TPDWeakProxy *proxy = [[TPDWeakProxy alloc] initWithObject:self];

// Now, you can use proxy anywhere you'd normally use self,
// except that self will have a weak reference to it where you use the proxy.

// As an example, NSTimer maintains a strong reference to its target. Sometimes
// this isn't what you want. This is also handy for dealing with
// classes that have strong delegate properties.

NSTimer *myWeakRefTimer = [NSTimer scheduledTimerWithTimeInterval:1.0
                                                           target:proxy
                                                         selector:@selector(myWeakRefTimerFired:)
                                                         userInfo:nil
                                                          repeats:NO];

安装

最简单的方式:使用 CocoaPods。否则,将 TPMWeakProxy.{h,m} 拷贝到您的项目中。

$ edit Podfile
platform :ios, '7.0'
pod 'TPDWeakProxy', '~> 1.1.0'

$ pod install

$ open App.xcworkspace

动机

TPDWeakProxy 解决了 Objective C 中的对象引用循环问题。当实例化的对象通过对其创建自己的对象保持强引用时,就会发生引用循环,使得第一个对象无法被释放,同时第二个对象仍然存在。

这在 iOS 中使用 NSTimers 的常见模式中可能成为问题。

例如,假设你有一个 UIViewController,它想要触发一个刷新事件。一个简单的方法是

@interface

@property (strong, non-atomic) NSTimer *myTimer;

@end

@implementation

-(void)dealloc {
    [self.myTimer invalidate];
}

-(void)viewDidLoad {
    [super viewDidLoad];
    self.myTimer = [NSTimer scheduledTimerWithTimeInterval:30.0
                                                    target:self
                                                  selector:@selector(myTimerFired:)
                                                  userInfo:nil
                                                   repeats:NO];
 }

@end

这个问题在于:NSTimer 对 target: 有强引用,而这个 target 通过 myTimer 属性有对 NSTimer 的强引用。现在我们有一个引用循环,因此我们会有内存泄露。

我们可以很容易地解决这个问题;NSTimer 由它关联的 NSRunLoop 对象强引用,所以创建它的 UIViewController 可以将其引用改为弱引用

@property (weak, non-atomic) NSTimer *myTimer;

太好了!现在我们没有内存泄露了,但我们仍然有一个问题。因为 NSTimer 对 UIViewController 有强引用,所以在 NSTimer 触发之后,我们实际上不会销毁视图控制器。如果你的 NSTimer 将在很久以后触发,这至少会浪费资源,可能还会引起微妙的错误。不幸的是,NSTimer API 在过去二十多年中基本上没有改变;苹果不太可能很快提供具有对 target 的弱引用的 NSTimer。因此我们使用 TPDWeakProxy 来解决这个问题,如下

-(void)viewDidLoad {
    [super viewDidLoad];
    TPDWeakProxy *proxy = [[TPDWeakProxy alloc] initWithObject:self];
    self.myTimer = [NSTimer scheduledTimerWithTimeInterval:30.0
                                                    target:proxy
                                                  selector:@selector(myTimerFired:)
                                                  userInfo:nil
                                                   repeats:NO];
 }

现在,NSTimer 将不会阻止 UIViewController 在从栈中弹出时被销毁,并且 dealloc() 将现在正确地使计时器失效。

感谢

文章 由 Mike Ash 编写,对于理解 Objective C 消息转发路径非常有价值。

许可证

TPDWeakProxy 基于 MIT 许可证提供。有关更多信息,请参见 LICENSE 文件。