[英]having retain cycles in code when its not causing memory leak
#import "ViewController.h"
@implementation A
- (instancetype)init
{
self = [super init];
if (self)
{
self.databaseQueue = dispatch_queue_create("someQueue", DISPATCH_QUEUE_SERIAL);
}
return self;
}
- (void) privateLogMethod
{
NSLog(@"private log method called");
[NSThread sleepForTimeInterval:1];
}
- (void) performSomeAction
{
for (NSInteger i = 0; i < 10; i++) {
dispatch_async(_databaseQueue, ^{
NSLog(@"inside for loop");
[self privateLogMethod];
});
}
}
- (void) dealloc
{
NSLog(@"removing A from memory");
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.someClassA = [[A alloc] init];
[self.someClassA performSomeAction];
[self performSelector:@selector(removeA) withObject:nil afterDelay:5];
}
- (void) removeA
{
NSLog(@"call to remove A from memory");
self.someClassA = nil;
}
@end
#import <UIKit/UIKit.h>
@interface A: NSObject
- (void) performSomeAction;
@property (nonatomic, strong) dispatch_queue_t databaseQueue;
@end
@interface ViewController : UIViewController
@property (nonatomic, strong) A* someClassA;
@end
If we see the code above, there is a retain cycle since class A
is holding on to databaseQueue
and databaseQueue
is holding on to self
. 如果我们看到上面的代码,那么就有一个保留周期,因为class A
持有databaseQueue
而databaseQueue
保持self
。 Thus, when ViewController
asks to dealloc A
after 5 seconds, class A
holds on to finish the loop before deallocating
itself. 因此,当ViewController
询问到dealloc A
5秒后, class A
持有之前完成环路deallocating
本身。 Below is the output. 以下是输出。
2017-09-14 14:21:06.774517+0530 testdealloc[72021:1812626] inside for loop
2017-09-14 14:21:06.774768+0530 testdealloc[72021:1812626] private log method called
2017-09-14 14:21:07.775218+0530 testdealloc[72021:1812626] inside for loop
2017-09-14 14:21:07.775480+0530 testdealloc[72021:1812626] private log method called
2017-09-14 14:21:08.778805+0530 testdealloc[72021:1812626] inside for loop
2017-09-14 14:21:08.779251+0530 testdealloc[72021:1812626] private log method called
2017-09-14 14:21:09.784467+0530 testdealloc[72021:1812626] inside for loop
2017-09-14 14:21:09.785089+0530 testdealloc[72021:1812626] private log method called
2017-09-14 14:21:10.790469+0530 testdealloc[72021:1812626] inside for loop
2017-09-14 14:21:10.790929+0530 testdealloc[72021:1812626] private log method called
2017-09-14 14:21:11.775522+0530 testdealloc[72021:1812575] **call to remove A from memory**
2017-09-14 14:21:11.796196+0530 testdealloc[72021:1812626] inside for loop
2017-09-14 14:21:11.796659+0530 testdealloc[72021:1812626] private log method called
2017-09-14 14:21:12.802018+0530 testdealloc[72021:1812626] inside for loop
2017-09-14 14:21:12.802483+0530 testdealloc[72021:1812626] private log method called
2017-09-14 14:21:13.804953+0530 testdealloc[72021:1812626] inside for loop
2017-09-14 14:21:13.805432+0530 testdealloc[72021:1812626] private log method called
2017-09-14 14:21:14.806252+0530 testdealloc[72021:1812626] inside for loop
2017-09-14 14:21:14.806604+0530 testdealloc[72021:1812626] private log method called
2017-09-14 14:21:15.807852+0530 testdealloc[72021:1812626] inside for loop
2017-09-14 14:21:15.808306+0530 testdealloc[72021:1812626] private log method called
2017-09-14 14:21:16.809550+0530 testdealloc[72021:1812626] **removing A from memory**
My question is this: We've a retain cycle in the code, however, this does not cause memory leak. 我的问题是:我们在代码中有一个保留周期,但是,这不会导致内存泄漏。 Is it okay, in such scenarios, to leave the code as is [because it does not cause memory leak for sure]? 在这种情况下,是否可以保留代码[因为它确实不会导致内存泄漏]? or should I use __weak weakSelf = self
and then weakSelf
in the block to ensure there is no retain cycle at all? 或者我应该在块中使用__weak weakSelf = self
然后使用weakSelf
来确保根本没有保留周期?
You ask: 你问:
Is this okay? 这个可以吗?
Largely, yes. 很大程度上,是的。
More accurately, it depends upon your needs/intent. 更准确地说,这取决于您的需求/意图。 If you need this to continue to run for your app to function properly (eg maybe you're converting and saving some images), then you definitely want a strong reference so that it finishes). 如果您需要继续运行以使您的应用程序正常运行(例如,您可能正在转换并保存一些图像),那么您肯定需要一个强大的参考,以便它完成)。
But if you don't need to continue to execute, then you'd use weakSelf
pattern. 但如果您不需要继续执行,那么您将使用weakSelf
模式。 For example, imagine you had a series of dispatched tasks in a view controller that were there solely to later trigger UI updates. 例如,假设您在视图控制器中有一系列调度任务,这些任务仅用于以后触发UI更新。 In that case, if the view controller was dismissed, you might not need these blocks to run, and you certainly wouldn't want it to hang on to the view controller for a view that was long since dismissed. 在这种情况下,如果视图控制器被解除,您可能不需要运行这些块,并且您当然不希望它挂起到视图控制器以查看已被解雇的视图。 (You might even want to cancel those dispatched items when the view controller was dismissed, but that's another topic.) (您甚至可能希望在取消视图控制器时取消这些已分派的项目,但这是另一个主题。)
Bottom line, it depends upon your intent. 底线,这取决于你的意图。
I second @Rob. 我是第二个@Rob。 But look for any single opportunity to avoid retain cycles. 但寻找任何避免保留周期的机会。 This is okay for a simple project, but while working on complex projects... it will save lots of time trying to debug/resolve an issue where you are not certain about the root cause. 这对于一个简单的项目是可以的,但是在处理复杂的项目时...它会节省大量时间来尝试调试/解决您不确定根本原因的问题。
Here is a beautiful article explaining different types of retain cycles and to avoid them. 这是一篇很好的文章,解释了不同类型的保留周期并避免它们。
https://www.cocoawithlove.com/2009/07/rules-to-avoid-retain-cycles.html https://www.cocoawithlove.com/2009/07/rules-to-avoid-retain-cycles.html
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.