Reputation: 1263
I run the instruments tool and get some Memory Leaks and i don´t know how to handle this. I´m using ARC!
This is my Code:
+ (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;
}
And here my 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];
}
EDIT:
I changed my Code to this now, but sadly it still gives me a Memory Leak....
+ (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;
}
Upvotes: 3
Views: 1917
Reputation: 69027
EDIT: after your changes, the explanation for the leak is the following:
You have a circular dependency between your GFRequest
object and the NSURLConnection
object, thus preventing both from being correctly deallocated. Indeed, you are setting the GFRequest
's connection property to a NSURLConnection
instance:
r.connection = [[NSURLConnection alloc] initWithRequest:[NSURLRequest requestWithURL:r.url]
while at the same time also making the r
be the delegate of that NSURLConnection
:
delegate:r
What happens is that NSURLConnection
's delegate does a retain on its delegate, and this is causing the dependency cycle.
I do not see an easy way to break the dependency, though, and keep your current design.
You could simply avoid storing your connection inside of the request, or you could not use the request as a delegate for the connection. Possibly, you should consider the possibility of subclassing NSURLConnection
and have it act as a delegate to itself.
OLD ANSWER:
There is a mismatch between the outer method name and the inner one:
+ (MARequest *)requestImageThumb:(NSString *)imageName
…
return [MARequest createWithURL:[NSURL URLWithString:urlString]
For the static analyser those have different semantics as to object ownership.
Replace the first one with:
+ (MARequest *)createRequestImageThumb:(NSString *)imageName
or the second one with:
return [MARequest requestWithURL:[NSURL URLWithString:urlString]
Depending on which semantics is proper for you case.
Upvotes: 2
Reputation: 481
Sounds like what is going on is that you have started the method with the word create
which indicates to ARC that it will return an object with a retain count of 1. In other words, create
indicates that the caller is going to be responsible for releasing the object when it is done.
But then you return this object directly inside another method that does not start with create
. And this indicates that if the caller of this second method should be retaining the object if it wants to keep it around.
There is a conflict here and I think ARC does not know what to do. Should it be releasing the object or not?
If you rename +createWithURL:type:
to +requestWithURL:type:
this should fix it because +requestWithURL:type:
will return an autoreleased object, which is what +requestImageThumb:object:
is expecting to return.
Alternatively, rename +requestImageThumb:object:
to +createRequestWithImageThumb:object:
to explicitly ask +createRequestWithImageThumb:object:
to return a retained object, which it is getting from +createWithURL:type:
.
Upvotes: 1