我有一个在函数内声明的对象。 此对象进行具有完成块的函数调用。 函数正确执行。
此函数进行网络调用(在另一个类中)。 从网络调用中获取结果后,我正在检查该类是否仍在内存中(使用 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
时会发生什么?
- 在第 3 行,将创建一个
LocalClass
的新实例,并将对它的引用存储在object
中。object
的类型是隐式__strong LocalClass *
的,因此新实例具有对它的强引用,并将保持活动状态。 - 在第 5 行,方法
aMethodWithCompletionBlock:
被调用的对象,方法是通过object
向其传递闭包来调用它。请注意,methodA
或AViewController
调用它的实例都不会保留对此闭包的引用,它只是传递给该方法。因此,在调用之后,属于methodA
的局部变量或属于AViewController
的实例变量与闭包之间不可能出现引用循环。 在第 12 行,
NetworkClass
的方法methodToMakeRESTRequestOnComplete:
称为传递闭包- 此闭包引用
self
因此它包含对调用aMethodWithCompletionBlock:
的LocalClass
实例的强引用 - 这与在第 3 行创建的
LocalClass
实例相同,因此现在有两个对该对象的强引用。 - 闭包还包含对参数
completionHandler
引用的块的强引用
- 此闭包引用
在第 20 行
methodToMakeRESTRequestOnComplete:
返回,因为传递的块是一个完成块,所以不太可能被调用。因此,此时NetworkClass
具有对该完成块的引用,并且完成块具有对LocalClass
实例的引用。- 在第 21 行返回
aMethodWithCompletionBlock:
。调用它的LocalClass
实例没有保留对参数completionHandler
的引用。 - 在第 6 行
methodA
返回。这会破坏其局部变量object
这会删除对它引用的LocalClass
实例的强引用。此时系统可以考虑销毁该实例,但是由于NetworkClass
具有对完成块的强引用,而完成块又对同一LocalClass
实例具有强引用,因此仍然需要而不是销毁。 - 在将来的某个时间线,
NetworkClass
调用它保留的块引用后到达 14。self
变量包含对最初在第 4 行创建的LocalClass
实例的强引用,因此该实例仍然存在,并且世界一切正常。 - 在第 20 行返回完成块。如果此时
NetworkClass
删除了对块的强引用,则该块可能会被销毁(可能 - 假设没有其他对它的强引用)。这种破坏消除了块对其self
和completionHandler
引用的对象的强引用,因此这些对象也可以(可能......)被销毁,并且最初在第 4 行创建的对象咬了灰尘。
没有有害的循环,不需要任何弱引用来管理它们。
呵呵