Multi User Core Data w/ XPC - objective-c

Howdie,
This is my first post, so if this has been answered somewhere please forgive me (I did search).
Problem:
I have a Cocoa app that needs to share a single Core Data database among multiple user accounts on the system.
Idea:
I would create a daemon to handle requests from the users (to cross user privilege boundaries) to save/retrieve the data from Core Data. Create a shared Managed Object Context that is used in the application and pass that MOC to the daemon through NSXPCConnection. The daemon will have a fully realized Core Data Stack. I can then set the MOC that was created in the app to be a child of the MOC that was created by the daemon. Hit save and I'm done?
Question:
Would this even work? Is this just a dumb idea? What are the other solutions? NSManagedObjectContext conforms to the NSCoder protocol, but in order to use it with XPC I have to subclass it and make it conform to the NSSecureCoding protocol? Would I also just need to make sure my ManagedObject subclasses conform to NSSecureCoder protocol to use with NSXPConnection? I suppose I can ditch the context all together and just send the managed objects.
I'm assuming NSXPCConnection copys objects instead of using pointers? Is this correct?
Also, I'd probably have to keep performance in mind as the objects are coded/ decoded as fully realized objects and not faulted. Is this correct?
Thank you in advance for your help.

Maybe it works. ;-)
But there are some special problems you have to deal with. To make a long story short: I think that it would be better to use an incremental store doing this. But its documentation is close to poor.
We implemented something like this for syncing. And we have to implement this for networking. (That is, what you want to do.) Here are the problems:
A.
Moving around the context won't help. The context contains a subset of the store objects. Which one is in the context is random to the app programmer. (Inserted and changed objects will live there, but not changed, not inserted objects can be there and can go away.)
B.
You can of course move around the store. Since it is on the hard disk, this would be easier, if you have access to that location, where it is stored. You can use an XPC service for that.
Doing so has the problem that you do not know, what one user changed. You only get the whole store. In contrast an incremental store knows the specific changes through the save request.
C.
"Different users" means that you have conflicts. This is "unnatural" to Core Data. Is is a graph modeller and being that, it is not "connection based". It opens a document, owns it, changes it, stores it, and closes it. As every document it is typically not owned by two or more apps (including two running instances of one app) at one time. There is no real good mechanism for working on a store simultaneously. So you have to handle that yourself. It is probably easier to handle that on the level of the incremental store than on a level build on top of it.
What you want to do is not that easy, if you do not make assumptions you can make in your special case. (For example having a locking mechanism on a higher level.)
My 0,05 $.

Related

2 separate systems, how to make them communicate

I got a DDS-system(OMG DDS) who's communicating with a ROS-node over radio. The information being received is a struct with velocity, state, longitude, latitude etc. This works well, and my DDS-client has no problem printing the information being transmitted from the node over the radio. Now, I've got a GUI-application written in Qt, who creates models and puts them on a predefined map. These modelse have defined set-information functions, which when triggered updates the map to give a smooth visualisation of the information it receives.
Now here is problem, I've no idea how to make the GUI application communicate with my DDS-client. I would rather not intertwine these two, since I've had enough trouble just making the DDS-client and sender work and compile with ROS. Ive though about a separate queue system, which can be included in the DDS-client and the GUI application, but I dont know if this could work. Ive also though about writing a SQL database, and then push new data, and pull new data when it is detected in my GUI application. Some sort of on_data_available function which triggers the pull-function. Ive heard the last one is a bad idea, since I'm working with only one set of data which is being continuously updated (the model represents one USV), and a database is then considered overkill, but I would love to get inputs here.
Im sorry if this isn't sufficient information, I can't really provide code examples for different reasons. If anyone have any inputs, shout out, would love to hear them. And if I'm not being specific enough, ill try to rewrite it as best as i can.
I've no idea how to make the GUI application communicate with my
DDS-client
Your question is not specific to DDS or your GUI application -- you essentially ask for a simple and convenient inter-process communication (IPC) mechanism. As you can see when you follow the link, there are loads of different options.
Given that you already have your data as well as the associated type definitions available in DDS, I suspect that using DDS for this task would still be the easiest way to go. You could set it up to communicate over shared memory or local loopback. DDS will do all discovery and communication under the hood, including (cross-language) de/serialization. If you choose a different mechanism, you might end up doing more work yourself.
As an alternative, some DDS implementations (commercially) support native integration with SQL databases. Those will introspect the DDS data definitions and create all required tables for you. Updates from DDS are automatically forwarded to the database, and vice-versa. You could feed your GUI off of that database.

best place to persist an nsmutablearray of objects

I'm an OSX beginner. Where is the best place to store an NSMutableArray of objects. the objects need to be presented to the user for updating, deleting etc. I've already written the code to manage and present the data to the user. i just need to now start saving the data. i don't envisage the array containing more than 50 objects.
i'm not sure where to persist the data. should i use a os file or NSUserDefaults. what does osx etiquette say?
thanks
Since you mention that the user will need to update and delete the data, Core Data is a very good option.
In addition to the benefits of the framework itself, Core Data integrates well with the OS X tool chain. The model design tools allow you to create your schema graphically, quickly and easily. You can use templates in the Instruments application to measure Core Data’s performance, and to debug various problems. On OS X desktop, Core Data also integrates with Interface Builder to allow you to create user interfaces from your model. These aspects help to further shorten your application design, implementation, and debugging cycles.
You can read more about the key features in the documentation to be sure that's what you're looking for.

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.

Abstracting Core Data from the rest of the app (MVCS pattern)?

I'm working on an app that is basically a client for a server-side REST API.
The app relies heavily on server-data (kind of like Facebook does).
In my app I have an ServerAPI class that manages all interaction with the server. It basically acts as the "Store" in the "Model-View-Controller-Store" pattern. The rest of the app uses a singleton instance of this class to access data.
So for example if one of my view controllers needs a list of Articles, it would call:
[[ServerAPI sharedAPI] fetchArticlesWithCompletion:^(NSArray *articles){
// Do something with the new articles.
}];
This way the app doesn't care how the articles are fetched. For all it knows, they were fetched from a local file and not a server.
This is all fine and well.
The problem now is I'd like to add some sort of caching. After looking around it sounds like Core Data might be the best tool for the job (but I'm definitely open to other suggestions).
I found AFIncrementalStore (NSIncrementalStore subclass for AFNetworking) which looks promising. But from my (currently limited) understanding of NSIncrementalStore, the app (view controllers) still interact directly with NSFetchRequests and MOCs to fetch data.
I'd like to keep my current API (ServerAPI singleton) and simply plug in Core Data "behind the scenes" so that the rest of the app remains unaware of the details. Basically the app shouldn't know that data is cached, or how it is cached, it should just request data and get data.
So my question is, what's a good strategy for implementing this? Has anyone done something like this before? Is it worth the effort? I understand that Core Data is itself a way of abstracting stores, so having a second layer of abstraction might be overkill. But I keep thinking of the case where if one day I decide to use NSCoding instead of Core Data to store objects to disk. I generally don't like having all my classes know about implementation details (in this case using core data vs not using core data).
I'm a little torn on what approach is best. I don't want to invest too much time into a solution that might not make sense in the long run.
Generally does it make sense to use Core Data APIs directly in code? Or is it best to abstract away all these details behind a custom DataManager that handles both server and local data.
Thoughts?
Personally, I'd use RestKit as the bridge between the RESTful API and Core Data. I would use Core Data and I wouldn't be thinking that changing to NSCoding might be a good idea in the future (that's a really very unlikely scenario). Core Data offers you a lot of options for storage, searching and memory management. Getting the same features from another store is going to be a lot of effort or a similar level of dependency.
Either way, you have 2 options - hide the cache or don't.
If you hide it, the side effect would be that you'd really need to call the completion block twice (first for the cache hit, second for the server response). How easy that will be depends on what you're doing. The issue would be that you wouldn't be able to leverage all of the search and memory management features of your cache (like only loading pages of data from the store and loading more as the user scrolls through a list).
If you don't hide it, yes you would use fetch requests and MOCs. Probably via NSFetchedResultsController. The impact is relatively low IMHO and the benefits are large (like the automatic page management). Now your structure is - view controllers watch the 'cache' for data (the ServerAPI owns the MOC so it still mediates the store), they can get existing data immediately and if they decide new data is required they call the ServerAPI. The ServerAPI works exactly as it does now (with the completion block) and the completion block is either used as a trigger to update the UI activity indication or as the actual source of data if needs be.
As you can probably tell, I wouldn't hesitate in using Core Data and allowing its features to be used in my view controllers. The part I'm interested in shielding the rest of the code from is the server API, not the local data cache.

iOS: Using Core Data to insert into a database

When using core data, how would I insert to values into a database, or even interact with a database. Is there a good tutorial for this? I have went over Core Data tutorial, but majority the files were done locally.
UPDATE
Someone from my previous question answered this "Core Data can use a database to accomplish this, but that's it's business, not yours. When you use Core Data, it is a black box. You tell it to save the data and then step out of the way."
Does that mean it automatically does the database side for me?
Thank you!
Core data is a black box in that it is an object oriented API for interacting with the SQLite db on the device (and in iCloud). If you are pushing to a web service that has a SQL database backend... Well, I've used a php controller for the web service that provides a rest interface. Then I get data from my device and hit the rest controller methods passing whatever data is appropriate as parameters in an http post. Not sure whether that's general or best practice but that's how we've done it in my experience
Core Data is not a db manager, and does much more than simply interact with your db. At the very least, you should consider Core Data as an ORM. Perhaps, the best way to understand Core Data is to think it as a graph administrator. You are going to interact with core data via a context (NSManagedObjectContext) that will let you fetch objects from it, and also insert, edit and delete them. Objects are subclasses of NSManagedObject. One important thing to care about are threads. NSManagedObject are not thread safe, you should never pass them between threads. Use NSManagedObjectsIDs instead. The important thing, you don't need to care about how core data store things, you can set the format of the store, but that's all (in that respect, you do have to take a few things into consideration when choosing the store, like performance, and whether you need to persist data between runs, but let's Core Data handle the details).
And if you want to know more, Marcus Zarra's book is excellent