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
Related
My document-based app immediately terminates the document upon cmd+w and it is not saved. How can I react to this and either prompt for saving the document or automatically save it?
Use the NSDocument method updateChangeCount(_:) to mark your document as edited, and Cocoa will take care of the rest!
Furthermore, if you use NSUndoManager for all changes, it updates the change count for you!
Most of the time, you should look for these kinds of "hooks" into existing Cocoa functionality, so that your app behaves exactly the same way as other OS X apps, and so that you inherit new features when new OS versions are released.
My OS X app has two windows. I've put one in MainMenu.xib, and the other in SecondaryWindow.xib.
When I run my app, the window in MainMenu.xib shows. I also want the second window in SecondaryWindow.xib to show at startup. How do I achieve this? Was it a good idea to use a separate xib file for the second window?
If you'd like to do it without a line of code, add NSWindowController object to MainMenu.xib and write second xib's name to it's property. When MainMenu.xib is loaded, this window controller will be created and will load the second xib, causing the second window to pop up if it's configured to be visible on startup.
Or do it programmatically from e.g. applicationDidFinishLaunching: or awakeFromNib:.
Besides being an instrument for breaking UI into independent modules, separate xibs make it possible, for example, to unload some of them and save memory (e.g. when window is closed), or load one multiple times.
In your case, if both windows always have to be in memory, you can safely keep them in the same xib.
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 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.
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.