最近、私は他の誰かのコードベースに落とされました。これまでに投げ出されたほとんどのことに取り組むことができましたが、これは少し頭がおかしいです。修正方法がわからない保持サイクルがいくつかあります。
FROAuthRequestをラップするカスタムオブジェクトがあります。FROAuthRequestには、解析、終了、失敗のブロックの3つのブロックが使用される完了ブロックがあります。完了、終了、および失敗のブロックはすべて、保持サイクルを引き起こしています。
原因はブロック内のivarへの参照であることがわかっていますが、試したものが機能しませんでした。試した内容については、投稿の最後を参照してください。
次のコードは、修正を開始する前の状態です。コードパスは次のようになります。
1:リクエストを作成します:
//in the MainViewController.m
SHRequest *request = [api userInfo];
2:SHRequestを作成するメソッド
//in API.m
-(SHRequest*)userInfo{
FROAuthRequest *request = [[FROAuthRequest alloc]initWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@%@",SH_URL_API,SH_URL_USER_INFO]]
consumer:consumer
token:token
realm:nil
signatureProvider:signatureProvider];
//wrap the FROAuthRequest in our custom object
//see below for the SHRequest
SHRequest *shRequest = [[SHRequest alloc]initWithRequest:request];
//set the parsing block
shRequest.parsingBlock = ^id(FROAuthRequest* finishedRequest){
NSDictionary *jsonResponse = [finishedRequest.responseData objectFromJSONData];
[user release];
user = [[SHUser alloc]initWithJSON:[jsonResponse objectForKey:@"user"]];
//more code
return [NSDictionary dictionaryWithObjectsAndKeys:user,kUserKey,nil];
};
[request release];
return [shRequest autorelease];
}
3:SHRequest
//in SHRequest.m
-(id)initWithRequest:(FROAuthRequest*)_underlyingRequest{
if(self = [super init]){
underlyingRequest = [_underlyingRequest retain];
//this is the majority of the post processing
underlyingRequest.completionBlock = ^{
//if the requests fails call the fail block
if(underlyingRequest.responseStatusCode != 200){
if(failBlock != nil)
failBlock();
return;
}
if([underlyingRequest.responseData length] > 0){
[object release];
object = parsingBlock(underlyingRequest);
[object retain];
if((underlyingRequest.error || !object) && failBlock != nil)
failBlock();
else if(finishBlock != nil)
finishBlock();
}else if(failBlock != nil)
failBlock();
};
underlyingRequest.failedBlock = ^{
if(failBlock)
failBlock();
};
}
return self;
}
4:userInfoメソッドからSHRequestが返されると(1)、終了ブロックと失敗ブロックが設定されます。(この場合、failBlockは設定されていません。
//in MainViewController.m
request.finishBlock = ^{
NSDictionary *userInfo = request.object;
//User
SHUser *user = [userInfo objectForKey:kUserKey];
//more code
};
[request send];
これが私が試したものです
。completionBlockコードをリクエストを開始するメソッドに移動し、__ blockタイプを使用しました。リークは消えたように見えますが、完了ブロックの実行時に__block変数の一部はゾンビです。
//in SHRequest.m
-(void)send{
__block void(^fail)(void) = failBlock;
__block void(^finish)(id) = finishBlock;
__block id(^parsing)(FROAuthRequest*) = parsingBlock;
__block FROAuthRequest *req = underlyingRequest;
underlyingRequest.completionBlock = ^{
if(req.responseStatusCode != 200){
if(fail != nil)
fail();
return;
}
if([req.responseData length] > 0){
id obj = parsing(req);//<--- parsing is a zombie
if((req.error || !obj) && fail != nil)
fail();
else if(finish != nil)
finish(obj);//<--- finish is a zombie
}else if(fail != nil)
fail();
};
underlyingRequest.failedBlock = ^{
if(fail)
fail();
};
[underlyingRequest startAsynchronous];
}
私が間違っていることについて何か考えはありますか?