My tableView wasn't loading because tableView:cellForRowAtIndexPath: wasn't being called. The NSLog messages that I have written inside tableView:cellForRowAtIndexPath: did not appear in the console. I had a weak NSArray #property called listOfItems. When I changed it to strong, the tableView finally showed it's contents. Could someone please clarify if tableView:cellForRowAtIndexPath: wasn't being called because the NSArray was weak. Is there a connection between the listOfItems property and the tableView:cellForRowAtIndexPath: method being called?
No object had a strong reference to the array. Your view controller had a reference, but it wasn't strong. This means that you don't care if it gets removed from memory, you don't need it to stick around. In this case, since your table relied on the data in the array, you don't want it to be removed from memory: you want it to stay around as long as the table stays around. To do so, you create a strong reference, which makes sure that that object isn't being removed from memory until that pointer (your property, in this case) didn't point to it anymore.
Related
In Objective C, if a ViewController has a UIKit object property, lets just say a view, and is instantiated in viewDidLoad, followed by being added to the subview, in order to remove it out of memory, both removeFromSuperview() and setting the object to nil must be done (if I'm not mistaken, but I could be...)
However, in Swift, only things with the optional type can hold a value of nil.
My question is, if I would like to animate things like UILabels or UIViews within my application, and later have them disappear (to both the user and removed from memory), would having that UIKit object being removeFromSuperView() be enough? or would I have to make all objects that I'm trying to animate optional, removeFromSuperView() and then set them to nil?
I apologize for my poor articulation. If further clarification is needed, please let me know. Much thanks for your input.
If you want the weak property objects to deallocate, then yes, you have to set them to nil or wait for the owning object to deallocate.
Objects in properties that are not weak will get a release call when the parent object is deallocated. This means the objects will also get deallocated if nothing else is keeping a reference to them.
If you create a temporary UILabel that's not a property of the View Controller and animate it and then removeFromSuperview() it, then it should disappear from memory as well.
As it was retained (refcount: 1) when the function creating the animation was running, later by the view hierarchy (refcount: 2), the function ended (refcount: 1), so only the view hierarchy was retaining it. If you removed it at the end of animation (refcount: 0) it is deallocated.
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.
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 have a bit of a problem in my code, and i'm beginning to wonder if it's a design issue..
I'm treating my appDelegate class as the primary model for my application. With the appDel class, I have a viewcontroller. In my appdelegate class I store an NSMutableArray called blocks which has all of my block object models. Similarly, in my viewcontroller I have an identical NSMutableArray called blockViews which stores all of my block object views. The way I update the view after receiving notifications from the model is through KVO. In my viewcontroller, I observe each location property of each block in my blocks array (in the app delegate), and update the corresponding blockView in blockViews.
I also have it set up so that whenever I add an object to my blocks array in the appDel, it adds an object to the end of the blockViews' array. Now, my problem arises when I try to remove an object from my blocks array (in the appDel class). I will not always be removing the last object, and so I am stuck as to how to get the actual index of the object I am trying to remove so that I can remove the corresponding index in my blockViews NSMutableArray.
In my observeValueForKeyPath method, the object being passed is the appDelegate class because I am observing the entire blocks array from my viewcontroller (I implemented the Indexed Array Accessors to allow for KVO notifications to occur), and because of this the object being passed into observeValueForKeyPath is in fact a reference to my appDelegateClass (which makes sense).
But, from this, I cannot obtain the index of which object was removed from the blocks array. Does anybody have any suggestions as to how I could alter this to provide an index, or a way to get the correct index?
Is there any way to observe an array for additions or removals, AND have the object being passed into my observeValueForKeyPath method be the block that was added/removed itself, instead of the appdelegate class?
Can't you use indexOfObject... (several variations) to get the index, and then remove it in both arrays? (You realize that NSMutableArray implements all the methods of NSArray, right?)
Is there any way to detect when an NSView will be dealloc'ed?
The reason is, I have some simple delegates (such as an NSTextField delegate that handles -control:textView:doCommandBySelector: to allow the return/tab keys to be entered). I'd like to just stick this delegate object in the nib, wire up the NSTextField's delegate connection and have it work.
And it does work, but the delegate is never released even after the NSTextField it is linked to is released, so the delegate object leaks.
I'd like the delegate object to be able to detect when the NSTextField is dealloc'ed, but I can't think of any way to do this, which leaves me having to store a separate link to the delegate object from some other controller and manually release it at some point which is very much less than ideal. Any ideas?
I've had a good look for this previously, and there doesn't appear to be any way to observe when an object is deallocated. I have seen one way to do it in a weak pointer class, but it involves isa swizzling, which can get nasty. Here is the website: http://www.cocoadev.com/index.pl?WeakPointers
Objects that are created from a nib file should be deallocated when the owner of the nib is deallocated, unless they are retained elsewhere. For example, when an NSWindowController is deallocated it will release any objects that were created when the nib was loaded. If your delegate objects aren't being deallocated, maybe it's because they are retained elsewhere, or there is a retain cycle.