当UIViewController创建的类作为另一个类的完成块时,当UIViewController获取dealloc调用时,内存管理生命周期如何工作?
假设UIViewController继承类实例化一个类ControllerMediatorClass。
ControllerMediatorClass又调用另一个类ClassThatDealsWithNetworking,其工作需要一些时间才能完成。
如果UIViewController在ClassThatDealsWithNetworking完成之前获取其dealloc,那么其所有权下的类何时会被清除?
当MyUIViewController将它设置为nil时,是否会立即释放'ControllerMediatorClass'的实例,因为ControllerMediatorClass仍然作为ClassThatDealsWithNetworking实例的完成块?
MyUIViewController:
@property (nonatomic, strong) ControllerMediatorClass *mediatorClass;
- (IBAction)userTappedSomething
{
[mediatorClass makeANetworkCall];
}
- (void)dealloc
{
self.mediatorClass = nil;
}
ControllerMediatorClass:
- (void)makeANetworkCall
{
ClassThatDealsWithNetworking *networkCommand;
[networkCommand execute:^(NSDictionary *data)
{
// handling completion that
} error:^(MyError *error)
{
// handling completion
}
];
}
(使用ARC)
答案 0 :(得分:0)
当MyUIViewController将它设置为nil时,是否会立即释放'ControllerMediatorClass'的实例,因为ControllerMediatorClass仍然作为ClassThatDealsWithNetworking实例的完成块?
是。因为块会自动捕获它使用的对象,并且只要保留块就会保留它们。
因此,[ClassThatDealsWithNetworking execute:]
方法可能会保留传递给它的完成块,然后在后台执行网络调用,然后在块完成后调用块并释放块此块中使用的每个变量也会保留。当块被释放时将被释放。
想象一下这个ClassThatDealsWithNetworking
类的伪代码:
typedef void(^NetworkingCompletionBlock)(NSDictionary* data)
@interface ClassThatDealsWithNetworking
@property(nonatomic, copy) NetworkingCompletionBlock completionBlock;
-(void)execute:(NetworkingCompletionBlock)block;
@end
@implementation ClassThatDealsWithNetworking
-(void)execute:(NetworkingCompletionBlock)block {
// make a copy of the block passed as a parameter
// so that we keep the completionBlock around inside
// the ClassThatDealsWithNetworking instance
// until the network request has finished
// ==> THIS WILL implicitly RETAIN every object used in the completionBlock
self.completionBlock = block;
...
// Then perform the network request
[NSURLConnection connectionWithRequest:... delegate:self];
...
}
-(void)connection:(NSURLConnection*)cxn didFailWithError:(NSError*)error
{
// call the completion block here
self.completionBlock(nil,error);
// then release the completionBlock
// ==> THIS WILL RELEASE every object previously implicitly retained by the completionBlock
self.completionBlock = nil;
}
-(void)connectionDidFinishLoading:(NSURLConnection*)cxn
{
NSDictionary* data = ...
// call the completion block here
self.completionBlock(data,nil);
// then release the completionBlock
// ==> THIS WILL RELEASE every object previously implicitly retained by the completionBlock
self.completionBlock = nil;
}
@end
然后,如果你这样做:
[networkCommand execute:^(NSDictionary *data)
{
self.someProperty = data;
} error:^(MyError *error)
{
NSLog(@"%@", error);
self.someProperty : nil;
}];
然后self
(您示例中的ControllerMediatorClass
)将被本身隐式保留,只要该块存在,因为您的引用{{1}在某个地方的街区。因此编译器知道在执行块时它将需要它并保留它。并且当块发布时将被隐式释放。
这可以确保在执行块时块中正在使用的所有对象仍然存在,从而避免崩溃。
请注意,如果您不小心,这可能会导致保留周期。例如,如果您忘记self
类中的自self.completionBlock = nil
(在委托方法或ClassThatDealsWithNetworking
方法中),则dealloc
永远不会释放该块实例,并将继续保留ClassThatDealsWithNetworking
。
有关详细信息,请阅读Apple文档中的Blocks Programming Guide。