在返回完成块之前,本地对象变为 nil - Objective C

Local Object became nil before returning completion block - Objective C

我有一个在函数内部声明的对象。此对象进行具有完成块的函数调用。该函数正确执行。

此函数进行网络调用(在另一个 class 中)。从网络调用获得结果后,我正在检查 class 是否仍在内存中(使用 weakSelf 和 strongSelf)

在检查过程中,显示​​ self 为 nil。

我知道如果我使用 class 方法或 属性 变量我可以解决这个问题。但是有没有办法保留这个对象(在函数内部声明)。 我用对象尝试了 __strong 和 __block,但没有用。

这是我的代码

@implementation AViewController {
        -(void)viewWillAppear:(BOOL)animated {
            [super viewWillAppear:animated];
            [self methodA];
        }
        -(void)methodA {
            LocalClass *object = [LocalClass alloc] init];
            [object aMethodWithCompletionBlock:^(NSDictionay *result) {

            }];

        }
    }
    @implementation LocalClass {
        - (void)aMethodWithCompletionBlock:(void (^)(NSDictionay *result))completionHandler {

            __weak typeof(self) weakSelf = self;
            [NetworkClass methodToMakeRESTRequestOnComplete:^(NSDictionay *someResult) {
                __strong typeof(self) strongSelf = weakSelf;
            if(!strongSelf) { // this check fails as strongSelf is nil
                return;
            }

            //some code execution
            if (completionHandler != nil) {
                completionHandler(someModifiedResult);
            }
            }];
        }
    }

I know if I use a class method or property variable I can resolve this. but is there any way to retain this object (which declared inside a function). I tried __strong and __block with the object, but not working.

您的代码试图解决一个不存在的问题,但这样做却产生了一个问题。

weakSelf/strongSelf 模式的目的是处理有害的 引用循环(并非所有引用循环都是有害的,确实有些是有用的).仅当您确定存在这种有害循环时才应使用它。

让我们看看没有任何 weakSelf/strongSelf 舞蹈的代码:

 1 @implementation AViewController
 2 {
 3    -(void)methodA
 4    {  LocalClass *object = [LocalClass alloc] init];
 5       [object aMethodWithCompletionBlock:^(NSDictionay *result) { ... }];
 6    }
 7 }
 8 
 9 @implementation LocalClass
10 {
11    - (void)aMethodWithCompletionBlock:(void (^)(NSDictionay *result))completionHandler
12    {  [NetworkClass methodToMakeRESTRequestOnComplete:^(NSDictionay *someResult)
13       {
14          if (!self)
15             return;
16 
17          //some code execution
18          if (completionHandler != nil)
19             completionHandler(someModifiedResult);
20       }];
21    }
22 }

现在当你有一个 AViewController 的实例并调用 methodA 时会发生什么?

  1. 在第 3 行,创建了 LocalClass 的新实例,并将对它的引用存储在 object 中。 object 的类型是隐式的 __strong LocalClass * ,因此新实例对其有强引用并将保持活动状态。
  2. 在第 5 行,在 object 引用的对象上调用方法 aMethodWithCompletionBlock: 并将其传递给闭包。 请注意,methodA 或被调用的 AViewController 的实例都没有保留对此闭包的引用,它只是传递给方法。因此在调用之后,属于 methodA 的局部变量或属于 AViewController 的实例变量与闭包之间不可能存在引用循环。
  3. 在第 12 行,NetworkClass 的方法 methodToMakeRESTRequestOnComplete: 被调用并传递一个闭包

    • 此闭包引用了 self,因此它包含对调用 aMethodWithCompletionBlock:LocalClass 实例的强引用
    • 这是在第 3 行创建的 LocalClass 相同 实例,因此现在有两个对该对象的强引用。
    • 闭包还包含对参数引用的块的强引用completionHandler
  4. 在第 20 行 methodToMakeRESTRequestOnComplete: returns,因为传递的块是一个完成块,所以它不太可能被调用。所以此时 NetworkClass 引用了那个完成块,并且完成块引用了 LocalClass 实例。

  5. 第 21 行 aMethodWithCompletionBlock: returns。调用它的 LocalClass 实例没有保留对参数 completionHandler.
  6. 的引用
  7. 第 6 行 methodA returns。这会破坏它的局部变量 object,从而删除对它引用的 LocalClass 实例的强引用。系统可以考虑此时销毁该实例,但是因为NetworkClass对完成块有很强的引用,而完成块又具有对同一个 LocalClass 实例的强引用,它仍然需要并且不会被销毁。
  8. 在将来的某个时间,在 NetworkClass 调用它保留的块引用后到达第 14 行。 self 变量包含对最初在第 4 行创建的 LocalClass 实例的强引用,因此该实例仍然存在并且一切都很好。
  9. 在第 20 行,完成块 returns。如果此时 NetworkClass 删除了它对该块的强引用,则该块可能会被销毁(可能——假设没有其他强引用指向它)。该破坏删除了块对其 selfcompletionHandler 引用的对象的强引用,因此这些对象也可以(可能...)被销毁并且最初在第 4 行创建的对象咬住灰尘.

没有有害循环,不需要任何弱引用来管理它们。

HTH