I am familiar with iOS programming, but I don't know where to put my logic when I start a Cocoa project for OS X. Are there any good online resources for transitioning to OS X from iOS?
EDIT:
Thanks for the help so far. My main question is where my code goes in the default template.
My main question is where my code goes in the default template.
Assuming a single-window app, I make a separate custom controller to own that window, and I have the application object's delegate own that controller.
So:
The application object's delegate
Owns the custom controller.
Creates it in applicationWillFinishLaunching: (note: not Did; I change this).
Releases it (and nils out the instance variable) in applicationWillTerminate:.
Does not own the primary window (I remove that ivar and all references to it).
Responds to applicationShouldTerminateAfterLastWindowClosed: with YES, so that the user can quit the application either by specifically quitting or by closing the primary window.
May also respond to application:openFile: or application:openFiles:, typically by passing the file(s) along to the controller to import or something.
The MainMenu nib
Owns the application's delegate.
Does not contain the primary window (I remove the blank one).
The primary-window controller
Owns the primary window.
Owns the model displayed in the window.
Creates initial/empty model in init.
Loads the primary-window nib with itself as owner in init.
Closes and releases window (first) and releases model (second) and subordinate controllers (third) in dealloc.
The primary-window nib
Named similarly to the controller; e.g., “SnippetListController” for the controller and “SnippetList” for the nib.
Contains the primary window.
Primary window has “visible on launch” (really on nib load) turned on and “release when closed” turned off.
The advantage of all of this is that the lifetime of every object but the application's delegate is clear and explicit, as is the area of responsibility. My application's delegate is little more than that; the only thing it does that isn't specifically an app-delegate job is owning the primary-window controller. Likewise, the primary-window controller does nothing but own the primary window and whatever model I have to show in that window. And at quit time, everything but the application's delegate gets deallocked.
For document-based apps, I stick pretty close to the template. I delete any template methods I don't need to customize, and I may switch one or both of the I/O methods to one of the other versions (e.g., from readFromData:ofType:error: to readFromURL:ofType:error:), and maybe delete the write method if I'm writing a viewer only; that's about it.
Dive in.
Seriously just jump in with both feet. Find something that you want to make and just make it.
From what you've said you've already got a fair bit of experience with Objective-C and Cocoa and most things carry straight across.
Related
I have an application that's not based on storyboards, but rather xib files. Main.xib contains the main application window. However, it's just a window. There's no NSWindowController. How can one be added?
Ok, figured it out. You simply add a new object to the scene, change its class to whichever NSWindowController subclass you want it to work with, attach the window to its output, then set an output to hold the window controller itself. I recommend on the app delegate.
I took things a step further by also changing the window to not show on launch, and I removed the window from the App Delegate (since it now has a reference to the window controller and thus the window indirectly already). This way I can center the window before actually showing it.
Only caveat to look out for is that you won't get the window-loading overrides since the window is handed to the VC, not loaded by it, so any code you need to run only when the window is set, simply override the window variable and add a didSet section. Works like a charm!
Still, I may try to dig deeper to see if I can update the Window controller to load the window normally so I can get those events as designed.
I started a Document-Based project on XCode for a MacOS project. I realize now that i don't need this functionality and its potentially causing problems and delays in my progress.
Is there a way to disable this functionality?
To keep documents from opening, all you have to do is implement application(_: openFile:) or application(_: openFiles:) in your app delegate. These are the methods that are called when any file is opened, and by default these messages are just shuffled off to NSDocumentController, which is responsible for the whole document-based-app thing. If you implement one of those methods to do something other than invoke the NSDocument architecture, you can keep the ability to open files while removing the rest of the document-based system.
Keep in mind, though, that menu items such as Open and Open Recent will still be routed to the NSDocumentController and use the old behavior. To completely remove the document-based functionality:
Get rid of your NSDocument subclass(es) (or just disable them)
Remove the references to those classes in your Info.plist
Remove any document-specific menu items (like Save)
I'd recommend that you hang on to the Open item; being able to open documents is handy even in a single-window or shoebox app.
If you have an NSDocumentController or a subclass in your main nib file or main storyboard scene, remove it or at the very least make sure that no actions are explicitly routed to it
If you have any code that uses NSDocumentController, get rid of it
I'm writing a single-window, non-document-based app for Mac OSX. I'm coming from an iOS project where we avoided Interface Builder like the plague. I'm forcing myself to use it for the Mac project just for the experience.
My program's menu and its main window are in two different nibs. The window contains a toolbar. Of course many of the toolbar and menu items are representing the same function, so I want to route them through the same code. Initially I put all the handlers for the menu/toolbar in my application controller and wired them to the menu/toolbar using Interface Builder. Then I realized many of the operations affect the window and its contents, not the entire program, so I thought it more appropriate to put those methods in the main window controller.
To support this I added an NSObject to my window nib, changed its class to my window controller class, and wired those up.
Of course what I'm seeing now is that my app controller creates an instance of the window controller when it creates my one-and-only window, AND the nib for the menu creates another instance of the window controller when it builds the interface from the nib. That may or may not prove to be problematic, but it seems wasteful. Seems like everybody should be talking to the one-and-only window controller I create in applicationDidFinishLaunching.
So question 1 is "How do I tell my program to use the existing window controller when building the user interface from the nib?"
If the answer to question 1 is "You don't" then I'm looking for a suggested organizational pattern to follow. Do I put all the menu/toolbar handlers in the app controller and route from there? Or is there some other common way of doing this that is consistent with the zeitgeist of Cocoa?
I am currently working on a web browser project from Apple's Mac Dev site.
I have completed the project, but have a bit of a problem. I have created the project as a Document-Based Cocoa Application, and now whenever I enter text in any text field on the web, the red traffic light button shows a black dot in the middle that signifies an unsaved document. When I try to close the window or entirely quit the application, a warning pops up like that in TextEdit or Pages where it alerts me to unsaved changes. It's not too much of a problem, but I would like if someone could please tell me how to remove that feature of a Cocoa Document-Based Application.
Why a document based application if your application isn't document based? Document based applications inherently include the concept of open and save; it is a fundamental part of what they are.
In any case, you could "work around" this by configuring NSDocument appropriately; override the proper methods and otherwise muck with the change count & dirty state of the document. But it'll be just that, a workaround. The documentation for NSDocument has all the information you need.
A cleaner overall solution would be to refactor your app to not use NSDocument. Creating multiple windows is quite straightforward in Cocoa (an action method tied to a menu item where the action method loads a nib file; if I remember correctly, you could even use NSWindowController still).
An easier solution would simply be to override the isDocumentEdited method to always return NO.
- (BOOL)isDocumentEdited {
return NO;
}
I'm writing a document-based Cocoa app that's basically a graphical editing program. I want the user to be able to show/hide non-modal windows (such as an inspector window). Since these windows would be shown/hidden from menu items, where is the "best" place to implement the actions, such as - (IBAction)toggleInspector:(id)sender?
I've seen that in the Sketch example code these are implemented in the app delegate, and the window controller instances are kept there as well, but that feels like more of a convenient place to put it than the most "graceful" place. Additionally, since this inspector would only be relevant when a document is open it feels like it should be associated more with the document's main NSWindowController than the app.
Additionally, since this inspector would only be relevant when a document is open it feels like it should be associated more with the document's main NSWindowController than the app.
No, because the Inspector is shared amongst all documents; there isn't one Inspector per document.
Remember that a single process can have multiple documents open; these are not multiple processes, one per document, as on Windows, but multiple documents within a single process. There is one Inspector per process, shared amongst all of the documents, and it applies to whichever of those documents is frontmost at the time.
I would give the Inspector its own controller, instantiated in the MainMenu nib.