I'm having some issues with my application's memory management. I allocate an NSView class and put it on one of my Windows. After some time, I remove the object from the superview and then put another object in it's place. The problem that I'm having is that the memory isn't freed when I remove it. It continues to hold as much memory as it previously held, and if I add more of that class, it continues to pile onto the memory. My question is, will removing that object get rid of all objects that the class held, or are some pointers being held onto, even after the object is removed? I can post code if necessary.
Thanks!
Edit:
Here's the code that I use to allocate it
MyClass *theClass1 = [[MyClass alloc] initWithFrame:frameRect];
[self.window.contentView addSubview:theClass1];
Here's the code that I use to deallocate it
[[self.window.contentView subviews] makeObjectsPerformSelector:#selector(removeFromSuperview)];
I create it on a timer, updated every minute. I do not reference it anywhere else.
The memory for each object should be treated separately for each instance of a class. Removing one instance should not affect the allocation of other instances (unless you had some custom code looking for other instances of the class).
As for the NSView removal, removeFromSuperview does release the receiver (the view being removed), which is why the Apple docs on NSView say to retain it if it is still needed later.
Posting the code where it is declared, instantiated, added, then removed would be helpful for a more specific answer.
Related
do we release an argument in fast enumeration? Therefore would this code be accurate:
for (MKCircle *circle in localOverlays) {
[mapView addOverlay: circle];
[circle release]; // Is it perfectly alright to call this?
}
I am just wondering, my first time working with fast enumeration!
The answer is in the Apple Memory Management Rules.
You own any object you create
You create an object using a method whose name begins with “alloc”, “new”, “copy”, or “mutableCopy”
Did you create circle? No.
You can take ownership of an object using retain
Did you retain circle? No.
So you don't own the object.
You must not relinquish ownership of an object you do not own
That seems fairly straight forward now that you have determined you don't own circle. The release in the example code in your question should not be there. In fact, most likely, it will cause a crash somewhere down the line.
Fast enumeration does not usually create new objects, it is going through the existing ones. That is why it is almost never the right thing to do: fast enumeration of regular containers (NSArray, NSSet, NSDictionary) does not retain objects before making them available to the loop, so releasing them would be an error. Even inside a dealloc method you shouldn't do it: releasing the container releases its items too, so you shouldn't be releasing them individually.
No. I don't think it's the right thing to do. It neither do a retain nor a release to the instance
for (MKCircle *circle in localOverlays) {
[mapView addOverlay: circle]; //retain here
}
addOverley: should do a retain to circle, and it's mapView's responsibility to release when mapView doesn't needs it
Simple guide, you retain it, and release it when you done using it
Easy question alert, but I want to be sure I'm not being stupid.
In my iPad app I'm dynamically creating a UIView, and filling it with UIButtons, UIImageViews, sometimes a MPMoviePlayerController, sometimes a UIImageView with a few UIImages as an animation.
After a certain amount of time, I'm removing the view from the screen and discarding it.
The question is: should I be setting any of these objects to nil?
I'm releasing everything after I allocate it, and I'm not getting any leaks. BUT my app is eventually crashing after running out of memory. Each one of these views I build seems to be lurking somewhere in memory.
Any help, much appreciated.
Duncs
It's hard to comment without code or knowing if you are using ARC or not (guessing not, because you said "releasing").
Do an Analyze and fix every problem it flags. It's very good at telling you if you are retain/releasing correctly
Use the Leaks Instrument to find leaks
If you have no more leaks, but are still crashing, then turn on Zombies and make sure you aren't releasing anything too early
Setting a variable to nil doesn't do anything to release the memory. If you have a #property that is declared with (retain), the auto-generated setter will make it so setting the property to nil will release the old value.
The dealloc of any class that has properties needs to do this to all properties that are pointers to retained objects. For UIViewControllers, you would also want to do this in viewDidUnload for IBOutlet properties.
When you are using ARC, while you add the UIView as subview of another UIView, the retain count will increase. On you "removeFromSuperview" it, it will decrease and it will be deallocated. In a Non-Arc environment, after allocating it and adding it to a UIView the retain will be of 2, but then you release it, so it will go back to 1. So there is always a balance between those. To check what's going on, you should use Instruments, to pinpoint the problem.
It only makes sense to "nil" it is when you have a #property of the iVar (for retain). Why is that? Because it will release the old value and it will set the new one to the value passed (in this case nil). You probably think that the issue is related the UIViews but might be something else. That's why I advise you to use Instruments.
Subviews added to a view are automatically retained by the view. Suppose you want to have a separate pointer to the same subview so you don't need to constantly retrieve it via its tag.
What type of #property is necessary for such a case? I assume that setting the property to retain is not a good idea since the main view is already retaining it? Should it be assign?
Or, is using #property entirely unnecessary here unless you plan to re-assign it later or refer to it with dot notation?
You can use either retain or assign.
Of course, if you use retain, you have to set the property to nil or release its object in viewDidUnload and dealloc.
The reason some people prefer retain is because it means the property is still valid in viewDidUnload. So if you have other cleanup to do, and that cleanup requires the view to still exist, you can do it in viewDidUnload.
If you use assign, you don't have to set the property to nil in viewDidUnload and dealloc (though it would be good practice). However, by the time you receive viewDidUnload, the view has already been released, so you can't use it at that point for other cleanup. Instead you have to override didReceiveMemoryWarning to do the cleanup before calling [super didReceiveMemoryWarning].
In iOS 5.0, you can do the cleanup in viewWillUnload instead of overriding didReceiveMemoryWarning.
Consider these two things:
There's no problem with retaining an object several times provided that each retain is balanced with release. With respect to properties, this just means that you should set your property to nil when you're done with it.
The basic idea behind memory management in Objective-C is that you worry about retaining the objects that you're using and let other objects worry about the objects that they're using.
Considering these, I'd advocate using retain. If you rely on he fact that a view retains its subviews, you've suddenly made your code dependant on external behavior. I'm not saying that UIView is likely to stop retaining its subviews, but if you keep a non-retained reference to a subview and later remove that subview from its superview you're code is likely to crash.
Some folks do use assign for outlets pointing to subviews when they know those subviews will never be removed. Personally, I don't see the point of relying on another object to retain something for you when retaining that thing yourself is so simple and cheap.
I'm studying memory managment in UIviewController, i'm a little confused, the important points to remember are:
viewDidLoad is called every time the view is shown, here I alloc variables of any kind.
viewDidUnload is called in case of low memory, I set all the property to nil.
dealloc, I release all property.
Is it all right?
Also, if I don't link a label to a IBOutlet, have I a memory leak or the system dealloc it anyway?
No. -viewDidLoad is called when the controller loads its view, not every time the view is displayed. Perhaps you're thinking of -viewWillAppear. Otherwise, your points are about right.
If you don't connect something to an outlet, the outlet will simply remain nil -- there's no leak. The label will generally be retained by its enclosing view, and will be released when the rest of the view hierarchy is released.
I want to ask a stupid question about the iPhone application. I am the green of the iPhone app. I read the following code in the Apple website.
MyViewController *aViewController = [[MyViewController alloc] initWithNibName:#"MyViewController" bundle:[NSBundle mainBundle]];
[self setMyViewController:aViewController];
[aViewController release];
And I have a question, how it means of the 'release' in the line 3?
Does it presents the memory clear? or the program take control of that object? or other meanings. Thank you very much.
When you alloc something, the object you get will have a retain count of 1 - this means that this object is currently being used by someone, so it should not be removed from memory. If you call retain on an object it will increase the retain count, meaning the object is being used by 2 things. If the retain count reaches 0, it implies that the object is no longer being used by anything and it can be removed from memory. You can decrease an object's retain count by calling release on the object.
In your example, aViewController is alloc'd and after line 1 has a retain count of +1.
It is then set as the view controller in line 2. This method is therefor taking ownership of the object, so should retain it for its own use.
Line 3, we don't want anything more to do with the view controller, so we release our hold of it. The retain count decreases by one - and it is now up to the new owner to release it when it is finished with it.
You might find it helpful to read through the memory management section of this tutrial
Whenever you call alloc, you own a reference to the object that comes back, and you must call release to indicate that you no longer intend to use that reference.
In the above case, you have allocated a new view controller and assigned it to a property of your class. Assuming the property is declared with the retain option, the property will acquire its own reference to the view controller by called retain on it. So there are now two active references to it. The property will eventually release its reference (either when it is assigned a different view controller, or when your class is finalised). But if you don't call release yourself, one reference will remain, and the view controller will never be freed.
In short, you must match every alloc with a release, otherwise things will leak.