I'm using CLGeocoder, and I'm using a block as a completion handler. I'm unsure of the retain/release cycle for the instance of CLGeocoder that I create.
Here's the basic code:
CLGeocoder* geocoder = [[CLGeocoder alloc] init];
[geocoder reverseGeocodeLocation:newLocation completionHandler:
^(NSArray* placemarks, NSError* error)
{
// process the placemarks...
[geocoder autorelease];
}
];
Is autoreleasing the geocoder as the last line of the block the recommended way to handle this? Any suggestions are appreciated!
You can just release it (no need for auto release) Auto release is for when you are unsure when you will need to release an object (such as returning an object at the end of a method or for convenience methods)
In this case you are certain that you are done using the object so it may be released. Of course, autorelease works too, but lingers around in memory longer.
Related
I have a singleton object in my app:
+ (id)shared {
#synchronized(self) {
if (sharedDownloadFirstData == nil)
sharedDownloadFirstData = [[self alloc] init];
}
return sharedDownloadFirstData;
}
- (id) init {
if (self = [super init]) {
}
return self;
}
And I want to know if I need to realese it (I am not using ARC). To do that I am using:
[[DownloadFirstData shared] release];
Did I need to release this object? I have an array and other stuff in the object that I need to release.
In Objective-C, you should only ever call release on an object you own. This typically means an object you've created with alloc, init, copy or mutableCopy or otherwise called retain on. Here, the consumer of [DownloadFirstData shared] didn't call any of those functions and is not responsible for releasing it. You will see this any time you call [UIColor blackColor], for instance.
You may want to call retain on such an object, if you are crossing autorelease boundaries or are just not sure of the lifetime:
DownloadFirstData *local = [[DownloadFirstData shared] retain];
...
[local release];
In this case, you've taken ownership and are responsible for releasing.
But what about the definition of shared? When you define a method not using init..., you are typically responsible for leaving with a release count of 0, with something like [[self alloc] init] autorelease]. This is not the case for the singleton because your goal is for it to always exist and therefore always have a non-zero retain count. You make this happen simply by not releasing it after you create it.
there is no sense in having a singleton if you will release it.
Usually a singleton is created because you want the same object till the app ends.
At the end of your app life cycle all memory related to the app is freed.
Use a standard approach, if you need alloc release often.
if your singleton takes a lot of memory, you should consider to write it better.
anyway, [[DownloadFirstData shared] release]; will work.
While I realize one is a class method and the other an instance method, they have the exact same description in the Apple docs so I'm not quite understanding the different syntax/use cases.
Their functionality is equivalent, but the class method returns an autoreleased object. That is, it's probably implemented along the lines of:
+ (NSFetchRequest *)fetchRequestWithEntityName:(NSString *)entityName {
return [[[NSFetchRequest alloc] initWithEntityName:entityName] autorelease];
}
This is a fairly common pattern in Objective-C libraries known as Class Factory methods.
Based on what you said, if they really have the same use case, the only difference has to do with the garbage collection on objective-C, according to the memory management design Apple uses.
Whenever you call an init method over an object, you own it and you are responsible for releasing it when you no longer need the object.
When you call any other kind of method that returns an object, that object is added to a NSAutoreleasePool, and it is autoreleased when the pool gets drained.
You can get more insights here.
So, following Apple's way, if you don't want so save the object for further use, you can call fetchRequestWithEntityName and not worry about releasing the object at the end of the method call. If you want to save it as an instance variable, you call the initWithEntityName method . They can, of course be interchanged, but this approach follows apple guidelines in what comes to memory management.
-(void)myMethod {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
id obj1 = [[Object alloc] initWithEntityName:...];
id obj2 = [Object fetchRequestWithEntityName:...];
//obj1 retain count is +1
//obj2 retain count is +0 (likely autoreleased)
[pool drain];
//obj1 still exists
//obj2 is no longer valid; may or may not have been deallocated
}
So basically, fetchRequestWithEntityName is achieved by:
+(id)fetchRequestWithEntityName:... {
return [[[self class] alloc] initWithEntityName:...] autorelease];
}
The main difference between those two API is as below:
fetchRequestWithEntityName will give you an autorelease object, so once the event loop is over it will be deallocated from the memory until you retain it.
But initWithEntityName will give you object which is to be released by you otherwise there will be memory leak.
I have a question about Grand Central Dispatch, blocks and memory management. Consider this code:
Worker *myWorker = [[Worker alloc] init];
[work doAsyncStuffWithBlock:^(NSMutableDictionary *info)
{
NSLog(#"processing info results");
}];
[myWorker release];
Here, I want the doAsyncStuffWithBlock to happen asynchronously and then perform the block when it has some results. Meanwhile this main code will continue on. Is it safe here to release myWorker? Will the dispatch_queue I implement internally keep a reference of it around to eventually execute that block? Or, should I release it inside the block? that seems weird. Thanks for any suggestions.
When a block references an Objective-C object, e.g.:
Worker *myWorker = [[Worker alloc] init];
[work doAsyncStuffWithBlock:^(NSMutableDictionary *info)
{
NSLog(#"processing info results");
[myWorker doSomething];
}];
[myWorker release];
it automatically retains that object and, when the block is released, it automatically releases that object.
So yes, you should release myWorker in your code, and no, you shouldn’t release myWorker inside the block.
Read
this
or this
You can release outside the block.
I'm wondering how bad is the following code for experienced objective-C programmers.
self.request = [[ASIHTTPRequest alloc] initWithURL:url];
[self.request release];
It is definitely less verbose this
ASIHTTPRequest *tmp = [[[ASIHTTPRequest alloc] initWithURL:url];
self.request = tmp;
[tmp release];
But I'm not sure if it is meaningful enough or doesn't lead to bugs.
What do you think?
UPDATE:
I don't want to use autorelase pools as my app is going to run on iphone where memory is limited.
UPDATE: I don't want to use autorelase pools as my app is going to run on iphone where memory is limited.
Do use the autorelease pools! Cocoa touch framework itself uses them; making one or two autorelease'ed objects yourself doesn't change the big picture.
It's true Apple warns you against excessive reliance on autorelease pools on iPhone, like putting hundreads of objects before the pool gets drained after the conclusion of the event dispatch, but excessive avoidance of autorelease pools is also counter-productive!
Nothing is black and white; nirvana is in the middle way.
Why not this?
self.request = [[[ASIHTTPRequest alloc] initWithURL:url] autorelease];
Or, if this is a class you wrote or have the source for, create a new class method (not instance) that does essentially the same thing (assuming NSURL * argument):
+ (ASIHTTPRequest *) requestWithURL:(NSURL *)url
{
return [[[self alloc] initWithURL:url] autorelease];
}
Definitely go with the latter, although choose a more descriptive name instead of tmp. You are responsible for releasing tmp, but you are not responsible for releasing self.request, at least not in the context given.
Alternatively, if you don't mind adding things to the autorelease pool, simply do:
self.request = [[[ASIHTTPRequest alloc] initWithURL:url] autorelease];
or
self.request = [ASIHTTPRequest requestWithURL:url];
What you missed is not the difference in verbosity but the memory management difference.
You often see code like this:
ASIHTTPRequest * requestTmp = [[[ASIHTTPRequest alloc] initWithURL:url];
self.request = requestTmp;
[requestTmp release];
You should consider what is happening if the property is retained and old one released in the setter method.
What this mean is that you create new request, refcount is 1.
self.request = request, now if setRequest looks like:
- (void)setRequest:(ASIHTTPRequest*)aReq
{
[aReq retain];
[request release];
request = aReq;
}
This means that the object retained the requestTmp you passed in and released the old one. Refcount of requestTmp is now 2.
After this call you can then release your original requestTmp that you created and you are safe because the object retained the requestTmp - refcount is still 1.
However if you do this:
self.request = [[ASIHTTPRequest alloc] initWithURL:url];
[self.request release];
you end up releasing the request that the object retained for its use. Note that you are release object's internal request where in the original case you released the tmp but the object keeps it's own retained reference.
So the result is different from the original code.
I am creating instances of a class FlickrImage parsing a Flickr API photos response. The class has a method getLocation that does another API call to get the geolocation:
NSLog(#"getting location for %i",self.ID);
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
OFFlickrAPIRequest *flickrAPIRequest = [[OFFlickrAPIRequest alloc] initWithAPIContext[appDelegate sharedDelegate].flickrAPIContext];
[flickrAPIRequest setDelegate:self];
NSString *flickrAPIMethodToCall = #"flickr.photos.geo.getLocation";
NSDictionary *requestArguments = [[NSDictionary alloc] initWithObjectsAndKeys:FLICKR_API_KEY,#"api_key",self.ID,#"photo_id",nil];
[flickrAPIRequest callAPIMethodWithGET:flickrAPIMethodToCall arguments:requestArguments];
[pool release];
I have implemented the callback method that would catch the response from the API and update the FlickrImage instance with the geolocation data - but it never gets called. Here's where the instances get created:
NSDictionary *photosDictionary = [inResponseDictionary valueForKeyPath:#"photos.photo"];
NSDictionary *photoDictionary;
FlickrImage *flickrImage;
for (photoDictionary in photosDictionary) {
flickrImage = [[FlickrImage alloc] init];
flickrImage.thumbnailURL = [[appDelegate sharedDelegate].flickrAPIContext photoSourceURLFromDictionary:photoDictionary size:OFFlickrThumbnailSize];
flickrImage.hasLocation = TRUE; // TODO this is actually to be determined...
flickrImage.ID = [NSString stringWithFormat:#"%#",[photoDictionary valueForKeyPath:#"id"]];
flickrImage.owner = [photoDictionary valueForKeyPath:#"owner"];
flickrImage.title = [photoDictionary valueForKeyPath:#"title"];
[self.flickrImages addObject:[flickrImage retain]];
[flickrImage release];
[photoDictionary release];
}
The retain is there because I thought it might help solve this but it doesn't - and doesn't the NSMutableArray (flickrImages is a NSMutableArray) retain its members anyway?
EDIT I should add that the getLocation method (first code snippet) is launched in a thread:
[NSThread detachNewThreadSelector:#selector(getLocation) toTarget:self withObject:nil];
Your delegate method is never being called because the request is never being made. When you call callAPIMethodWithGET:, it sets up communications to run asynchronously on the current thread's run loop, then returns immediately. That way you can safely call it on the main thread without blocking.
Because you are calling the method from a thread you created yourself, it does not see the main run loop, but the run loop for your new thread. However, because you never execute the run loop, the messages are never sent, a response is never received, and your delegate is never called.
You could fix this by calling [[NSRunLoop currentRunLoop] run] in your new thread. That will let the work happen. But in this case would be easier to never detach a new thread in the first place. Your program won't block, and you won't have to worry about your delegate method needing to be reentrant.
I've also run into this problem when requesting and parsing XML on a different thread my solution was to do this:
while([[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:start] && !isFinished){
}
Where start = [NSDate dateWithTimeIntervalSinceNow:3]; this is basically a timeout so that it doesn't live forever and isFinished is set to true when my parsing has completed.
I'm not familiar with these flicker API wrappers, but in this code:
NSDictionary *requestArguments = [[NSDictionary alloc] initWithObjectsAndKeys:FLICKR_API_KEY,#"api_key",self.ID,#"photo_id",nil];
Are you certain that both FLICKR_API_KEY, and self.ID are not nil? If either of them is nil, you'll end up with a dictionary that has less items in it than you intend.
Could you post the callback method(s) you have implemented – this could be just down to a simple typo, as it appears OFFlickrAPIRequest won’t do anything if the delegate does not implement the required callback.
Did you also implement flickrAPIRequest:didFailWithError: to see if there was an error returned from the API call?
Okay, I did solve it, with help from some of the suggestions above.
I did remove the extra retain because it did in fact create a memory leak. It did not look right from the outset, so my gut feeling about that is worth something, which is a good thing ;)
I removed the redundant threading because the API call is already asynchronous and does not require an additional thread to be non-blocking. After that, the callback method was being called but I ran into different problems concerning object retention. If interested you might want to check out that question, too
Thanks all.
The setDelegate method of OFFlickrAPIRequest does not retain the delegate like it should. This means you're stuck ensuring that your delegate is alive as long as the request is (or patching the class to properly own its own references).