注意:此库已被 TPDWeakProxy 替换。此存储库将在 2015 年 9 月之后删除。
一个 NSProxy 对象,用于将强引用转换为弱引用。
// Create a weak proxy to the object which you would like to be weakly referenced.
// For example, self.
TPWeakProxy *proxy = [[TPWeakProxy 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.
NSTimer *myWeakRefTimer = [NSTimer scheduledTimerWithTimeInterval:1.0
target:proxy
selector:@selector(myWeakRefTimerFired:)
userInfo:nil
repeats:NO];
最简单的方式:使用 Cocoapods。否则,将 .h 和 .m 文件复制到您的项目中。
$ edit Podfile
platform :ios, '6.1'
pod 'TPWeakProxy', '~> 1.0.0'
$ pod install
$ open App.xcworkspace
TPWeakProxy 解决了 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: 有强引用,而目标通过 myTimer 属性对 NSTimer 有强引用。现在我们有一个引用循环,因此我们有一个内存泄漏。
我们可以通过一种相对容易的方式开始修复它;NSTimer 对它关联的 NSRunLoop 对象有强引用,因此创建它的 UIViewController 可以将其引用更改为弱引用
@property (weak, non-atomic) NSTimer *myTimer;
好的!现在我们不再有内存泄漏了,但我们仍然有一个问题。由于 NSTimer 对 UIViewController 有强引用,因此我们不会在实际释放视图控制器之前释放它,如果您的 NSTimer 在很久以后才激发,这至少浪费了资源,甚至可能引起微妙的错误。不幸的是,NSTimer API 在过去二十多年中基本没有改变;苹果不太可能很快提供具有对 target 有弱引用的 NSTimer。所以我们用 TPWeakProxy 如此修复它
-(void)viewDidLoad {
[super viewDidLoad];
TPWeakProxy *proxy = [[TPWeakProxy alloc] initWithObject:self];
self.myTimer = [NSTimer scheduledTimerWithTimeInterval:30.0
target:proxy
selector:@selector(myTimerFired:)
userInfo:nil
repeats:NO];
}
现在,NSTimer 不会阻止视图控制器在从堆栈中弹出时被销毁,销毁()现在会正确地使计时器失效。
TPWeakProxy 可在 MIT 许可证下使用。有关更多信息,请参阅 LICENSE 文件。