iOS正确使用@weakify(self)和@strongify(self) [英] iOS Proper Use of @weakify(self) and @strongify(self)

查看:2498
本文介绍了iOS正确使用@weakify(self)和@strongify(self)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我开始将libextobjc( https://github.com/jspahrsummers/libextobjc )整合到我的iOS应用程序中利用EXTScope的 @strongify @weakify ,但在深入了解该过程之前有几个问题。

I'm starting to integrate libextobjc (https://github.com/jspahrsummers/libextobjc) into my iOS application primarily to take advantage of EXTScope's @strongify and @weakify, but have a few questions before proceeding too deep into the process.

这是一个故意过于复杂的例子,试图解决如何处理这个问题:

Here's an example that's intentionally overly-complicated to try to suss out how to handle this:

- (void)someMethod {
    if (self.someBOOL) {
        _someObjectInstanceVar = [Object objectWithCompletionHandler:^{
            // self reference #1
            if (self.someProperty) {
                // self reference #2
                [[Async HTTPRequest] sendAWithID:self.property.id completionHandler:^(void (^)(NewObject *newObject) {
                    // self reference #3
                    [self showViewWithObject:newObject handler:^{
                        // self reference #4
                        [self reloadData];
                    }];
                }];
            }
        }];

    else {
        [[Async HTTPRequest] sendBWithID:self.property.id completionHandler:^{
            // self reference #5
            [self reloadData];
        }];
    }
}

我的理解是,如果我想做任何事情,比如一个异步HTTP请求,并在完成处理程序引用self中,如 [self reloadData] ,我不需要对强/弱做任何事情,因为请求块本身不是保留完成块,因此保留周期没有问题。在上面的代码示例中,我认为#5 是一个保留周期不是问题的情况。

My understanding is that if I want to do anything like an async HTTP request, and inside the completion handler reference self, like [self reloadData], I don't need to do anything with strong/weak as the request block itself isn't retaining the completion block, so there's no problems with retain cycles there. In the above code example, I think #5 is a case where a retain cycles isn't an issue.

主要关注的是所有将块作为属性/ init参数的对象,内部保留在块属性中。在 objectWithCompletionHandler 方法中, someObject 作为实例变量保存在completionHandler块中,有多个对self的引用我知道会导致泄漏。我的主要问题是在这种情况下,您需要如何处理弱化 strongify 以使其更安全 ?一个@weakify和@strongify调用是否足够,如下所示:

The main concern are all of the objects that take a block as a property/init param, that are internally holding onto the block properties. Inside the objectWithCompletionHandler method, where someObject holds onto the completionHandler block as an instance variable, there are multiple references to self there that I do know would cause a leak. My main question is in such a case, how would you need to handle weakify and strongify to make it "safer"? Would one @weakify and @strongify call each be sufficient, like the following:

- (void)someMethod {
    @weakify (self);

    _someObjectInstanceVar = [Object objectWithCompletionHandler:^{
        @strongify(self);
    ...
}

以上 @strongify(self)引用足以用于自引用#1,2,3和4,或者我必须(甚至可以工作)获得一个新的弱/强引用在 sendAWithID 方法内使用,嵌套 reloadData

Would the above @strongify(self) reference be sufficient to use for self references #1, 2, 3, and 4, or do I have to (and would it even work) get a new weak/strong reference to use inside the sendAWithID method and the nested reloadData?

编辑:固定代码让问题更有意义并修复一些语法错误。

Fixed code to have question make more sense and fix some syntax errors.

推荐答案

如何 @ strongify 有效



调用 @strongify 后, self 块中 块内的指针地址不同于块 块。那是因为 @strongify 每次都声明一个名为 self 的新局部变量。 (这就是它抑制 -Wshadow 警告的原因,它会在局部变量影响另一个局部变量时发出警告。)值得阅读和理解这些功能的实现。因此,即使名称相同,也将它们视为单独的引用。

How @strongify works

After @strongify is called, self will have a different pointer address inside the block than it will outside the block. That's because @strongify declares a new local variable called self each time. (This is why it suppresses the -Wshadow warning, which will "warn whenever a local variable shadows another local variable.") It's worth reading and understanding the implementation of these functions. So even though the names are the same, treat them as separate strong references.

预先假定(这不是真的)每次使用一个块都会创建一个参考周期,你可以:

Presupposing (which is not true) that each use of a block would create a reference cycle, you could:

- (void)someMethod {
    if (self.someBOOL) {
        @weakify(self);
        _someObjectInstanceVar = [Object objectWithCompletionHandler:^{
            @strongify(self);
            // self reference #1
            if (self.someProperty) {
                @weakify(self);
                // self reference #2
                [[Async HTTPRequest] sendAWithID:self.property.id completionHandler:^(void (^)(NewObject *newObject) {
                    @strongify(self);
                    // self reference #3
                    @weakify(self);
                    [self showViewWithObject:newObject handler:^{
                        // self reference #4
                        @strongify(self);
                        [self reloadData];
                    }];
                }];
            }
        }];
    // etc…
}

但是,请记住第一次使用之后的 @strongify self 将引用本地堆栈变量。当它们定义的范围结束时,它们通常会被销毁(只要您不将它们存储到属性或在嵌套块中使用它们。那么基于您的代码显示,你只需要 //自我引用#1

However, remember that after your first use of @strongify, self will refer to local, stack variables. These will typically get destroyed when the scope in which they're defined ends (as long as you aren't storing them to properties or using them in a nested block). So based on the code you showed, you only need it after // self reference #1.

阅读单元测试 @weakify @strongify 将有助于澄清这些功能的正确用法。

Reading the unit test covering @weakify and @strongify will help clarify the correct usage of these functions.

这篇关于iOS正确使用@weakify(self)和@strongify(self)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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