I've recently converted my iOS project over to ARC. One of the view controllers is not calling its dealloc method and is not being dealloc'ed according to Instruments.
I've double checked all of my properties and set the appropriate ones to weak. I've also made sure that anything that has the view controller as a delegate has it unset on viewWillDisappear but the view still sticks around in memory.
I'm a newbie at Instruments: how can I tell what is retaining this view?
Well if you are really stuck and the program is complex (or abstracted, in the case of ARC), you can bring out the cannons:
Open your Xcode project
Choose the executable (if needed)
Press cmd+i (Profile)
Choose the 'Leaks' Instrument in Le Wizard (if needed)
Press Return to begin profiling
Exercise your app
Press 'Stop' in Instruments
Verify the 'Allocations' instrument is selected
Click and Hold the Popup Button named 'Statistics'
Select the Objects List item
Locate the allocation you are interested in, among the records in the Objects List
Select that allocation/object
Click the 'detail arrow' to the right of the address in the table view cell of that allocation
Now you see all events related to the allocation (allocation, free, reference count operations)
Press cmd+shift+e for Extended Detail
Go through the events in this list, and locate the imbalance you seek.
Related
Kind of a newbie question, so forgive me if I'm missing some basic concepts...
I have a view controller within a window, which contains multiple NSTableViews, each of which having a variety of associated observers added via addObserver. These work fine and as expected, with notifications going to each of the correct table views. However, if I close the window, then open a new window (of the same type), posted notifications are being sent to the table views of the window that was previously closed.
I was under the impression that as of macOS 10.11 observers did not have to be explicitly removed, which I would assume would happen when the original window is closed... UNLESS I'm missing something fundamental about closing windows. At the moment, I don't do anything special when the user closes a window, and the window just vanished from the screen. Do the views created in my viewDidLoad method live on even after the window is closed? Or no I need to explicitly dispose of these views in a method such as viewWIllDisappear?
Thanks!
Even when object you added as observer is disposed the observer is not. According to official documentation you have to pair each addObserver with corresponding removeObserver. This is true and for NotificationCenter and for KVO. By the way adding object as observer does not increase its owners, so under correct memory management left observer result in run-time crash - that is why needed paired removeObserver (if there is no crash in such situation it means there is leak).
The place where to do this depends on usage. If you add observer in viewWillAppear then it is better to remove it in viewWillDisappear, if you add on creation then remove should be done in deinit
What's a smart method to track class properties history in Xcode ?
I have a zombie property, and I don't understand when it is over released.
Also, I don't want to introduce memory leaks by erroneously over retaining it in the wrong place.
Thanks
I'm not sure what you exactly mean by tracking the history but on overreleasing objects there is an excellent tool called Instruments that can be used in conjunction with the NSZombieEnabled flag. The latter enables tracking that catches access to already-released objects (e.g. when overreleasing you access the release selector one more time on an already released object).
To do this in XCode 4 you select your app, select it to run in the simulator and Choose (in the Menu) Run -> Profile. Now Instruments should launch and present a selection of profiling options. You now select Zombies, the app starts and as soon as you hit a zombie object, a little flag will pop up in the timeline. There (clicking the arrow) you can access the offending object, the object's history (i.e. who retained and released that object) and if you enable the right sidebar, you also get a stacktrace for every entry.
I would like to build something similar to the code-completion feature in Xcode 4. (The visual style and behavior, not the data structure type work required for code completion).
As the user is typing, a pop-up window presents other word choices that can be selected.
The Feature in action:
I'm not exactly sure where to start. I am mainly concerned with the visual appearance of the window and how I should populate the list with a given set of words. Later I will get into making the window follow the cursor around the screen and etc.
I am mainly looking for an overview of how to display such data in a "window", and how to cusomize the appearance of the thing so it looks like a nice little informational popup rather than a full-on OS X window.
Just add a subview to your current view that happens to be a tableview. Programmatically cause it to be visible on an event (such as mouseDown), and adjust it's position based on where you want it. You will need to instantiate the proper delegate/datasource methods, but it should be pretty straight forward. You will also need a source for the words you want to use in your autocomplete, and put them in an array or something for your tableview datasource to go through.
Like I said, it's not terribly hard, provided you are comfortable using tableviews and adding views to your existing view. If this doesn't explain enough, leave a comment and I can flesh this comment out more.
Add a (completions) subview to your view and set its visible property to NO. Create a separate AutoComplete object that includes the subview as a property and fills it with potential completions. Your controller can respond to key pressed (key typed) events and give the last word (substring the text from the end to the 1st preceding blank) to the AutoComplete on each event. The basic logic in AutoComplete could be something like:
Given an AutoComplete with a list of known words "dog, spaghetti, minute, horse, spare, speed"
When asked to complete a fragment "sp"
Then the following words should be offered as potential completions, "spaghetti, spare, speed"
Which would imply that you need to instantiate it with a list of words (this could be done in the init of your controller), and create a method "-(NSArray*) completeFragment:(NSString*)fragment;". You could drop this into an OCUnit test case and iterate over your implementation of autocomplete until you get it right. You would then write a method that takes the completions from AutoComplete and lists them in the subview. Even better you might create currentWord and potentialCompletions properties in AutoComplete that gets updated as you send it "newFragment:(NSString*)fragment;" messages. Throw that into OCUnit and work it out then use that potentialCompletions property to drive updated of a the subview (which is probably best modeled as a custom tableView).
I would like three menu items on the menubar with the keyboard shortcuts cmd-1, cmd-2, cmd-3. This I know how to do.
Each menu item would open up a different window (win1, win2, win3).
I want it so that only one instance of each window is permitted to be open at any one time (i.e. only one win1, one win2, etc).
How is this best approached?
If the windows in question are in the MainMenu.nib it's simple; attach the action to -makeKeyAndOrderFront: on each window.
If, on the other hand, they are not in MainMenu.nib, as is more likely the case if your application is structured in a sane fashion; things get a little more complicated. Long story short; you need to attach the menu item actions to appropriate methods on some manner of controller object (most likely your application delegate, although any controller that "sees" all the required nibs will do); and then have the controller in question send a similar message to its window.
This is generally a sensible approach, as you can have smaller controller objects attached to your windows that also act, if appropriate, as data sources for the various views in the windows in question.
It also allows for lazy loading of the windows, which is, at last count, a Good Thing™.
If this is some manner of document-oriented (not necessarily document-based) application, and the windows display some attribute of the currently selected "document" or piece of data; subclassing NSWindowController and loading the window controllers in your MainMenu.nib is probably a good place to start.
Note: If the objects responsible for controlling the windows live in the responder chain, they don't even need to be referenced in MainMenu.nib; you can just attach the appropriately-named IBActions (e.g. openDetailsWindow: or the like) used to open the windows to the virtual FirstResponder object. (Simply add the selectors to its list of known methods, and you're golden.)
Reedit: To make the window not appear in the windows menu, you can call [window setExcludedFromWindowsMenu:YES].
To check/uncheck the menu item is a bit tricker, as it requires your window controller actually knowing about the menu item; but as long as this is the case, it's quite simple, again; call -setState:, with the relevant state names (NSOffState, NSOnState), for example from the delegate methods called when the window is shown/closed. (This could, again, be encapsulated "inside" the application delegate; if you for whatever reason don't want your MainMenu.nib to contain the window controllers.)
I am currently working through the famous "Cocoa Programming for OSX" by Aaron Hillegaas.
In Chapter 12 he wants me to create an about window using
[BOOL] successful = [NSBundle loadNibNamed:#"About" owner:self];
which, by itself, works perfectly well. However, I am using the garbage collector and since I do not retain a pointer to that about window, it is garbage collected and thus disappears after a second or two. It works perfectly well if garbage collection is disabled.
Is there a way to create a window without holding a pointer to it and without having it eaten by the garbage collector?
You can retain the window with CFRetain, or use NSGarbageCollector's disableCollectorForPointer:. However, you can easily introduce a memory leak. Make sure whichever action you use to close the window also releases the window.
If the sender passed to the close action inherits from NSView, it will have a window property that you can use to get a pointer to the window.
However, this is not how Cocoa is designed to work. In Chapter 12 of Hillegaas' book, he has this to say:
When sent showWindow: for the first time, the NSWindowController automatically loads the nib file and moves the window on screen and to the front. The nib file is loaded only once. When the user closes the [window], it is moved off screen but is not deallocated. The next time the user asks for the [window], it is simply moved on screen.
If you deallocate the About window, your app will either crash or appear not to respond the second time someone opens it.
Edit: An alternative (but one that doesn't give you practice in loading nibs) is to add the About window an an NSWindowController to the main nib (make sure you uncheck the About window's "Visible At Launch" attribute). This makes a mess of Main.nib, but can be done entirely in Interface Builder. Connect:
the About controller's window outlet to the About window
the About controller's showWindow: action to the About menu item
if you've your own close button in the About window, connect it to the window's performClose: action.
As for how advisable this course is, Apple has this to say:
A very simple application might be able to store all of its user interface components in a single nib file, but for most applications, it is better to distribute components across multiple nib files. Creating smaller nib files lets you load only those portions of your interface that you need immediately. Smaller nib files results in better performance for your application. They also make it easier to debug any problems you might encounter, since there are fewer places to look for problems.