我有一个在函数内部声明的对象。该对象进行具有完成块的函数调用。功能正常执行。
此函数进行网络调用(在另一个类中)。从网络调用中获取结果后,我正在检查该类是否仍在内存中(使用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);
}
}];
}
}
答案 0 :(得分:1)
我知道如果我使用类方法或属性变量,可以解决此问题。但是有什么方法可以保留该对象(在函数内部声明)。我尝试使用
__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
时会发生什么?
LocalClass
的新实例,并将对它的引用存储在object
中。 object
的类型隐式为__strong LocalClass *
,因此新实例对其有很强的引用,并且将继续存在。aMethodWithCompletionBlock:
引用的对象调用方法object
,并将其传递给闭包。 请注意,methodA
或AViewController
的实例都没有被调用来保留对此闭包的引用,它只是传递给方法。因此,在调用之后,不可能在属于methodA
的局部变量或属于AViewController
的实例变量与闭包之间建立引用循环。 在第12行,methodToMakeRESTRequestOnComplete:
的方法NetworkClass
被称为传递闭包
self
,因此它包含对引用LocalClass
的{{1}}实例的强引用aMethodWithCompletionBlock:
的相同实例,因此现在对该对象有两个强大的引用。LocalClass
引用的块的强引用在第20行completionHandler
返回,因为传递的块是完成块,所以不太可能被调用。因此,在这一点上,methodToMakeRESTRequestOnComplete:
引用了该完成块,而完成块引用了NetworkClass
实例。
LocalClass
返回。调用它的aMethodWithCompletionBlock:
实例未保留对参数LocalClass
的引用。completionHandler
返回。这将破坏其局部变量methodA
,从而将强引用丢弃到其引用的object
实例。此时系统可以考虑销毁该实例,但是,因为LocalClass
对完成块有很强的引用,而对完成块有很强的引用NetworkClass
实例仍然需要并且未被销毁。LocalClass
调用其保留的块引用之后的某个将来的时间线14处。 NetworkClass
变量强烈引用了最初在第4行创建的self
实例,因此该实例仍然存在并且一切都很好。LocalClass
放弃了对块的强引用,则可以(可能–假设没有其他对它的强引用)销毁该块。破坏消除了该块对其NetworkClass
和self
所引用的对象的强引用,因此这些对象也可以(可能...)被破坏,并且最初在第4行创建的对象会咬住对象。灰尘。没有有害的循环,不需要任何弱引用来管理它们。
HTH