NSURLConnection内存泄漏

时间:2014-06-23 14:46:41

标签: ios objective-c memory-management memory-leaks nsurlconnection

我运行乐器工具并获得一些内存泄漏,我不知道如何处理这个问题。我正在使用ARC!

这是我的代码:

+ (MARequest *)requestImageThumb:(NSString *)imageName
                      object:(NSInteger)objectId {
   NSString* urlString = [NSString stringWithFormat:@"%@/%@", kBaseImageThumbURL, imageName];

   LogTrace(@"Creating image thumb request for file %@", imageName);

   //Here starts the leak!!
   return [MARequest createWithURL:[NSURL URLWithString:urlString]
                           type:REQUEST_TYPE_GET_IMAGE];
}


+ (MARequest *)createWithURL:(NSURL *)url
                    type:(NSInteger)type {

   MARequest* r = [[MARequest alloc] init];

   r.url = url;
   r.requestType = type;
   r.responseData = [[NSMutableData alloc] init];
   r.connection = [[NSURLConnection alloc] initWithRequest:[NSURLRequest requestWithURL:r.url]
                                               delegate:r
                                       startImmediately:NO];

   return r;
}

这是我的NSURLConnectionDelegate

#pragma mark - NSURLConnectionDelegate
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
   LogTrace(@"request %@: didReceiveResponse", self.url);
   [self.responseData setLength:0];
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
   LogTrace(@"request %@: didReceiveData, %d bytes", self.url, data.length);

   [self.responseData appendData:data];
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
   LogTrace(@"request %@: didFailWithError: %@", self.url, [error description]);

   self.connection = nil;
   self.failed = YES;

[self invokeAction];
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
   LogTrace(@"request %@: connectionDidFinishLoading, %d bytes", self.url, [self.responseData length]);
   self.connection = nil;

   [self invokeAction];
}

修改

我现在把我的代码更改为了这个,但遗憾的是它仍然给了我一个内存泄漏......

+ (MARequest *)requestImageThumb:(NSString *)imageName
                      object:(NSInteger)objectId {
    NSString* urlString = [NSString stringWithFormat:@"%@/%@", kBaseImageThumbURL, imageName];

    LogTrace(@"Creating image thumb request for file %@", imageName);

    return [MARequest requestWithURL:[NSURL URLWithString:urlString]
                           type:REQUEST_TYPE_GET_IMAGE];
}

+ (MARequest *)requestWithURL:(NSURL *)url
                    type:(NSInteger)type {

   MARequest* r = [[MARequest alloc] init];

   r.url = url;
   r.requestType = type;
   r.responseData = [[NSMutableData alloc] init];
   r.connection = [[NSURLConnection alloc] initWithRequest:[NSURLRequest requestWithURL:r.url]
                                               delegate:r
                                       startImmediately:NO];



   return r;
}

2 个答案:

答案 0 :(得分:2)

编辑:更改后,泄漏的解释如下:

您的GFRequest对象与NSURLConnection对象之间存在循环依赖关系,因此无法正确释放这两者。实际上,您要将GFRequest的连接属性设置为NSURLConnection实例:

   r.connection = [[NSURLConnection alloc] initWithRequest:[NSURLRequest requestWithURL:r.url]

同时也让r成为NSURLConnection的代表:

             delegate:r

NSURLConnection's delegate does a retain on its delegate会发生什么,这会导致依赖性循环。

但是,我没有看到一种简单的方法来打破依赖性,并保留您当前的设计。

您可以简单地避免在请求中存储连接,或者您无法将请求用作连接的委托。可能,您应该考虑子类化NSURLConnection的可能性,并让它充当自己的委托。

老答案:

外部方法名称与内部名称之间存在不匹配:

+ (MARequest *)requestImageThumb:(NSString *)imageName
…
   return [MARequest createWithURL:[NSURL URLWithString:urlString]

对于静态分析器,它们具有与对象所有权不同的语义。

将第一个替换为:

+ (MARequest *)createRequestImageThumb:(NSString *)imageName

或第二个:

   return [MARequest requestWithURL:[NSURL URLWithString:urlString]

取决于适合您的语义。

答案 1 :(得分:1)

听起来就是你已经用create这个词启动了方法,它向ARC表明它将返回一个保留计数为1的对象。换句话说,create表示调用者将在完成后释放对象。

然后你直接在另一个 not create开头的方法中返回这个对象。这表明如果第二种方法的调用者应该保留该对象,如果它想要保留它。

这里存在冲突,我认为ARC不知道该怎么做。它应该是否释放物体?

如果您将+createWithURL:type:重命名为+requestWithURL:type:,则应该修复它,因为+requestWithURL:type:将返回一个自动释放的对象,这是+requestImageThumb:object:期望返回的对象。

或者,将+requestImageThumb:object:重命名为+createRequestWithImageThumb:object:,明确要求+createRequestWithImageThumb:object:返回保留对象,该对象来自+createWithURL:type: