简体   繁体   English

在不导致内存泄漏的情况下在代码中保留周期

[英]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持有databaseQueuedatabaseQueue保持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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM