具有块,ARC和非ARC的Objective C内存管理 [英] Objective C memory management with blocks, ARC and non-ARC

本文介绍了具有块,ARC和非ARC的Objective C内存管理的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经使用块已有一段时间了,但是我感到在ARC和非ARC环境中都缺少有关内存管理的东西.我觉得加深了解将使我避免许多内存泄漏.

I have been using blocks for some time now, but I feel that there are things I miss about memory management in both ARC and non-ARC environments. I feel that deeper understanding will make me void many memory leaks.

AFNetworking是我在特定应用程序中主要使用Blocks的方法.在大多数情况下,在操作的完成处理程序中,我会执行类似"[[self.myArray addObject]""的操作.

AFNetworking is my main use of Blocks in a particular application. Most of the time, inside a completion handler of an operation, I do something like "[self.myArray addObject]".

在ARC和未启用ARC的环境中,"self"将根据

In both ARC and non-ARC enabled environments, "self" will be retained according to this article from Apple.

这意味着,每当调用AFNetworking网络操作的完成块时,self就会保留在该块内部,并在该块超出范围时释放.我认为这既适用于ARC,也适用于非ARC.我同时运行了泄漏工具和静态分析器,以便发现任何内存泄漏.没有任何显示.

That means that whenever a completion block of an AFNetworking network operation is called, self is retained inside that block, and released when that block goes out of scope. I believe that this applies to both ARC and non-ARC. I have ran both the Leaks tool and the Static Analyzer so that I may find any memory leaks. None showed any.

但是,直到最近我才偶然发现一个我不知道的警告.在此特定示例中,我正在使用ARC.

However, it wasn't until recently that I stumbled upon a warning which I couldn't figure out. I am using ARC in this particular example.

我有两个实例变量,它们指示网络操作的完成和失败

I have two instance variables that indicate the completion and failure of a network operation

@property (nonatomic, readwrite, copy) SFCompletionBlock completionBlock;
@property (nonatomic, readwrite, copy) SFFailureBlock failureBlock;
@synthesize failureBlock = _failureBlock;
@synthesize operation = _operation;

在代码中的某处,我这样做:

Somewhere in the code, I do this:

[self.operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id
                                                    responseObject) {
NSError *error = [NSError errorWithDomain:@"com.test" code:100 userInfo:@{@"description": @"zero results"}];
            _failureBlock(error);
        } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
            NSLog(@"nothing");
        }];

Xcode抱怨调用failureBlock的行,在此块中强烈提示捕获"自我"的消息很可能会导致保留周期.我相信Xcode是正确的:失败块保留了self,而self保留了它的自身.拥有该块的副本,因此不会释放这两个块.

Xcode complains about the line that calls the failureBlock, with the message "Capturing "self" strongly in this block is likely to result in a retain cycle. I believe Xcode is right: the failure block retains self, and self holds its own copy of the block, so none of the two will be deallocated.

但是,我有以下问题/发现.

However, I have the following questions/observations.

1)如果我将_failureBlock(error)更改为"self.failureBlock(error)"(不带引号),则编译器停止抱怨.这是为什么?这是编译器错过的内存泄漏吗?

1) If i change _failureBlock(error) to "self.failureBlock(error)" (without quotes) the compiler stops complaining. Why is that? Is this a memory leak the compiler misses?

2)通常,使用作为实例变量的块在ARC和未启用ARC的环境中使用块的最佳实践是什么?似乎在AFNetworking中的完成和失败块的情况下,这两个块是 not 实例变量,因此它们可能不属于我上述的保留周期类别.但是,当在AFNetworking中使用进度块时,可以采取什么措施来避免像上述那样的保留周期?

2) In general, what is the best practice to work with blocks in both ARC and non-ARC enabled environments when using blocks that are instance variables? Seems that in the case of completion and failure blocks in AFNetworking, those two blocks are not instance variables so they probably don't fall into the category of retain cycles that I described above. But when using progress blocks into AFNetworking, what can be done to avoid retain cycles like the one above?

我很想听听其他人对ARC和非ARC的想法,包括内存管理的块和问题/解决方案.我发现这些情况容易出错,因此我认为有必要对此进行一些讨论以清除问题.

I would love to hear other people's thoughts on ARC and non-ARC with blocks and issues/solutions with memory management. I find these situations error-prone and I feel some discussion on this is necessary to clear things up.

我不知道这是否重要,但是我将Xcode 4.4与最新的LLVM一起使用.

I don't know if it matters, but I use Xcode 4.4 with the latest LLVM.

推荐答案

1)如果我将_failureBlock(error)更改为"self.failureBlock(error)" (不带引号),编译器停止抱怨.这是为什么?这是 编译器错过的内存泄漏?

1) If i change _failureBlock(error) to "self.failureBlock(error)" (without quotes) the compiler stops complaining. Why is that? Is this a memory leak the compiler misses?

在两种情况下都存在保留周期.如果您的目标是iOS 5以上版本,则可以传递一个对self的弱引用:

The retain cycle exists in both cases. If you're targeting iOS 5+, you can pass in a weak reference to self:

__weak MyClass *weakSelf;
[self.operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
    NSError *error = [NSError errorWithDomain:@"com.test" code:100 userInfo:@{@"description": @"zero results"}];
    if (weakSelf.failureBlock) weakSelf.failureBlock(error);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    NSLog(@"nothing");
}];

现在将不再保留self,如果在调用回调之前将其释放,则该回调为no-op.但是,在后台线程上调用回调时,可能会进行释放,因此此模式有时会导致崩溃.

Now self won't be retained, and if it's deallocated before the callback is invoked, the callback is a no-op. However, it's possible that it could be undergoing deallocation while the callback is invoked on a background thread, so this pattern can create occasional crashes.

2)通常,在这两种情况下都使用块的最佳实践是什么 使用以下块时,支持ARC和非ARC的环境 实例变量?似乎在完成和失败的情况下 AFNetworking中的两个块,这两个块不是实例变量,因此 他们可能不属于我所说的保留周期 如上所述.但是,当在AFNetworking中使用进度块时, 可以采取什么措施来避免像上一个那样的保留周期?

2) In general, what is the best practice to work with blocks in both ARC and non-ARC enabled environments when using blocks that are instance variables? Seems that in the case of completion and failure blocks in AFNetworking, those two blocks are not instance variables so they probably don't fall into the category of retain cycles that I described above. But when using progress blocks into AFNetworking, what can be done to avoid retain cycles like the one above?

大多数时候,我认为最好不要将块存储在实例变量中.如果您改为从类中的方法返回该块,则仍然会有一个保留周期,但是该保留周期仅存在于从调用该方法的时间到释放该块的时间之间.因此,它将防止您的实例在块执行期间被释放,但是保留周期在释放块时结束:

Most of the time, I think it's better not to store blocks in instance variables. If you instead return the block from a method in your class, you'll still have a retain cycle, but it only exists from the time the method is invoked to the time the block is released. So it will prevent your instance from being deallocated during the block execution, but the retain cycle ends when the block is released:

-(SFCompletionBlock)completionBlock {
    return ^(AFHTTPRequestOperation *operation , id responseObject ) {
        [self doSomethingWithOperation:operation];
    };
}

[self.operation setCompletionBlockWithSuccess:[self completionBlock]
                                      failure:[self failureBlock]
];

这篇关于具有块,ARC和非ARC的Objective C内存管理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆