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