ControllerMediatorClassはClassThatDealsWithNetworkingのインスタンスの完了ブロックとして機能するため、MyUIViewControllerがnilに設定しても、'ControllerMediatorClass'のインスタンスはすぐに割り当て解除されませんか?
はい。ブロックは、使用するオブジェクトを自動的にキャプチャし、ブロックが保持されている限りそれらを保持するためです。
したがって、[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
の例では)、ブロックが存在する限り、ブロック自体によって暗黙的に保持されself
ます。これは、ブロックの本体のどこかに参照があるためです。したがって、コンパイラは、ブロックが実行されたときにそれが必要になることを認識し、それを保持します。また、ブロックが解放されると、暗黙的に解放されます。
これにより、ブロックの実行時にブロックの本体で使用するすべてのオブジェクトが引き続き存在し、クラッシュを回避できます。
注意しないと、保持サイクルにつながる可能性があることに注意してください。たとえばself.completionBlock = nil
、ClassThatDealsWithNetworking
クラス(デリゲートメソッドまたはdealloc
メソッド)で自分自身を忘れた場合、ブロックはClassThatDealsWithNetworking
インスタンスによって解放されることはなく、保持し続けself
ます。
詳細については、AppleのドキュメントのBlocksProgrammingGuideを参照してください。