Adding non-model nodes to an NSTreeController - cocoa

I have an NSTreeController that manages an entity is a core data model and an NSOutlineView that displays this tree.
I would like the tree to display some special nodes that do not correspond to entities in the underlying core data model. How would I go about doing that? Should I subclass NSTreeController?

Keep in mind you don't have to use NSTreeController even with Core Data. I've always avoided it since it had a pretty bad reputation back in 10.4, even though I heard 10.5 improves things somewhat. In any case, using NSOutlineView's data source methods will give you full control over what's included in the UI. Subclassing NSTreeController might work, but it'll be more challenging than if it were an array controller because it uses shallow proxy objects, not your actual core data entities.

Related

Core-data raises "The file has been changed by another application"

When changing data in my core-data application, a error message comes up:
The document “xyz.sqlite” could not be saved. The file has been
changed by another application.
In fact, there is no other application that has changed data. I observed in addition, that the undo management is not working well then.
Probably, I should not use more than one (unique?) Arraycontroller bound to the managedObjectContext for one entity ?
In my app, I use a classical master-detail relationship setup with 2 controllers for each entity - and 2 table views to display the data.
But, in addition I want to present a list of all details, where I can change the master. Therefore, I am using another Array controller bound to the same managedObjectContext. This one does not have a content set to the master, so it will have all detail objects. Using this approach makes it easy to manage the relationship in the associated tableview (by simply binding "selected Object" to the relationship of the detail) - but it seems to impact the app.
Does anybody else face this issue ? Any idea is welcome !
Core Data on the Mac has never dealt well with multiple programmatic changes to the underlying data, especially in document-based apps. See, for example, autosavesInPlace causes New Document save to fail.
I think you're on the right track by using the same MOC for all of your views. If you use multiple MOCs, you ave the risk of getting the data out of sync between views. Using Cocoa Bindings on the array controllers ought to be keeping everything in sync.
Is there a situation where you're making programmatic changes to the data in the background? Those should probably be done in a child of the viewContext. Or take other steps to make sure they get synced to the viewContext.

Dealing with NSManagedObjects when using MVVM

I've been struggling with a good answer to this one for a while:
How do you deal with NSManagedObjects as the Model in MVVM?
I've tried a few different approaches:
Retaining a copy of the NSManagedObject on the ViewModel — although this seems a bit dangerous to me, with the potential for threading issues
Unpacking the NSManagedObject into the properties I actually use on the VM via an -initWithModel: method — this would mean I no longer receive any updates to the NSManagedObject after the initial initialisation
Retaining a copy of the NSManagedObject's NSManagedObjectID, and using an NSManagedObjectContext specifically for each ViewModel instance to retrieve and monitor a private NSManagedObject and it's attributes — this seems a bit heavy to do this for every ViewModel instance (and potentially quite fragile)
None of these seem ideal. I have an idea in my head that it might be best to combine passing in an initial NSManagedObject instance via -initWithModel:, but only retaining the NSManagedObjectID, then listening for core data save notifications and weeding out any that don't relate to the retained object ID.
What I would do, and I don't know if this is necessarily the best practice, is pass in the model and then bind properties of the view model to (possibly mapped) properties on the model. That way you get updates through the view model. It does leave a little bit open to threading problems, but you can use deliverOn: to ensure that updates are always delivered on the main scheduler.

Cocoa MVC ≠ actual MVC?

Today I was getting some refresh about software design patterns.
In particular I was wondering about the difference between MVC and Three-tier-layer. Basically, from what I read on wikipedia and other sources, the main difference between the two is the components interaction:
A fundamental rule in a three tier architecture is the client tier
never communicates directly with the data tier;
whilst
...the MVC architecture is triangular: the view sends updates to
the controller, the controller updates the model, and the view gets
updated directly from the model
Now: if we take the apple docs regarding this matter we see this:
And they clearify that Views and Model shouldn't communicate directly:
view objects are typically decoupled from model objects in an MVC
application
and
When a model object changes (for example, new data is received over a
network connection), it notifies a controller object, which updates
the appropriate view objects
And so on.
So, what's the matter here? Is Cocoa adopting its own idea of an MVC, regardless of the common one? Or am I missing something in the common way of seeing an MVC architecture?
While it can be said that Cocoa's version of MVC is a sort of subset of the actual definition of MVC, they are not separate entities. The Cocoa version of MVC typically revolves around the use of a View (typically an NSWindow and/or an NSView), a controller (typically an NSWindowController), and a model layer (anything from a simple array to a Core Data stack). The separation of powers in this model is clear, but where in the 'tier' structure that Wiki defines should each of these belong?
I would argue that the Controller and the View are a part of the client layer. Not only is the controller responsible for the delegation between the model and the view, but it is responsible for responding to user events and determining the correct course of action to take during non-framework error handling. By taking this approach to MVC, you can now begin to see how Cocoa does, in fact, satisfy the broader definition of the pattern.
A fundamental rule in a three tier architecture is the client tier never communicates directly with the data tier;
This one's probably the hardest to reason about of the 3, and it involves delving into what "communication" actually means in the context of the pattern. When we say communication, what we mean is that the controller has no direct involvement in the actions taken by the model. That's not to say that the controller cannot order a change in the contents of the model, but rather that the controller does not have a hand in how the model updates itself. The controller acts as a director, not an implementer, which vastly simplifies the creation of a database layer, and is one of the reasons that Core Data and SQLite3 exist as external frameworks rather than as Foundation classes.
view objects are typically decoupled from model objects in an MVC application
That brings up one of the age-old taboos when programming with the pattern: making your views too smart. The controller provides a solid barrier between the model and view, such that the controller acts as a director and a filter for content from the model layer. Without any such barrer, say a tableview, would have to ensure that every cell had a copy of the data from the database, and that each cell knew when and how to update itself when a change is propagated in another cell. In Cocoa, this is where our NSWindowControllers come in. They manage the display of a root view and act as a barrier between some model and the content of the view it manages. Though, it is important to note that the controller objects in Cocoa are view-biased, mostly because it would be nearly impossible to provide a generic outlet to any kind of model layer without quite a bit of unnecessary glue.
When a model object changes (for example, new data is received over a network connection), it notifies a controller object, which updates the appropriate view objects.
That's the way it should be, for the reasons I've laid out above. But, to build on the networking example you've given, consider this:
Given an NSOperation that fetches data, and a controller that manages a tableview, you would probably not like the controller sticking its fat fingers into the operation, nor would you like the tableview to receive raw NSData and have to spend valuable rendering time processing the result and displaying it.
And so on. So, what's the matter here? Is Cocoa adopting its own idea of an MVC, regardless of the common one? Or am I missing something in the common way of seeing an MVC architecture?
I guess the conclusion I would draw from this is that your definition of the separation of powers in MVC and in how Cocoa does it is off. Cocoa is fairly rigid about adhering to the pattern, though there is an interesting contemporary movement within the Objective-C community towards MVVM.
You are correct the MVC practiced in most cocoa apps is not the MVC as it is defined in the text books. There are many variations of MVC employed by different frameworks. The MVC employed by tools with visual designers are heavily influenced by their visual designer implementation. With XCode you have story boards and nibs. The cocoa libraries and the way concerns are separated are influenced by this. If you want to take advantage of these tools, I would recommend understanding how concerns are separated by Xcode and work within this approach. Your code will coexist with it more smoothly. Apple documentation will help with this.
That being said, MVC is about separation of concerns. Separating concerns is hugely important in designing and maintaining software. Separating concerns properly can reduce dependency, reduce cyclomatic complexity, and make your code much more testable and maintainable. I think it is good that you are paying attention to this and whatever way you structure MVC should look to the reason why you are separating concerns as the guide to implementation.

KVO observation vs NSNotificationCenter observation

I'm wondering if there is a reason to use one over the other in KVO vs NSNotificationCenter observations. Performance, memory usage, speed, etc?
The two are not always interchangeable. Conceptually, KVO is only for observing a property of an object. For example, you can't use KVO to replace NSApplicationWillTerminateNotification because it notifies observers about an event happening, not a change in a property of an object.
As for performance and memory usage, they are both fast and use negligible memory. NSNotificationQueue has coalescing to stop floods of notifications. KVO doesn't have any coalescing as far as I know, which did cause performance issues for me at one point. I was observing hundreds of objects, and when a batch update happened to those objects I'd get hundreds of KVO callbacks. It wasn't a performance issue with KVO itself, but with my own code running as a result of the batch update.
Performance isn't really the issue, it's more about the best fit for the problem. If it's a property change, use KVO. If it's not a property change, use a delegate or a notification depending on whether you need a single observer or multiple observers.
A very old question, but thought of adding some points. I agree with Tom Dalling's answer, however, there are many scenarios in big applications where we tend to add observer for a property of an object and we cannot, or, we miss out removing them from list of observers.
Let us consider the following scenario from my application - A ViewController displays a snake object, I am observing for a property change on this object - "venom". So whenever viewController needed to show a different snake I would simply remove the view controller from observer of that snake object.
The app evolved to show a list of snakes instead of a single snake, this means I had to observe for property of all snakes in that object. Now, when an old snake is removed from the array I should get to know about this event so that I can remove view controller as observer from this snake object. To do this, I have to first observe for changes on the array itself. To do this I have to follow particular protocol to insert objects into array and remove them from array. This way the complexity builds on. We all do know the consequences of not removing observer from an object and if that object is released by the OS!
Above is just one example to cite, the main problem here is I cannot get the list of KVO observers for a given object to remove them from observers before this object gets released - This can be easily achieved by NSNotification and NSNotificationCenter. At times, I tend to be inclined towards using NSNotification over KVO, however, KVO always has edge over notification in terms of good design practice.

Data Storage question

Another newbie question: What's the best way to store data in a Cocoa application written in Obj-C? For example if I want to create a sort of "quizzer" that quizzes the user with pre-written (and user-written) questions? How would I store these questions and answers? Core Data?
Thanks!
Of course it's Core Data!
It will handle everything.. take a look here: http://developer.apple.com/macosx/coredata.html
It's a full API that can handle:
ORM between databases and run-time objects
persistence
automatic building tools (like an ER-editor)
it's ready out of the box, you won't need to implement almost anything.. you will already have access to your data by just querying it to the object controllers
Probably this solution is over-sized for your problem but you will learn how to use it with a simple case, and I will come handy in the future..
Core Data is certainly an excellent option, as #Jack has shown. There are some other options as well.
NSCoding - You can make your model objects conform to the NSCoding protocol (similar to java.io.Serializable), which means you'd be able to directly write them to files. I've found that this is a great option when I don't have massive amounts of data to persist, and the data that I am persisting has a relatively simple structure.
SQLite - If your data is very relational, you may want to consider using a database (probably SQLite) directly. Core Data is an object store, and while it handles things like relationships between objects, it doesn't allow you to do really useful things like INNER/LEFT/OUTER/CROSS/NATURAL JOIN or other multi-table operators.
NSUserDefaults - if your data is very small and is just essentially key-value pairs, then you can probably throw it all into the NSUserDefaults object, which will persist it for you in the preferences file. However, even if your data is simple, NSUserDefaults might not be the best option if you have lots of it.

Resources