Lets say I have multiple View controller classes using the same UIAlertView *alertView. *alertView's delegate is set to a centralized delegate.
I do this because would like to use the .tag to do different things based on it.
The question is every time I invoke an alert view or dismiss it, what do i have to do to prevent a memory leak?
Should I not release every time? Or is this a very bad idea?
Thanks.
A UIAlertView may be "shown" from anywhere in your app. I have an app that the main UIViewController has a timer that every so often brings up a UIAlertView. When that timer goes off, even if my main view being shown is from a completely different UIViewController (and thus view) the Alert will come to front.
If you really want to "actively" bring up the UIAlertView from any of your UIViewControllers (lets say based upon a user action), then I would do one of two things.
1) setup my Application Delegate Object with the UIAlertView implemented there, with accessor methods for invoking (showing) the Alert view, and thus freeing it from there also, or
2) Generate a singleton like object with the AlertView implemented there!!!
In either case then you can simply dealloc your UIAlertView once within the dealloc routine you write for either of those placements, and alloc it only once when the object is initialized.
Just treat it like you would any other object. If you want to keep it around, assign it to a retained property like: self.myAlert. You still need to release it like you normally would when creating it. The retained property will take care of keeping it around for you.
Always keep your retains(alloc's, copy's, etc...) and releases balanced.
Related
I've run into this problem a couple of times and want to know the correct approach to take.
For an example, let's say I'm writing an iPhone app and I want a custom alert view class that uses blocks.
So I write the class, then later on in my code I go:
MyAlertView *alert = [MyAlertView alertWithBlahBlahBlah...];
[alert addButton:#"button" withBlock:^{ ... }];
[alert show];
Somewhere in the alert view class, we have
- (void)addButton:(NSString *)button withBlock:(void (^))block {
[_blocks setObject:[block copy] forKey:button];
}
- (void)show {
... drawing stuff ...
UIButton *button = ...
[button addTarget:self selector:#selector(buttonPressed:) ...];
...
}
- (void)buttonPressed:(id)sender {
((void (^)())[_blocks objectForKey:[sender title]])();
}
So, the alert view now shows up just fine. The problem is, if I tap a button, it attempts to send the buttonPressed: selector to the MyAlertView object that was displayed. The MyAlertView has, however, been removed from the superview at this time. ARC decides that because the alert view is not owned by anyone anymore, it should be deallocated, not knowing that a button needs to message it in the future. This causes a crash when the button is tapped.
What's the right way to keep the alert view in memory? I could make the MyAlertView object a property of the class that's using it, but that's kind of silly (what if I want to show two alerts at once?).
If an object were to remain in memory, and you do not have a reference to it, this is known as a memory leak. As I said in my comments, you need to keep some kind of reference to it so that a) it is not deallocated, b) you can send a message to it, and c) you can deallocate it before your class is deallocated.
The most obvious way to do this would be with a property in your class. Since you said that you don't want to do that (maybe you have a lot of them) then another possible solution would be to keep an array of cached objects that you plan on reusing and eventually deallocating.
I think you can use performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay to retain the alert view in runloop.
Actually, I just came across an wrapper implementation for UIAlertView using this skill.
Check UIAlertView input wrapper for more detail.
Quite simply, you're breaking the memory management rules. ARC doesn't change the rules, it just automates them. If you need an object to stay alive, it needs to have an owner. Every object in your app's object graph, all the way back to the application delegate, has an owner. It may not be obvious what that owner is (and sometimes the owner may be an autorelease pool), but there is one.
If you want this view to stick around, it needs to be owned by something, even if it's not "currently being used". If it's onscreen, it should be part of the view hierarchy. If it's not, the ideal owner is likely to be the object that created it.
I have a view with some buttons, text fields, and methods. When I load the view, switch to another view, and then switch back, my app crashes. I added in an NSLog in each method to see what the last method call before the crash was, and it was -(void)dealloc{
I am wondering why this method was called? Is it called every time you reload a view? I've double checked my code and I definitely do not call it anywhere.
EDIT : Found my problem, I was releasing an array that I was using to store views. Thanks to #Darren I traced my problem.
Dealloc is called when a class is no longer needed and removed from memory.
When you have no more pointers holding onto anything in the view, then it's dealocated.
How are you switching to/from the view?
if you set a (strong) pointer to the view then it won't be dealocated automatically.
-dealloc is called whenever an object's reference count drops to 0. To find your problem, figure out what object's -dealloc was called. What's the second method on the call stack? The third? Was -dealloc sent to a valid object pointer in the first place?
There are several ways to approach this sort of thing. A good first step is to turn on NSZombies (Google for it). That'll let you know if you're sending a message (like, say, dealloc) to an invalid object. Usually, that causes a crash, but with NSZombies you'll get a nice error message instead.
I want to make sure that all my initializations for my views and stuff are handled every time my application starts, even when it is called back after being sent to the background, such as with multitasking.
What's the best way to do this? should i use applicationDidBecomeActive to call viewDidLoad on my viewcontroller directly? I'm guessing this is not wise. I just want to make sure that stuff gets done on load every time the user calls up the app, no matter what state it is in at the time.
I have several apps published that do just that - call viewDidLoad on one or several UIViewControllers from applicationDidBecomeActive.
It works just fine. Apple doesn't object to it either.
However, be aware that if you have allocations in your viewDidLoad you need to either check for already allocated instances or release the instances you allocate in viewDidLoad when your app suspends. The same goes for DB connections that need to be closed, notification listeners, and so on.
As long as you watch for these elements and handle them correctly, the approach is valid and very usable.
Hey guys, I currently have a root table view which has a toolbar at the bottom and has labels and a refresh button within it, much like the Mail app's toolbar. This root table view controller obtains data from a server by allocating and initializing a DataUpdater class. Within this class are the NSURLConnection delegate methods that are called while communicating with the server.
As you can probably guess, I need to know when certain (delegate) functions are called within the DataUpdater class and the values of the parameters passed to these delegate functions so that I can update the labels on the toolbar accordingly (i.e. Connecting..., Updated, etc).
The problem I am having is determining how to notify the root table view controller of what is going on in these delegate methods. Would I use protocols, if so how? I have been skimming the documentation and don't quite see how I would get this effect. Or would you suggest I implement my program another way?
Thanks in advance!
A protocol is a kind of contract that says: I promise to provide the non-optional methods defined in the protocol, and maybe even the optional ones. It's purpose is like Java interfaces: to work around missing multiple-inheritence.
The delegate pattern in Objective-C normally works like this: you define a protocol, and then in your class, you define a variable like id<MyProtocol> myDelegate; and define a setter and maybe getter (either via normal methods, e.g. - (void)setDelegate:(id<MyProtocol>)aDelegate; or via properties.
Note that the delegate is not retained ! So if you work with a property, you need the assign option, not retain.
Now back in your class, you check whether myDelegate is nil and if not, you can directly call its non-optional methods. If you want to call an optional method, you first need to verify its presence via respondsToSelector:.
So if you decide to use the delegate pattern, you need to define a protocol, add that protocol to your root table view controller, implement the necessary methods there, and make sure to call [foo setDelegate:self]; or something similar to inform your other class that the root table view controller is the delegate. And of course implement the delegate calls in your class.
Edit:
An alternative might be to use NSNotifications, BTW. The advantage of notifications is that you can have multiple objects listen and react to them. The disadvantage is that you cannot (directly) pass values back. For example, you can define a delegate method that asks the delegate whether to do something or not. That's not possible with notifications, it's more like shouting into a room instead of having a one-to-one conversation.
DarkDust's answer about protocols is fine but I would like to add some things to it.
One underlying thing that is often forgotten when it comes to delegation is object ownership. When a program is running it creates a tree of objects. Its root object is the application delegate and for example it owns a navigation controller, which owns the individual view controllers, which own the view and the view owns its subviews and so on.
Often the question comes up: "Why is the delegate not retained, just assigned?" The problem is that if you send a message to a deallocated object the program crashes. So how do you make sure the delegate stays around? The answer is object ownership.
I give you an example: a UITableView and its data source which is the TableViewController which is nothing but a delegate. The TableViewController holds a reference with its view property to the UITableView, so it owns the TableView. That means when the tableView is alive there must also be its parent object present, which is the UITableView's delegate. So there is no danger that the delegate goes away somehow.
In the end it is again all about memory management.
Take home message is: think upfront about object ownership will make your program mode modular, easier to maintain and will lead to a looser coupling between individual objects.
I'm trying to implement my own version of NSViewController (for backwards compatibility), and I've hit a problem with bindings: Since bindings retain their target, I have a retain circle whenever I bind through File's owner.
So I thought I'd just explicitly remove my view from its superview and release the top level objects, and that would take care of the bindings, because my controller isn't holding on to the views anymore, so they release me and I can go away. But for some reason, my view controller still doesn't get released. Here's a sample app exhibiting the problem:
http://dl.dropbox.com/u/34351/BindingsLeak.zip
Build it, launch it, and hit Cmd-K ("Create Nib" in "Edit" menu) to load a NIB into the empty window. Hit Cmd-K again to release the first view controller (TestNibOwner) and load a new one. The old view controller never gets dealloced, though.
Remove the "value" binding on the checkbox, and it gets released just fine.
If you set breakpoints at the release/retain/autorelease overrides, you see that _NSBindingInfo retains the TestNibOwner, but never releases it in the leaking case.
Anyone know how to fix this?
Doing a little investigation with class-dump and friends, it looks like Apple has a private class called NSAutounbinder that takes care of this dirty work for classes such as NSViewController and NSWindowController. Can't really tell how it works or how to replicate it though.
So, I can't really answer your question on how to prevent the retain cycle from happening for arbitrary bindings in a loaded nib, but perhaps it's some consolation to know that Apple is cheating, and you're not missing anything obvious. :-)
One thing I've done for the same problem is to create a proxy NSObjectController inside my nib. My NSViewController-like class has a pointer to this proxy and all bindings are bound through it. When I want to cleanup the view controller, I then do [selfProxy setContent:nil] on the object controller and release the view controller. In this instance the NSObjectController proxy acts as the auto-unbinder in this case.
It's more manual and you can't just release the view by itself, but it does solve the retain problem.
I'd suggest you do this:
-(void) releaseTopLevelObjects
{
// Unbind the object controller's content by setting it to nil.
[selfProxy setContent:nil];
NSLog( #"topLevelObjects = %#", topLevelObjects );
[topLevelObjects release];
topLevelObjects = nil;
}
In your nib, bindings would happen through a path like:
selfProxy.content.representedObject.fooValue
When you remove your view from its superview, are you also sending it another -release message? It was created by unarchiving from the nib, right?