Dealing with NSManagedObjects when using MVVM - cocoa

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.

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.

When to create a custom NSNotificationCenter?

I've been playing about with the NSNotificationCenter and I've been wondering when you would use your own custom notification center rather than the defaultCenter? And what would the advantages of this be?
Forgive my ignorance, but it seems like I could get along quite happily just using the defaultCenter and nothing else, but I want to make sure I am not missing something vital.
Apple documentation is vague, and it just states that usually a programmer wouldn't need to create a new one:
Each running Cocoa program has a default notification center. You typically don’t create your own. An NSNotificationCenter object can deliver notifications only within a single program.
Full source: NSNotificationCenter documentation.
However every notification center can handle a network of notifications, distinguished by name and object. When you add an observer you typically call the method in some way like this:
[center addObserver: self selector: #selector(observe:) name: #"observe" object: someObject];
And when you post a notification you can specify the object:
[center postNotificationName: #"observe" object: someObject];
This way say that you use N names and M objects, you can handle N*M distinguished notifications. I think there is no need to use two notification centers. Theoretically if you have finished all names you can create another one using alloc+init, but I hardly see how it can actually turn out handy.
Also consider that notification center is often used when there are two objects that do not own a direct pointer to each other (otherwise why not simply calling a method on it?), due to avoid complicated bindings (specially when you use a lot of xib files), so having an unique notification center object is very handy.
If instead you use a notification center got with allot+init, then you must ensure that all the communicating objects have a pointer to that notification center, and this would add some complexity. All notification center's power would be wasted.
Although it's used heavily in AppKit via the defaultCenter singleton accessor, at it's heart, NSNotificationCenter is really just a "generic decoupling mechanism." Allowing you to alloc/init your own instances of it is just an expression of that generic-ness. If you wanted to use it for something else, you could.
To illustrate with a somewhat absurd example, think of it this way: NSDocument has a windowControllers accessor that returns a specific, blessed, important instance of NSArray that contains references to all the window controllers specific to that document. That said, NSArray is just a "generic list data structure". Just because there exists this special instance of it with a specified purpose doesn't mean it might not be useful to reuse NSArray for your own purposes. Both NSArray and NSNotificationCenter provide generic data structures/building blocks, specific instances of which are used in blessed "occupations" around AppKit, but both of which could be useful on their own.
The primary use case I've seen for creating standalone instances of NSNotificationCenter is when you want to run multiple instances of some complex subsystem on multiple threads in parallel and not have them potentially get confused by cross-thread notifications. In this case, the general pattern is to allocate one NSNotificationCenter per thread. This compartmentalizes the notifications for each network of objects to a single thread. This will generally be required if observers pass nil for the object parameter intending to listen to all notifications with a given name, regardless of source.
All that said, I concede that, in my experience, making private instances of NSNotificationCenter is pretty rare.
Apple's Doc
If your app uses notifications extensively, you may want to create and post to your own notification centers rather than posting only to the default notification center. When a notification is posted to a notification center, the notification center scans through the list of registered observers, which may slow down your app. By organizing notifications functionally around one or more notification centers, less work is done each time a notification is posted, which can improve performance throughout your app.

Best way to cache an NSArray of text/dictionaries and have it useable across the entire app?

I am making a request for an array of perhaps 10-100 objects, all of which are JSON objects that I parse into NSDictionary's. I want to cache this and use this data across the entire application. Is NSCache useful for this or is it better to use NSUserDefaults or what is actually the most accepted way of persisting data across an entire app? CoreData? I'm a iOS newb and don't have too much experience in this.
What you are looking for is a way to access data across your app. This is typically the role a Model plays in MVC.
CoreData and NSUserDefaults are ways to save data so it is not lost when your app closes or is quit. They can be parts of a Model, but do not help in having that data be accessible throughout your app.
If you want an object that stores data and can be accessed anywhere in your code, you are probably looking for a Singleton.
As this excellent Stack Overflow answer explains:
Use a singleton class, I use them all the time for global data manager classes that need to be accessible from anywhere inside the application.
The author provides some sample code you might find helpful.
This would allow you to create a simple object accessible throughout your program that has your NSDictionaries. Because it is a singleton, other classes in your program can easily access it - meaning they can also easily access the NSDictionaries you've stored in it.
If you do decide you want to save data, that singleton object would also be an ideal location to write any load and save code.
Good luck!
Other good resources are:
Wikipedia's Entry on Singeltons
What Should My Objective C Singleton Look Like?
Singeltons and ARC/GCD

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.

Adding non-model nodes to an NSTreeController

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.

Resources