如何将用户登录的 JSON 响应保存到 Core Data 中以跟踪 Swift 中的用户状态?

Posted

技术标签:

【中文标题】如何将用户登录的 JSON 响应保存到 Core Data 中以跟踪 Swift 中的用户状态?【英文标题】:How to save JSON response from user login into Core Data to track the user state in Swift? 【发布时间】:2021-03-08 05:53:45 【问题描述】:

我正在尝试将来自用户登录的 json 响应保存到 Core Data 中,以便当用户退出应用程序并再次打开时,它会识别该特定用户。我只有简单的 json,它是 ["String":Any, .... "String":Any] 类型,现在我通过制作如下结构模型来保存响应,谁​​能知道实现什么的最佳方法我想要,请帮帮我 我是 Core Data 的新手,我不知道从哪里开始

【问题讨论】:

print(loginData) 打印的信息是否正确? 是的,它会打印json的登录ingo 邮政编码为文字而非图片 你应该先做一些教程和阅读一些关于 Core Data 的文章,因为 *** 不是一个教程网站,所以这个问题很广泛,应该关闭。 是的,我阅读了苹果文档,他们关于如何使用 CoreData 的示例很难理解这个概念,所以我搜索了有用的教程网但没有成功,最后一个选项是询问 ***, 【参考方案1】:

首先声明你的核心数据容器

//CoreData container
private lazy var persistentContainer: NSPersistentContainer = 
    let container = NSPersistentContainer(name: "container_name")
    container.loadPersistentStores(completionHandler:  (storeDescription, error) in
        if let error = error 
            //Error handling
        
    )
    return container
()

这里container_name 将是您的核心数据文件名。

然后这个函数会做保存:

public func saveLoginData(data: LoginData) 
    let context: NSManagedObjectContext = self.persistentContainer.viewContext

    let entityDescription: NSEntityDescription = NSEntityDescription.entity(forEntityName: "LoginInfo", in: context)!

    let loginInfoEntry: NSManagedObject = NSManagedObject(entity: entityDescription, insertInto: context)

    //Set your values here
    loginInfoEntry.setValue(data.AccountId, forKey: "accountId")
    loginInfoEntry.setValue(data.UserId, forKey: "userId")
    ... //Set all your values

    //Then save
    do 
        try context.save()
     catch 
        //Error handling
    

查询您的数据:

public func getLoginData() -> LoginData? 
    let context: NSManagedObjectContext = self. persistentContainer.viewContext
    let loginDataFetchRequest: NSFetchRequest = NSFetchRequest<NSManagedObject>(entityName: "LoginInfo")
    do 
        let fetchedData: [Any] = try context.fetch(loginDataFetchRequest)
        let loginDataObjectArray: = fetchData as! [NSManagedObject]
        let loginDataObject: NSManagedObject = loginDataObjectArray[0]
        var loginData: LoginData = LoginData()
        loginData.AccountId = loginDataObject.value(forKey: "accountId") as! String
        ...//Set all your values
        
        return loginData
        
     catch 
        //Handle errors
        return nil
    

这只是对您的问题的一个简单回答,为您指明方向。请参阅 CoreData 文档和其他一些教程以更好地理解。还要确保处理上述步骤可能引起的所有错误。我没有考虑可能发生错误的每一种情况。

【讨论】:

感谢您的帮助,但是对于查询,它不起作用,因为 LoginData 是可解码协议,它说它会引发错误并且我在查询时无法创建 LoginData 的新实例,是有什么办法吗? 我更新了答案。 var loginData: LoginData = LoginData()。你能显示错误吗 它在var loginData: LoginData = LoginData() 中说“在调用中缺少参数'from'的参数”我应该给一些解码器的LoginData()一个参数,这是错误 仅使用print(loginDataObject.value(forKey: "accountId") as! String) 而不创建 loginData 来检查查询中的值是否正确。 chat.***.com/rooms/229646/…来聊天【参考方案2】:

基础知识 在 XCode 上创建您的 Swift 项目并检查 Use CoreData 确保在您的课程标题上使用import CoreData

保存到 CoreData 如果您的项目使用CoreData,您可以继续使用下面的保存功能:

func saveLoginDataToCoreData(data: LoginData)

    guard let appDel = UIApplication.shared.delegate as? AppDelegate else  return 
    let context = appDel!.persistentContainer.viewContext
    let entity = NSEntityDescription.entity(forEntityName: "LoginInfo", in: context)!
    let mngdObj = NSManagedObject(entity: entity, insertInto: context)
    
    mngdObj.setValue(data.LoginToken, forKeyPath: "loginToken")
    mngdObj.setValue(data.UserId, forKeyPath: "userId")
    // Add all loginData here...
     
    do  try context.save(); print("LoginData has been saved to CoreData")
     catch  print("An error has occurred: \(error.localizedDescription)")  

另一方面,如果您的项目不使用 CoreData,您可以声明一个名为“CoreData Stack”的 CoreData 容器(这会自动包含在 AppDelegate 中使用 CoreData 的项目中)。您可以将它放在需要它的 ViewController 类中,或者放入 UIViewController 扩展中以供全局使用:

lazy var persistentContainer: NSPersistentContainer = 
    let container = NSPersistentContainer(name: "Your_DataModel_Filename")
    container.loadPersistentStores(completionHandler:  (storeDescription, error) in
        if let error = error as NSError? 
            print("An error has occurred: \(error.localizedDescription)")
        
    )
    return container
()

使用方法:

func saveLoginDataToCoreData(data: LoginData)
    
    let context: NSManagedObjectContext = self.persistentContainer.viewContext
    let entity: NSEntityDescription = NSEntityDescription.entity(forEntityName: "LoginInfo", in: context)!
    let mngdObj: NSManagedObject = NSManagedObject(entity: entity, insertInto: context)
    
    mngdObj.setValue(data.LoginToken, forKeyPath: "loginToken")
    mngdObj.setValue(data.UserId, forKeyPath: "userId")
    // Add all loginData here...
     
    do  try context.save(); print("LoginData has been saved to CoreData")
     catch  print("An error has occurred: \(error.localizedDescription)")  

更新:后续答复

如果您想使用该 loginToken 或 LoginData 中的任何数据,我们可以获取我们之前从 CoreData 中保存的值。

为了有效地检索值,最好先保存当前用户的 LoginToken。为方便访问,建议登录时保存在UserDefaults,注销时删除即可。

func saveCurrentLoginToken(_ token:String)
    let defaults = UserDefaults.standard
    defaults.set(token, forKey: "currentLoginToken")
    defaults.synchronize() 

示例用法:

// ...
let currentLoginToken = data.LoginToken
mngdObj.setValue(currentLoginToken, forKeyPath: "loginToken")
self.saveCurrentLoginToken(currentLoginToken)
// ...

获取当前登录令牌:

func getCurrentLoginToken() -> String? 
    let defaults = UserDefaults.standard
    let token = defaults.object(forKey: "currentLoginToken") as? String
    if token != nil  return token! // Return value if not nil
     else  return nil  // Will return as nil if you haven't save the LoginToken in UserDefaults

获取特定数据

我创建了一个函数,我们可以使用它来获取我们之前保存的任何信息:

func getAnyValueFromCoreData(_ loginToken:String,_ key:String) -> Any?  // key = data you want to retrieve the value of

    guard let appDel = UIApplication.shared.delegate as? AppDelegate else  return nil 
    let context = appDel.persistentContainer.viewContext
    let fetchReq = NSFetchRequest<NSManagedObject>(entityName: "LoginInfo")
    fetchReq.predicate = NSPredicate(format: "loginToken==%@",loginToken)
    
    var anyVal: Any?
    
    do  let result = try context.fetch(fetchReq)
        for data in result 
            let val = data.value(forKey: key)
            // Check if nil to avoid fatal error
            if val != nil  anyVal = val!  else  anyVal = nil  
     catch 
        anyVal = nil // Set value to nil in case of error (not always recommended)
        print("An error has occurred: \(error.localizedDescription)")
    
    
    return anyVal 

现在,例如,如果您想获取当前用户的 ReturnCode:

func getReturnCode() -> Int? 
     let token = getCurrentLoginToken() // retrieve from UserDefaults
     let returnCode = getAnyValueFromCoreData(token!,"returnCode") as? Int
     return returnCode

使用(在您在评论中描述的情况下):

func checkReturnCode()
     let returnCode = getReturnCode()! // catch if nil?
     if returnCode == 0 
          // show MainPage to User
      else  
     // or use Switch Statements for more than two ReturnCodes
     // or to handle error in case of default (nil value)

免责声明:我没有测试上面的代码,如果你遇到任何错误,请在 cmets 中告诉我。编辑:更新 @987654333 @并把filterReq替换成getAnyValueFromCoreData()(自制函数)

【讨论】:

谢谢,它工作得很好,但后来如果我想使用该 loginTokens 或 LoginData 中的任何数据,我该如何检索它?例如在另一个 vc 中,如果 returnCode == 0,则向用户显示主页。 我已更新我的答案以解决您的后续问题。请让我知道它是否有效 我认为它有一些错误,我已经搜索了互联网但找不到解决方案,它在getAnydatafromCoredata()方法中显示Cannot find 'fetchEntity' in scopeCannot find 'filterReq' in scope @Ulugbek,抱歉,这些是我忘记包含的自制功能。将更新我的答案 是的,不用担心,我非常感谢您的帮助,现在通过查看代码并且我了解流程,我期待您的更新,

以上是关于如何将用户登录的 JSON 响应保存到 Core Data 中以跟踪 Swift 中的用户状态?的主要内容,如果未能解决你的问题,请参考以下文章

如果 JSON 响应结果为 0/11,我如何将用户发送到 servlet 中的 .html 页面

如何在swift中将json数组保存和检索到用户默认值?

如何在您的登录 api 的 Json 响应后重定向用户反应本机

在 SwiftUI 中将加载的 json 文件中的更改保存到 Core Data

如何从 JSON 对象中获取特定的键值

.NET Core:从 API JSON 响应中删除空字段