如何处理多用户数据库

12

我的应用程序与许多应用程序类似--它有一个登录屏幕,用户在其中输入用户名和密码,并有一个登录按钮。我的应用程序还使用核心数据来保存大多数用户的业务对象,当然这些对象是特定于用户的。

我还有一个登出按钮,以便切换用户。这并不经常发生,但仍然是必要的。

现在,如果不同的用户登录,我需要获取他的特定数据。但是我该怎么做呢?
当用户注销时,我不想删除用户的数据库,我希望即使其他用户从设备上登录,也可以保存它。

我唯一能想到的就是在每个通过Core Data保存的实体中添加一个"ownerId"属性,并在获取对象时使用该属性作为谓词。
但这似乎太混乱了。

1个回答

22

iOS没有真正的多用户概念,因此“登录”范围仅限于您的应用程序。最简单的解决方案是为每个用户使用不同的持久存储文件名。这仅在一个地方(无论您在哪里设置核心数据堆栈)派生,因此实现起来相当简单。

在标准的Core Data模板中,持久化存储位置设置在应用程序委托的persistentStoreCoordinator方法内。就是这一行:

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

这基本意味着数据将存储在文档目录中的sqlite数据库文件中,文件名将被称为coreDataTemplate.sqlite

假设在执行此代码之前,您已经让用户登录,并根据某个列表检查了他们的用户ID,并为他们想出了一个唯一标识符。进一步假设这个标识符已存储在用户默认设置中。

将上面的行更改为:

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

这将为您的用户提供一个唯一的文件名。

如果您更改了用户,则需要保存当前的托管对象上下文,然后将应用程序委托的持久化存储协调器和托管对象上下文设置为null。当它们重新访问时,将在新的用户ID下访问。


我使用 xCode 核心数据模板,所以我不太知道在哪里和如何使用不同的文件名,但听起来像是一个非常好的解决方案。你可以指导我如何“重置”持久存储并通过不同的文件名加载吗? - Eyal
@jrturton 我几个月前实现了相同的解决方案(很高兴看到除了我的思维之外还有其他来源)。但是,如果您有一个GCD队列将数据保存到用户中,然后您注销,这不会引起任何问题吗? - Natan R.
@jrturton 感谢您的解释。有一个问题:我的persistentStoreCoordinator和managedObjectContext默认定义为只读属性。为了在注销时将它们设置为nil,我应该从它们的属性定义中简单地去掉readonly部分。只想确保这样做没有任何危害。干杯 - mkc842
通常你会将它们作为只读的外部变量保存,但在用于保存核心数据栈的对象内部,你可以将它们保存为可读写的变量。我认为没有必要将持久性存储协调器作为属性保留。 - jrturton
1
还有人这样做吗?自动版本迁移会发生什么?迁移会在用户登录时运行吗? - Brett
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接