Bad-practice to retain 'self'? - iphone

I have a simple query that I'd like cleared up by someone... Is it bad-practice to retain self?
I have a server request object that I'd like to make. I'd like to be able to use it in the following fashion:
ARequest *request = [ARequest request: someParam];
request.delegate = self;
[request begin];
In order for the object not to self destruct as soon as the autorelease pool is drained, I imagine I need to call a retain in it's init method and then a release once the server response has been received, processed and delivered to it's delegate.
However, something is raising a warning bell in my head with this approach. Better ways to do it?

There is nothing wrong with retaining self, as long as you release it at some well-defined point in accordance with normal memory management protocol. If an object requires itself to exist until some condition is met, it should take responsibility for that, in the same way as it does for any other object it requires to continue existing.
Introducing otherwise extraneous manager objects or foisting the responsibility off on the object’s owner for superstitious reasons would be the real anti-pattern here.
(The equivalent approach in garbage-collected code would be for the object to exclude itself from garbage collection while results are pending, or root it through a collection of some sort if you dislike that idea.)

It's not unheard-of, but it is somewhat uncommon. The main way I've seen it used (and used it myself) is when you're dealing with some sort of semi-synchronous object (by semi-synchronous I mean that it does not block the main thread, but it also does not execute on a background thread; an NSURLConnection would fit this bill). For example, I wrote a subclass of NSWindowController that was specifically for displaying a window as a sheet and for invoking some certain delegate callbacks. Basically, you'd alloc/init a new sheet controller and invoke beginSheetForWindow:. This would run the sheet semi-synchronously, and then invoke an appropriate callback when the sheet was dismissed.
Since the invoking object doesn't necessarily "own" the sheet (think of it as a Mac version of a modal view controller on iOS), the sheet controller does [self retain] immediately before showing the sheet, and [self release] immediately after cleaning up and invoking callbacks. The purpose behind this was to ensure that the controller object would stick around until the sheet was done. (The sheet, IIRC, was retained by the runloop, but I also needed the controller to stick around)
Like I said, it's very rare to come across a situation where you would want to [self retain], but it's not impossible. However, as a general rule of thumb, if you think that you need to [self retain], you may want to think again.

Easiest way to do this would be to create an iVar for your request, retain the request when you start it and release it when the last delegate method is called.
Is ARequest a class you created? Does it create a new thread to asynchronously submit the request?

I once did the same thing as you. I wrote a Category-Method on NSString to send it it to a server, that will print it. In the Category-Method I had to call [self retain], so that the callback methods could be a NSString-Categroy-Method to.
I felt so bad about it, that I rewrote everything to use a Singleton, that is accessed by the Category-Method. So the Singleton will retain the string as long as necessary.

Related

How to work around/handle delegation EXC_BAD_ACCESS errors? Obj C

I'm coding a library (Obj-C for iPhone) that I want to package and sell, so I obviously need to work out any design kinks before listing it for sale. I am also utilizing this library to help me develop another app.
My library is heavily built on task delegation. The primary function I have is to launch a (potentially) long-running process, and when it's done, I call a Delegate Protocol method in the class's delegate.
An additional complicating factor here is that I will often schedule this task to fire off every 30 seconds or so. Usually, I do this with [self performSelector:#selector(someMethod:) withObject:nil afterDelay:30] rather than using an NSTimer. Then, when the delegate method successfully returns, I process the returned data and trigger the method to fire in another 30 seconds. This gives me 30 seconds BETWEEN method calls, rather than 30 seconds FROM THE START OF ONE CALL TO THE NEXT. (This is mainly just in case the call ever takes more than 30 seconds, which shouldn't happen.)
The error that I'm catching is that sometimes, the Delegate callback method is failing with an EXC_BAD_ACCESS error. Based upon my investigation, it appears that the delegate of my class library has disappeared (been released/dealloced) since the long-running process was initiated. Thus, when it calls [[self Delegate] doSomeDelegateMethod], it's accessing a released object.
I tried first checking [[self Delegate] respondsToSelector:#selector(doSomeDelegateMethod)], but even that access apparently also throws the EXC_BAD_ACCESS.
It doesn't yet seem that checking for [self Delegate] == nil is the right way to go, either.
One way I think I have solved the problem, in this specific instance, is when the view controller that instantiates my object is disappearing (and therefore on its way to the garbage dump), I call [NSObject cancelPreviousPerformRequestsWithTarget:self]. This apparently fixes the problem. (Does this "fix" also indicate that my object "knows" about the call to come and keeps itself in memory until it can successfully, desperately, fire off its final shot?)
This appears to put a band-aid on a bullet wound. Yes, it appears to stop my app from breaking this time, but my gut tells me that this is a poor solution.
I've also considered setting the custom object to nil in my viewWillDisappear:animated: method, which is probably the correct coding pattern, but it doesn't seem right that the customer has to be so precise in handling my objects.
What's really bugging me, though, is that I haven't yet found a way, as a library developer, to "box in" my code so that it won't throw an exception for the user if they don't do just the right things. Basically, I'd like a way to have my object:
Get a request.
Go look for the answer.
Find the answer.
Try to return the answer.
Realize that there's nothing on the other end.
Give up and die on its own. (OK, so "die on its own" probably won't happen, but you get the point.)
One interesting side point:
A main reason I have for preventing this type of error from occurring is this:
I did the following steps:
Built my library's .h/.m files.
Generated my library's .a output file.
Imported my library's .a/.h files into another project.
Had the error described above.
Got to peruse the code from one of the .m files that SHOULD have been hidden inside the .a file.
Am I missing something here? Am I really risking exposing my entire source code if it ever throws an error for a client? (This is just a side issue, but I'm fairly concerned here!)
Thanks for any help you can provide to help me be a better programmer!
---EDIT---
I have found another reason why this is important. In another view controller, where I am using this library, I implemented the NSTimer strategy. If the view is popped from the navigation stack (i.e., in the viewWillDisappear:animated: method), I invalidate said timer. So, no more calls will go to my library after the view disappears.
Here's the rub: what if the view disappears IN THE MIDDLE of the long-running call? Yes, it's tricky and unlikely to do, but I just had it happen on the simulator. In particular, THIS is why I'm looking for a workaround to let my code realize "hey, there's nothing on the other end of this pipe" and then fail gracefully. Anyone?
Thanks!
There are several approaches to this problem:
The traditional delegate approach (UITableViewDelegate) makes it a requirement to clear yourself as delegate before going away. This is traditionally done in dealloc of the delegate with otherObject.delegate = nil. Failure to do so is a programming error. That's basically what you're seeing. This is the common pattern when the delegate and the delegator have basically the same lifespan.
Another approach is how NSURLConnection handles it: retain your delegate until you're done. The key to this working well is that NSURLConnection has a lifespan of its own, so the retain loop will work itself out automatically. UITableView could not retain its delegate because this would almost always create a permanent retain loop. If your object lives for a while and then goes away, then this makes sense. Typically here the delegate has a much shorter lifespan than the delegator, so the retain loop doesn't hurt anything.
Any object that calls performSelector:withObject:afterDelay: should always call cancelPreviousPerformRequestsWithTarget:self in its own dealloc. This has nothing to do with your delegate, though. It should be self-contained to the object itself. (I don't know why I keep thinking this is true, and then proving to myself again that it isn't. When you call performSelector:...afterDelay:, you are retained, so you can't deallocate before it fires. My SIDE NOTE, while true, isn't relevant here.)
SIDE NOTE cancelPrevious... is really expensive in my experience. If you have to call cancelPrvious... very often, I recommend keeping your own one-shot NSTimer and just resetting it when it fires to get the same effect. performSelector:withObject:afterDelay: is just a wrapper around a one-shot timer.
I'm answering myself because the page warned me to not have extended discussions in the comments... :)
OK, so it appears that part of my answer is that [self performSelector:withObject:afterDelay:] automatically retains my object until it gets to "fire that shot", at which point I'm guessing the view controller dies.
So, now it makes sense why my custom class is trying to access a released object when it tries to return its answer to its delegate, which is an __unsafe_unretained object, meaning that it can die at will (I think).
What I'd like now is a way to prevent this from causing an error. In .NET, I've got all sorts of error handling options to do this, but I'm unable to think of a fail-safe "bail out" here.
I've tried [[self Delegate] isKindOfClass:..., but can't be sure what kind of class the delegate will be, so it won't work.
I've also tried [[self Delegate] respondsToSelector:#selector(...)]. I'm not sure why this fails, but I get the EXC_BAD_ACCESS here, too.
What I don't want is my customers to be able to crash my product with such a simple, innocent mistake.
As an aside, does anyone know why this sort of failure gives me such easy access to the contents of the .m file that should be hidden inside my .a file? Did I build my library incorrectly?
Thanks!
Try setting Delegates to nil in dealloc.
example:
self.fetchedResultsController.delegate = nil;
I've seen this problem a lot lately and usually fix the problem. Even though delegates are supposed to be weak references, sometimes some private implementation is using them as well.
If I release, I get bad access, if I retain, I leak
That's where I had a similar problem.
Edit: When using ARC, you can still override dealloc for cleanup, you just can't call [super dealloc] or release anything.

Objective-C multithreading, what happens when an object gets dealloc while its methods are being executed? (And how to prevent it?)

I am writing an app for the iPhone and arrived at this situation.
I have a view controller, myViewController, that will dealloc whenever the user taps the "back" button on the screen. There a thread in the background that communicates with a remote server and may message a method, updateUI, method in myViewController.
What would happen if the background thread messages updateUI in myViewController, but the user just happened to tapped the "back" button at the right time such that it causes myViewController to dealloc while updateUI is still executing?
My guess is that the dealloc method will run and the app might crash if updateUI ends up using a null pointer. Assuming this is the case, the current solution I have is:
[self retain];
// updateUI code here
[self release];
I am unsure if this is the best solution, as I feel that this is a common problem when dealing with multiple threads.
Is my assumption correct? If so, is there a better solution?
What you are describing is known as a "race condition." Race conditions can be difficult to identify in testing, track down once reported, and reproduce because sometimes execution in the debugger can effectively modify how the code is being executed (avoiding the condition that one is trying to reproduce). Race conditions are one of the major pitfalls in concurrent programming - making the area deceptively difficult to do well.
In principle, it is a best practice to minimize the use of shared resources and closely qualify how the sharing is coordinated when implementing concurrency. If an object is shared across multiple threads, it should be retained by each of them to ensure that the object stays in-scope while each thread completes its processing.
Apple has been taking steps to simplify implementing concurrency. This is a good starting point for familiarizing yourself with the topic on iOS.
http://developer.apple.com/library/ios/#documentation/General/Conceptual/ConcurrencyProgrammingGuide/Introduction/Introduction.html%23//apple_ref/doc/uid/TP40008091
It's also useful to be aware that Objective-C 2.0's properties can support atomic operations (and are atomic by default, thus the nonatomic keyword to disable this default).
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Articles/ocProperties.html
And, this is the old-school guide to threads (out of favor approach, but still useful background - be sure to be familiar with NSLock).
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Multithreading/Introduction/Introduction.html%23//apple_ref/doc/uid/10000057i
Whenever some part of your code depends on another, it should retain this dependency until it is not needed. In your case the background worker should retain the controller and only release it when the work is done (or cancelled).
If you dealloc and then nil your objects then this shouldn't be an issue - you can send messages to nil in objective-c.
Alternatively, if you wanted the viewController to get the message and if your targeting iOs 4, you can use blocks and GCD. Blocks auto retain objects and therefore if a block references your viewController, would keep it around for as long as its needed, even if -(void)dealloc ; has been called.
Here is a decent Block tutorial
Yes, your app will crash, likely with something along the lines of EXC_BAD_ACCESS.
As far as multithreading, you will want to retain your objects until everything is done with them and program defensively. Check for the existence of objects before trying to manipulate them.

best way to release an object that you lose track of

So I am creating an class that does an animation. There is a timer delay. So I will instantiate this class. Have it do its thing then have a timerFinished type of delegate to continue on.
This question comes from my sheltered garbage collection career.
What is the best way to release this object?
Do I have it release itself when it finishes that task (not even sure that this is possible).
Do I have the object that implements the delegate release it?
Having trouble wrapping my mind around the best way to do this.
FWIW, I've found it rather dangerous to have objects that retain/release themselves, for the simple reason that you may have objects hanging around in the background that you don't know about anymore. Even worse, if they message another object, they may be retaining views or controllers you've long closed.
Also, this pattern doesn't work in the garbage collector on MacOS.
So, I'm currently trying to re-educate myself to keep a global NSArray for each class that may have such objects floating around. That way, during debugging I have a place where I can easily see these objects, and I can cancel them from dealloc by e.g. having a "cancelAllConnectionsWithDelegate: self" method.
You should have your object post a notification when it's finished or send a message to its delegate, and the listening object or delegate can handle cleanup of the object.
Generally, if you are not sure when or where to release your object you can call autorelease on it when initializing. Like this:
NSObject *anObject = [[[NSObject alloc] init] autorelease];
Yes, when you're done with the animation, you can send the animation class instance a [self release] message. Just be sure you're really done with the animation class when you send the message.

Is calling [self release] allowed to control object lifetime?

I want to create an object in Objective C but I don't hold a reference to it.
Is it allowed to let the object control its own lifetime by calling [self release]?
In case you're wondering why I need this: I want to create an object that subscribes to some notifications, but after a while the object is no longer needed and should go away.
So, is the following allowed?
- (void) destroyMyself {
 [[NSNotificationCenter defaultCenter] removeObserver:self];
[self release];
}
If you see this in code, its probably wrong. However there are legitimate response for it in certain circumstances that are arguably defensible. (So make sure you are doing it for the right reasons.)
A good example of when this makes sense, is when you create an object that goes off to download a url. The object sits in memory while downloading the url, then sends a message to its delegate saying the data is ready (or url couldn't be downloaded). Once its message has been sent it destroys itself as its no longer needed. In this situation the code/function that created the 'url downloader' may no longer even be in memory, i.e. if it was called in response to a user selection a menu item or an action in a view controller that is no longer on the screen.
This is useful when the code that creates the "download" object doesn't care if the download completes or not.
The rules are simple. You should only release an object if you own it. i.e. the object was obtained with a method starting "new" or "alloc" or a method containing copy.
Cocoa Memory Management Rules
An object must not therefore do [self release] or [self autorelease] unless it has previously done [self retain].
To quote the great philosopher Alicia Silverstone, "I had an overwhelming sense of ickiness" when I read that. But I couldn't really tell you why.
I think I would use autorelease rather than a simple release since you're still executing code in self when you call it, but other than that I can't think of any technical reasons why it wouldn't work.
It's legal, but be careful. You want to be sure nothing else is going to send you a message after you release yourself.
I've done this kind of thing for a faulting scheme back before we had CoreData.
Well part of the protocol is that if you send release to self, then you should have sent retain once as well, which I suppose you do. Then there is nothing fishy. I mean the allocing code must be able to control the lifetime of your instance; it itself can only prolong its life, never make it shorter (since making it shorter, then you'd suddenly leave the allocing owner of the instance with an invalid pointer).
And I will use [self autorelease] instead of [self release]. Because usually it's called in
- (void)aMethod
{
[self.delegate aDelegateMethod:self];
[self release];
//If you add code related to self here, after [self release], you are making a huge mistake.
}
If I use [self autorelease], I can still do something after autorelease.

Is it acceptable to release object in a method of the object's class

Is it acceptable for a instance method of a class to release itself?
ie to have a method that calls:
[self release]
Assume that my code is not going to access self after calling [self release]
Is it acceptable for a instance method of a class to release itself?
ie to have a method that calls:
[self release]
Assume that my code is not going to access self after calling [self release]
First, I would want to have a really good reason to release myself. The only time I've done it is in a singleton that I dump to free up large chunks of memory on an iPhone. This is a rare event.
Your code is part of the class object. Hence, it is not really a problem to call [self release]. Of course, you are much safer, from an encapsulation perspective, if you call [self autorelease]. At least then, if someone up the call chain calls your methods, you don't cause an exception.
Andrew
You should only do this if you've done something like
[self retain];
But it's unclear why you would do that. The Cocoa Memory Management Documentation might help
While I doubt that immediately after your release, memory would move much, keep in mind that the code that your [self release] is in, resides in a memory block inside your object, self. Thus, it is possible that after returning from [self release], you end up in code that is no longer allocated and is being written over by some other process. Can't say for sure how probable that is, but it seems possible.
I have used this technique once before, for a similar situation (standalone object handling response from a web delegate that may outlive the view that launched the request).
It does work, but is actually rather tricky to get right. Since then I have found that using NSOperations in an NSOperationQueue is a much more solid and well-understood approach to encapsulating background actions that run independent of the requestors. Usually when an operation is done a notification is sent out on the main thread informing whatever caller might still be around that data is ready for pickup.
Plus for simple remote requests you can use the simpler synchronous URL calls in your Operation since they run in a separate thread and will not block the main thread while data is incoming (handy when fetching small images from URL's, for example).
You can do it. It works. It is a bit dangerous, especially since optimizing compilers can rearrange your code in ways you didn't intend them to.
A little bit safer is to call [self autorelease], which will release the current object at some point in the near future (the next time through the runloop typically) rather than right away.