How to deal with a multiple-user database
Asked Answered
L

1

12

My app is like a lot of apps -- it has a login screen where the user enters a username and password, and a login button My app also uses Core Data to save most of the user's business objects, that of course are user-specific.

I also have a sign out button to enable switching users. This does not happen a lot, but it's still necessary).

Now if a different user logs in, I need to fetch his specific data. But how do I do it?
I don't want to delete a user's database when he signs out, I want to save it even if other users log in from the device.

The only thing I can think about is to add an "ownerId" attribute to every Entity I save via Core Data, and use this attribute as a predicate when I fetch objects.
But that just seems too messy.

Localize answered 2/5, 2012 at 15:56 Comment(0)
V
22

iOS doesn't really have a concept of multiple users so the "login" would be limited in scope to your app. The simplest solution would be to use a different filename for the persistent store for each user. This is only derived in one place (wherever you set up your core data stack) so it would be pretty straightforward to implement.

In the standard core data template, the persistent store location is set inside the persistentStoreCoordinator method of the application delegate. It is this line:

 NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"coreDataTemplate.sqlite"];

This basically means that the data will be stored in a sqlite database file in the documents directory, and the file will be called coreDataTemplate.sqlite.

Assuming that before this code is executed point you have made the user log on, and checked their user ID against some list and come up with a unique identifier for them. Further assume the identifier has been stored in user defaults.

Change the line above to:

NSString *userIdentifier = [[NSUserDefaults standardUserDefaults] stringForKey:@"loggedOnUserID"];     
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:[NSString stringWithFormat:@"%@_coreDataTemplate.sqlite",userIdentifier]];

This will now give you a unique file name for your user.

If you change users, then you will need to save the current managed object context, then set the persistent store coordinator and the managed object context of the app delegate back to nil. When they are re-accesed, it will be under the new user ID.

Vardon answered 2/5, 2012 at 16:2 Comment(11)
I use xCode core data template so I don't really know where and how to use a different filename, but it sound like a very good solution. Can you guide me how to "reset" the persistent store and load by different filename?Localize
Will do, but it won't be for a couple of hours.Vardon
OK, done - hope that helps. I haven't done anything like this myself, it's just how I would do it.Vardon
If I could I would accept your answer 10 times! that was very helpful and very well explained :) What about the managedObjectModel? do I need to set it to nil also? do I need to make his modelURL different for every user?Localize
@Vardon I implemented the same solution months ago (and I'm happy to see another source besides my mind). However, if you have a GCD queue saving data to a user, and then you do logout, it can't cause any problems?Katelyn
@Vardon Thanks for the explanation. One question: my persistentStoreCoordinator and managedObjectContext are by default defined as readonly properties. In order to set them to nil upon logout, I assume I should simply remove the readonly part from their property definitions. Just want to make sure there's no harm in that. CheersBunting
@Bunting usually you'd keep them externally as read only , but internally as read-write, within the object you are using to hold your core data stack. I'd argue that there is no need to keep the persistent store coordinator as a property.Vardon
I have setup my coredata stack within a separate NSObject subclass, when I set the persistent store coordinator and the managed object context to nil from the app delegate nothing happens and the app logs back to the same persistent store. Any ideais @jrfurton ??Tracytrade
@marcoscurvello sounds like you're not using a different store URL for each user.Vardon
I'm setting the URL for the persistent store using NSUserDefaults, a string value which is set for every new user who logs in. This worked before when I made the user input credentials on every app start, now I am implementing the auto login feature similiar to messaging apps like Skype.Tracytrade
Is anyone still doing it like this? What happens with automatic version migration? Does the migration run when users log in?Cannice

© 2022 - 2024 — McMap. All rights reserved.