最近我被扔进了别人的代码库,我已经能够处理到目前为止它抛出的大多数事情,但这个有点过头了。有一些保留周期我不知道如何解决。
有一个包装 FROAuthRequest 的自定义对象,FROAuthRequest 有一个完成块,其中还使用了 3 个块,一个解析块、完成块和失败块。完成、完成和失败块都导致了一个保留周期。
我知道原因是对块内 ivars 的引用,但我尝试过的方法没有奏效,请参阅帖子末尾的我尝试过的内容。
以下代码是我开始尝试修复它之前的样子。代码路径如下:
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 方法 (1) 返回 SHRequest,就设置完成和失败块。(对于这种情况,没有设置 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];
}
关于我做错了什么的任何想法?