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;
}
Related
On Mac it is usual that there is a "hidden" main window.
The usual example is "Text Edit". When you open a file you with you don't see a "main frame". Instead every single file will be opened in its own "Text Edit" instance. This is OSX way of emulating the so-called MDI interface.
However, there is an exception. If you open Xcode and open the project there, you can click on the file and it will be open inside the main Xcode window. And if you double click the file it will be opened in its own independent editor window, keeping the main Xcode window visible.
My question would be: do I need to do anything special in order to make my program behave like an Xcode? Should I use different class for the main frame or maybe react differently on the opening document event?
Any hints/pointers where to look or even to the official Apple documentation would be helpful.
The TextEdit behavior you're describing is much more like “SDI” than “MDI”, and the terms “SDI” and “MDI” weren't even needed until Microsoft invented MDI long after Xerox invented the SDI-type interface of which macOS is a derivative.
Anyway, I think you are misunderstanding Xcode's behavior. You seem to think “its own independent editor window” is a different kind of window than “the main Xcode window”. But in fact the new window is of the same kind as the old window, with some optional parts hidden. You can show those hidden parts and make the new window look exactly like the old window. Demo:
The ability to open multiple windows showing the same document (or, in Xcode's case, project) is a matter of software architecture. If you carefully design your app so that multiple windows can share a single model object graph, and can be notified and redraw themselves when the object graph changes, then you have an app that supports multiple windows showing the same document. If you want multiple kinds of windows showing the same document, nothing about Cocoa stands in your way. As a matter of fact, Xcode does have at least one other kind of window in which it shows some properties of a project:
That project settings sheet is really another window; macOS keeps it attached to the main window, but it is in fact an instance of NSWindow (or a subclass of NSWindow), no doubt with its own custom window controller that references the same project objects as the main window.
If you use the Cocoa NSDocument architecture, then a small amount of multi-window support is built-in: an NSDocument knows about its associated windows (via their window controllers). If you want to use the NSDocument architecture, you should read Document-Based App Programming Guide for Mac.
It is unclear what you are after. The traditional Mac UI has been one window per document - i.e. SDI with a single instance of the app running multiple windows - but there has always been the ability for any app to organise the content of that window as it sees fit, including showing multiple "documents" within one window - i.e MDI type UI.
Apps approach such "MDI" in different ways, e.g. some use panes (views) and others tabs. From macOS Sierra the standard NSWindow supports tabs, this system is (semi)automatic for standard document apps. Read Apple's NSWindow Automatic Window Tabbing section in the Sierra release notes for more details.
If you wish to use multiple panes - e.g. like Xcode - you just use views (NSView) and arrange them how you wish.
HTH
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 have a question regarding enabling the File Open menu item for a OSX Cocoa App.
I have created a openDocument method in the AppDelegate and hooked up the menu item to the method and have verified the method gets called when I click on the file open menu.
- (IBAction)openDocument:(id)sender
My question is, is this really the way to implement the file open menu functionality? I was half expecting Cocoa to automatically display the open panel dialog instead of me having to write the code in the openDocument method to do it. Is this not the case?
NSDocumentController has a default implementation of openDocument:.
For non document-based applications, you have to provide a custom implementation (like you did).
The reason probably is, that for document based apps, the document controller can create an instance of NSDocument with the contents of the URL returned by the open panel.
For other apps, it's less obvious what the app should do after the user selected a file. So you have to specify that behaviour via code.
If your app fits the document-based model, you could take a look at the Document-Based App Programming Guide. You get a lot of default behaviour for free when adopting the Cocoa document architecture.
Xcode creates all necessary classes when you check the "Create Document Based Application" checkbox in the "New Project" wizard.
I have continued work on an app made by another. It looks in relevant parts identical to the standard NSDocument window-based app that you get when starting a new project (where the Window menu works like normal, ie. the NSDocument appears in the Window menu with the title Untitled).
But in this app, something seems to have happened to the Window menu or the app, that has somehow disconnected this automated behavior from the NSDocument.
Quite substantial work is needed to get this finished, submitted, and later rejected (by reviewers) app into a fresh project.
I'm looking to the experienced Mac app devs for:
What requirements/dependencies need to be fulfilled for the NSDocument to appear in the Window menu as normal?
I have checked MyDocument.h/.m (they are the standard stubs, virtually unchanged), and properties and outlets/delegates in MyDocument.xib, MainMenu.xib (none seem to be missing), and -Info.plist (which is identical to that of a New Project app). I'm experienced with XCode and Cocoa Touch, but not yet with Cocoa.
I'm willing to check things and write test code and give quick feedback, if you would help me over this last hurdle :)
I just had the same problem, and solved it by creating a reference to the window, and showing the window when the nib gets loaded:
- (void)windowControllerDidLoadNib:(NSWindowController *)aController
{
[super windowControllerDidLoadNib:aController];
[window makeKeyAndOrderFront: self];
}
The cause of the problem is still unknown to me. If after trying that it doesn't work, try debugging it. You may discover the real cause, for example the window may have been already deallocated because there isn't any strong reference (not even in NSApp) to it.
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.