测试已测试 | ✗ |
语言语言 | Obj-CObjective C |
许可证 | MIT |
发布上次发布 | 2016年2月 |
由 Mark Ferlatte,Mark Ferlatte 维护。
一个 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 文件。