How to self destruct an object in objective-c? - objective-c

My object finish their job. He have the control of work flow, but now it have to call a function in the object that create it and have to be released. The problem is like this:
AnObject *object;
- (void)function
{
object = [[AnObject alloc] init];
[object doYourJob];
//The program continue to run next line, it don't stop here. So, I can't send a [object release] here
}
- (void)callThisWhenFinish
{
//do something
//can't call [object release] because it is in the stack and run a line of a released object
}
So, how can I release the memory of object, I try this:
Send a [object release] in callThisWhenFinish or in function. - Fail! The program still have to run some lines of AnObject.
Use delegate way to run callThisWhenFinish. - Fail! I cant release AnObject because it try to run the next line when the function callThisWhenfinish finish.
Use a NSNotificationCenter to post a notification to callThisWhenFinish. Fail! When I post notification it immediate call the callThisWhenFinish and AnObject can run the next line and it is release, causing a crash.
Use the same NSNotificationCenter with a delay on it. How safe is this way? How can I know that AnObject will not be called again?
Use the [object autorelease]. This work, but I don't know when it is done. My AnObject use a lot of RAM and have to be free as fast as possible.
Any other idea?

If your object is doing background work, it is a good idea to have it retain itself during that time. That way, you don't have to worry about it being deallocated until it is done. Your function method can safely release it after starting the action, but it won't be deallocated until it is ready to be.
AnObject *object;
- (void)function {
object = [[AnObject alloc] init];
[object doYourJob];
[object release];
}
- (void)callThisWhenFinish {
//do something
}
In AnObject:
- (void)doYourJob {
[self retain];
// enter background and call backgroundMethod
}
- (void)backgroundMethod {
// This is the method which doYourJob calls in the background to do the work
// Do some work
[delegate callThisWhenFinish];
// do whatever else needs to be done
[self release];
}

If you can't make it an ivar, why not something like this:
- (void)callThisWhenFinishAndRelease:(id)obj
Then you have a pointer to it.

Related

Do I need to release my singleton object?

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.

blocks and async callback, dealloc object - need to nil the block

There is a similar question here, which doesn't explain exactly what I want: Objective C Blocks as Async-callbacks & BAD ACCESS
I have a view controller, which calls a service with an async callback. The callback is done using a block, which references variables on the view controller to populate them.
It looks like so:
- (void) loadData {
__block MyViewController *me = self;
[self.service executeWithCompletion:^(NSArray *result, NSError *error) {
if (!error) {
me.data = result;
}
}];
}
However, if I dealloc the view controller, 'me' is then badly accessed by the callback.
What is the simplest way of making 'me' NULL? If i put it as an iVar, it then brings back the circular reference... i think?
I think I'm missing something obvious....
Thanks
Are you targeting iOS 5.0 or later (or Mac OS X 10.7 or later)? If so, you can use ARC and a __weak variable (instead of a __block one). This will automatically zero out when the referenced object is deallocated. Your code would look like
- (void)loadData {
__weak MyViewController *me = self;
[self.service executeWithCompletion:^(NSArray *result, NSError *error) {
if (!error) {
MyViewController *strongMe = me; // load __weak var into strong
if (strongMe) {
strongMe.data = result;
}
}
}];
}
If you need support for an older OS then you need to find a different solution. One solution is to just go ahead and let the block retain self. If the service is guaranteed to execute the completion block (and then release it), this will only produce a temporary cycle that will break automatically when the completion block is run. Alternatively if you have some way to cancel the service (in a way that guarantees the block cannot be called after the cancellation), you can stick with the __block and just be sure to cancel the service in your -dealloc. There's other alternatives too but they're more complicated.
I did a combination of things above from the suggestions. Including nilling the blocks. Although, my objects are still not getting released immediately. i.e. I'd put a breakpoint on dealloc of MyViewController, and without the __block variable it would get called at a much later point in time (probably due to the async connection) and sometimes not at all.
The code is fairly complex - so I imagine there are other things going on for it to not work as suggested above.
What I have also done, is used Mike Ash's MAZeroingWeakRef, which i guess is the same as using __weak - which #KevinBallard suggested.
Below is how I've implemented it, and it appears to be working. Dealloc is called immediately on disposal of the view controller, which i want. And I can't get it to crash... and with the log comment that i've put in, I can already see that I'm dodging bullets.
- (void) loadData {
__block MAZeroingWeakRef *zeroWeakRef = [[MAZeroingWeakRef alloc] initWithTarget:self];
[zeroWeakRef setCleanupBlock: ^(id target) {
[zeroWeakRef autorelease];
}];
[self.service executeWithCompletion:^(NSArray *result, NSError *error) {
MyViewController *me = [zeroWeakRef target];
if (!me) {
DULog(#"dodged a bullet");
}
if (!error) {
me.data = result;
}
}];
}
Is there a real retain cycle problem that you're trying to avoid? Is there a reason that self should not simply be retained until -executeWithCompletion: completes? Is there any real chance that it won't complete?
So long as it really will eventually complete (even with failure) and so long as it releases the block after invoking it (perhaps by setting a property to nil), then the retain cycle will eventually be broken and all will be well.

Is object that calls performSelector:withObject:afterDelay get retained by the NSRunLoop?

I have a certain object that perform a "Refresh" every X seconds. ("The Updater")
The way I'm doing this repetitive update is by calling performSelector:withObject:afterDelay and in my selector I'm re-scheduling as necessary.
Of course I have a method to stop these invokations by calling cancelPreviousPerformRequests.
The problem is that this "Updater" is never being deallocated.
There is only one other object that retaining the Updater (AFAIK), and the retaining object is being deallocated and calls [self setUpdater:nil];
I'm suspecting that this is have something to do with the performSelector:withObject:afterDelay method, but I couldn't find any reference to that question in the documentation.
Can anyone confirm or dismiss it?
Thanks!
APPENDIX
This are the scheduling methods:
-(void) scheduleProgressUpdate
{
[self stopProgressUpdates]; // To prevent double scheduling
[self performSelector:#selector(updateProgress)
withObject:nil
afterDelay:1.0];
}
-(void) updateProgress
{
// Perform update..
[self scheduleProgressUpdate];
}
-(void) stopProgressUpdates
{
[NSObject cancelPreviousPerformRequestsWithTarget:self
selector:#selector(updateProgress)
object:nil];
}
As far as I know the performSelector method retain its receiver and arguments.

NSTimer possible crash cause

I have an issue while working with NSTimer.
Let's assume I have this architecture :
ThreadedClass.m (contains a NSTimer* timer;)
- (id) init {
if (self = [super init]) {
// do blablabla
[self launchAThread];
}
return self;
}
- (void) launchAThread {
[NSThread detachNewThreadSelector:#selector(selectorToMyThreadFunction)
toTarget:self
withObject:nil];
}
- (void) selectorToMyThreadFunction {
//I do my stuff in here
//Then i relaunch a Timer to call this function
//periodically but it has to be "atomic" so no
//repeating timer since i don't know the time
//this function will take
//I do some [self changeSomething];
[self restartTimer];
//MyThread ends here (and might be recreated by the Timer's bip
}
- (void)restartTimer {
if (![NSThread isMainThread]) {
[self performSelectorOnMainThread:#selector(restartTimer)
withObject:nil
waitUntilDone:NO];
return;
}
[timer invalidate];
[timer release];
timer = [[NSTimer scheduledTimerWithTimeInterval:interval
target:self
selector:#selector(launchWithTimer:)
userInfo:nil
repeats:NO] retain];
}
- (void) launchWithTimer:(NSTimer *)theTimer {
if (theTimer == timer)
{
[timer release];
timer = nil;
[self launchAThread];
}
else
{
//Nothing to be done in here, a user launch a thread manually
}
}
So let's assume the user of the class alloc it and release it right after. My timer will still be alive and the object too (since there is a retain made by the timer).
When the timer will fire, it will do [self launchAThread] and then the timer will invalidate and release itself AND it will release my object which now has a retainCount = 0... Let's assume, one more time, the object is deallocted right after, this will cause crash and there is nothing i can do to stop it that comes right to my mind.
I agree, this is a lot of assumptions but i'm curious to know if someone already had this issue and how he solved it.
Thanks for reading and I hope I was clear ! :)
Yo have to always invalidate your timer before releasing it. If the timer is a part of a view controller I am always invalidating it in viewWillDisappear. For me is so odd that NSTimers retains theirs owners. I think the best way is to create - (void)cleanUp method, that will invalidate the timer and warn the user of the class to ALWAYS use cleanUp before releasing. If somebody knows the better way I will be glad.
As long as you're not using a repeating timer, why not use dispatch_after? You'll save yourself the headache and overhead of the NSTimer object. And if you just stick with GCD you can avoid the call to detachNewThreadSelector: as well.
NSRunloop will retain the timer for you, which means you don't have retain/release it at all
Since I'm making a library, i can't assume that the user will call a cleanUp function anytime.
So to solve my problem, I added a new "layer" : a new class that will do the thread and timer part so that I am the user of this class and I know I have to cleanUp !
I first resorted to using a cleanUp kind of function too.
I also have an object A owning object B that contains the timer - which retains object B. When object A is deallocated it releases object B, but B lives on because the timer retained it. Then in the method fired but the timer, I'm using a delegate relationship to call back to object A → hard crash. This is where object A needs to "cleanUp" B's timer. This could lead to other problems though if other objects also rely on object B. And also class A shouldn't and might not know the implementation secrets of class B. :-P I guess a good solution could be to unset that delegate relationship before releasing is done in A's dealloc because you don't know if B will die even if you released it - someone else might have retained it (LIKE THAT D*** NSTIMER)... :-P

memory leak when using callback

I'm having an issue with memory management when dealing with callbacks and async code in objective c.
I cant seem to find a way to release the instance that the callback is set on.
For example:
MyClass *myArchive = [[MyClass alloc] init] ;
[myArchive callBack:^(RKObjectLoader* objectLoader, id object ) {
NSLog(#"success");
} fail:^(RKObjectLoader* objectLoader, NSError* error) {
NSLog(#"failed");
}];
[myArchive searchArchive:words:paging];
The problem being that I don't know when or how to release the instance *myArchive. Using Instruments within xcode to profile my code I always get a leak here. The function searchArchive performs an async request to a server using restkit. I wont reference the instance from within the callback as I heard this causes a retain cycle and I have done some reading about using __block and other c approaches to avoid retain cycles which is all fine but as it stands now with no actual code happening within the callback how do I release the *myArchive instance. anyone able to explain how I should deal with this within objective-c?
EDIT:
This is where I set the callback in myclass
// Sets internal backs on this object which basically wrap the delegate
//
- (void)callBack: (void (^)(RKObjectLoader* objectLoader, id object))success
fail: (void (^)(RKObjectLoader* objectLoader, NSError* error))fail {
//sanity check
NSAssert(_currentDelegate != self, #"Delegate is another object. Can not set callback");
// store our callback blocks in the instance
_success = [success copy] ;
_fail = [fail copy] ;
}
and then release _success and _fail in dealloc
and within the #interface
#interface myClass : NSObject<RKObjectLoaderDelegate> {
// holds the block callback for "success"
void (^_success)(RKObjectLoader* objectLoader, id object);
// holds the block callback for "fail"
void (^_fail)(RKObjectLoader* objectLoader, NSError* error);
}
I hope this gives more insight into what I'm doing wrong.
EDIT 2:
Ok I'm beginning to see the errors now:
-(void)retrieveGallery{
//create call back for async and deal with the result
[_galleryItems callBack:^(RKObjectLoader* objectLoader, NSArray *objects) {
//success happy days. do a bunch of code here that does not cause leaks
} fail:^(RKObjectLoader* objectLoader, NSError* error) {
//retry the attempt to retrieve gallery data from the server
_retryCount++;
if (_retryCount < _maxRetryCount) {
[self retrieveGallery];
}
}];
//read the collection of gallery items from server
[_galleryItems readGallery];
}
The only actual memory leaks are when the callback catches a fail for what ever reason and then calls the [self retrieveGallery] function from within callback to attempt again. this is what is causing the leak so I'm guessing that is a big no no. How should I attempt the function (retrieveGallery in this case) again.
Memory management isn't really any different because you are using an asynchronous callback. myArchive should be a property of whatever class you are doing this in. You want it to stick around until the task is complete, right?
#property (retain) MyClass *myArchive;
Then..
myArchive = [[MyClass alloc] init];
void (^on_success_callback)(void) = ^(void){
NSLog(#"success");
self.myArchive = nil;
};
You need to make sure you are managing the callbacks properly, i.e. copying them from the stack and releasing them when you are done.
If you have retains and releases in your code you probably aren't using the accessor methods properly.