本地对象在返回完成块之前变为零 - 目标 C



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

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

在此检查期间,它显示,自我为零。

我知道如果我使用类方法或属性变量,我可以解决这个问题。 但是有没有办法保留这个对象(在函数中声明)。 我尝试__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);
}
}];
}
}
我知道

如果我使用类方法或属性变量,我可以解决这个问题。 但是有没有办法保留这个对象(在函数中声明)。我尝试__strong__block该对象,但不起作用。

您的代码正在尝试解决一个不存在的问题,并且这样做会创建一个问题。

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 行,方法aMethodWithCompletionBlock:被调用的对象,方法是通过object向其传递闭包来调用它。请注意,methodAAViewController调用它的实例都不会保留对此闭包的引用,它只是传递给该方法。因此,在调用之后,属于methodA的局部变量或属于AViewController的实例变量与闭包之间不可能出现引用循环。
  3. 在第 12 行,NetworkClass的方法methodToMakeRESTRequestOnComplete:称为传递闭包

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

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

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

呵呵

相关内容

最新更新