Documents and Nib files: What does apple mean by "Document"? - objective-c

I don't understand how the term "Document" is used in objective-C and cocoa. When I build an Application, why do I have an "Document"? That makes no sense to me. I could have an Application like an Image Editor, wherein I can open like 100 Images at same time. So every Image is a Document and has its own Nib file? Can someone explain that term in a way that's humanly understandable? Best would be a lot of examples, I think.

From my ancient but still mostly relevant Cocoa NSFAQ (Not-so FAQ):
Q18
Why would I want a Document subclass?
A18
Because you have a central data model which needs an object to manage it.
In more detail, don't always think Document==File. The conceptual Document in most Mac applications may indeed map to a single file on disk but is also often a central object (Model in classic MVC design).
If you're using a database, the Document might manage the database connection and even end up saved as a file persisting that connection.
For your photo library, the Document might be singular, just containing some settings, or you may have multiple Documents corresponding to different layouts and filters as to which photos are visible.
There's no reason why you can't have more than one Document or even hundreds open if you want to go that way - the Document is a way to provide data to views and you can have hundreds of instances if you want.

Document-based, in terms of the Xcode templates, essentially means an NSDocument subclass. NSDocument and NSDocumentController provide an abstraction that makes it simpler to support multiple documents.
You are correct, you can hand-code it without NSDocument just fine. However, NSDocument does make it a bit easier.

Related

How to use Core-Data best in complex Apps

I am a Mac App Dev and have some questions about how to use Core-Data correctly.
I have multiple TableViews and they are all playing around with the same data (which I want to save persistently with Core-Data). I know the central part of Core-Data which I have to work with - NSManagedObjectContext and I know how to create NSManagedObjects and save/edit/delete these in the persistent store.
But actually I'm wondering about how to organize all that together with multiple ViewControllers,Views,Tables,.. efficiently and without merge conflicts. I've read about some approaches for that: one was by passing the context down from the delegate through every layer of your code. Somebody else suggests to create a singleton-class, let's call it DatabaseManager, which holds the NSManagedObjectContext instance and you go and ask it from there. (I especially like this approach, don't know why.) Or just ask the delegate every time with [[NSApplication sharedApplication] delegate], does this have any disadvantages?
Okay, a lot of questions here but that was only about the How. Now I want to know about your recommendations of where I should actually do all interaction with the managedObjectsContext. (to be in compliance with MVC and don't mess up my code and make it more complicated than it has to be..)
Should I save stuff to Core-Data in my NSTableViewDelegate/-DataSource Classes directly or just fire up an Notification for someone else?
Should I implement some instance methods for my Model-Objects (like -(void)saveInstanceToDatabase,..) to encapsulate Core-Data-Interaction?
Ok thanks in advance for all the brave guys who read until this point and give me some kind of response :D I always appreciate code-examples!
After years of working with Core Data... I've come to the conclusion it's not very good. There are some serious flaws in it's design that can only be solved properly by abstracting the whole thing away.
I recommend implementing your own model for manage objects, which uses core data underneath but does not ever expose it.
Your views and controllers and application delegate and all of that should not ever touch core data at all. They should talk to a series of classes you create yourself, which has been custom tailored for your particular application.
That object layer can use core data underneath, or it might use something else like FMDB or NSCoding or even just plain old NSData objects (this is the fastest option, if you need extremely high performance with large amounts of data, especially when combined with features like NSDataReadingMappedIfSafe).
Start with Core Data. Look at the other options if you have problems. Having your own layer on top means you can easily abandon it in future. And many developers have chosen to move away from Core Data shortly after their app ships to the public. Often due to unsolvable bugs or performance issues.

Sharing NSDocument subclass between multiple NSWindowControllers

I have a application that isn't currently a document-based application (because I thought it would be more trouble than its worth). However I've been thinking it may possibly be worth it now, but there is one issue I haven't worked out yet. Sharing NSDocument subclasses between multiple windows.
So do subclasses of NSDocument have to be tied to a single NSWindowController, or can I share these between multiple windows? The reason I ask is my applications files are likely to up 100MiB (or larger) and its also likely that a user will open the same file in more than one window. Also these files take a relatively long time to process, so allowing multiple windows access to the same NSDocument would be excellent. Also, the files are updated very quickly with lots of data, so synchronizing multiple instances of the same document would use a lot of CPU time.
Has anybody done this, or can it even be done with a Document-based application? Any advice on this topic is greatly appreciated.
You should be able to use the method - (void)addWindowController:(NSWindowController *)aController found in the NSDocument Class Reference to do just that. There will be a lot of logic to let it know where to send what data, but this will at least give you control over several window controllers linked to the same document
So far this is the best answer I've found, which doesn't directly answer the question, but deals with many of the same obstacles I'm facing. Hopefully someone else has a better, more detailed and direct answer for me.
http://www.cocoadev.com/index.pl?DocumentBasedAppWithOneWindowForAllDocuments
The Document architecture wil help you to manage multiple models - ie. if you want the user to have multiple models open simultaneously and be able to switch between them, it could be of benefit to you.
It doesn't stop you from doing anything, it doesn't make otherwise easy things difficult. Handling the Windows and GUI is still down to you, and if you are unsure how to structure this, it wont make any difference if you use a document or not.
If the contents of a window can change over time to represent different documents - what happens when many documents are open? This can be a difficult problem to solve, and i don't really mean from a technical point of view (changing a window's contents is as easy as window.contentView=newView, right?).
It sounds like you have many misconceptions about what the document architecture is and what it can do for you.
The default is each document has one dedicated windows controller. But you can override
- (void)makeWindowControllers
to create your own windows controller and add them to the document as Slev mentioned.

NSDocument vs sqlite records

I'm developing a cocoa application that could be used to manage customer and employee details in a small business.
When I read through the NSDocument architecture, I believe that the document/window management and workflow it gives you is excellent, however I am trying to figure out how that architecture fits into (if at all) an application that reads each record from a database, instead of from individual files.
I think I could "fudge" some of the file-based operations in the workflow to read individual database rows instead of files, but I wonder if that is going to bite me later on.
Am I better off just ditching the NSDocument path and building my own Window- and Document-Controllers? Any thoughts?
Along the same lines, are there any books that describe "application design" in the cocoa world? The Hillegaas book is outstanding for describing the bottom-up approach, but it would be nice to get some guidance about designing/building real-world, complex apps (for those of you with Eclipse RCP experience, there is a great book called "Eclipse Rich Client Platform: Designing, Coding, and Packaging Java Applications" - something like that for Cocoa would be awesome). Anything out there like that?
You could either have your application backed by one sqlite database or store all the records in a file.
NSDocument-based applications are for when your application reads/edits/creates a file. Applications like this include text editors, image editors, pdf viewers, that sort of thing.
If you wanted your users to be able to create/edit/delete the databases you create and perhaps keep several different databases on their computer, NSDocument makes that super convenient.
If your intent is to give your users access to one single database that they an add/remove records to, you don't want to bother with NSDocument.

What is a document in this context?

I'm a bit confused regarding the document architecture. Lets look at MSN for Mac - what would the document be in that application? The contact list? The text we insert to talk to other people?
When the need comes to save or read data into the application, what type of data should it read? Contact lists or chat logs?
Update:
Pushing this a bit forward, what is a document? A file type that the application is prepared to open?
Maybe MSN for mac isn't a document-architecture application. Not every program needs to use the same system.
In general, a 'document' is just what you say; the data that makes up your application's files. It can refer to documents on disk - which have a particular filetype, or runtime documents, which are a collection of interrelated model objects in your application.
Your application might support saving/loading documents of various different on-disk filetypes, but they could all be represented with the same model objects at runtime.
MSN clients and other chat applications create and view logfiles. They can't edit them, as far as I know, but that's a feature - they're logfiles after all. There are easier ways to create such logfiles, but there is a nice pseudorandom quality to the way these applications do it which some people prefer. Sort of like SO but different.

Internationalization with Nibs. Is that really a good idea?

In the Apple Docs they say that a Nib enables internationalization by just translating the Nib into many languages. I am thinking now about a worse but realistic scenario: You have made a huge user interface. Then you translate this into 25 languages. So you get 25 different Nibs. You also get a huge redundancy in styling and defining the UI: 25 times the same stuff. Same Bindings, same everything. Just text is different.
So, I really think this is a very bad approach. Instead, I would prefer to just link in all texts from a resource bundle or something like that. Just a file with text strings, which is linked in at run time from the appropriate language resource. Then you only have "trouble" linking in the text which really doesnt make any fun. But then, you can do changes on your UI ONCE without having to do the same step 25 times over and over again. A new Binding in every nib. That would be so horrible!!
Now, please tell me I got that wrong. Apple does not assume that we do something so creazy?
The localization situation is not ideal. Although Cocoa UI elements support some dynamic flexibility in their sizing (the ausosizing flags), it's very difficult to arrange them in a view so that they will accommodate any sized text.
As Heng-Cheong points out, this usually means that some adjustment to layout is required on a per-localization basis. Apple supports a process called incremental localization with a tool called "ibtool", bundled with your developer tools. The process is far from intuitive and seems to have some subtle bugs, but it helps to make the process easier than, say, separately maintaining 25 different nibs manually. The process essentially involves mapping changes you make to your primary nib onto the other localized nibs. Apple describes the process in more detail:
https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/LoadingResources/CocoaNibs/CocoaNibs.html
In order to avoid this painful process, some people take a different approach. If you compromise on the layout of your views, you can achieve a situation where every UI element accommodates the largest localized string. Using the alignment features of text fields, etc., you can thus arrange an acceptable layout, though the extra spacing required for the localization with the largest strings often causes a less-than-ideal layout for the language whose strings are shortest. If you take this approach, you need to design your nibs so that a controller class populates the nib's UI elements with the correct localized strings at runtime.
Finally, some developers go so far as to apply their own relayout to the elements in a nib, optimizing them for the sizes of the strings that have been set upon them. This would be a refinement of the strategy above, where a single nib is used and manipulated at runtime to achieve the desired effect.
Sometimes, localization involve more than just replacing text, but changes in layout too. For example, strings in one locale/language may be significantly longer than in another, forcing a change in layout. Right-to-left language often will mean some changes in layout too.
Building on the previous two answers, there's a tool called iLocalize that aims to make the process easier than ibtool does (and it's older than ibtool). I've never used it myself, but my friend Evan uses it on both Adium and Growl and loves it.