【问题标题】:Retrieving custom Object from NSUserDefaults从 NSUserDefaults 检索自定义对象
【发布时间】:2019-09-17 22:42:45
【问题描述】:

我有一本价值观字典

class Objects {
    let values = [
    "AAA": ["AAAAAAA", "111111111"],
    "BBB": ["BBBBBBBB", "2222222"],
    "CCC": ["CCCCCCCC", "3333333333"],
    "DDD": ["DDDDDD", "44444444"],
    ]
}

我将其转换为自定义对象并显示在表格视图中。

struct  Object {
   var heading : String!
   var imageName: String!
}

然后用户可以选择两个对象存储在UserDefaults中

let defaults = UserDefaults.standard

func addObject(_ object1: String, object2: String) {

    // Get objects for user
    var userObjects = fetchObjectsFromUserDefaults()

    // Add to user currencies
    userObjects.append([object1,object2])

    //Update user defaults value for key
    // [ [Object1, Object2], [Object1, Object2] ]

    defaults.set(userObject, forKey: "userCurrencies")
}

// Gets [[String]] values from user defaults for key
func fetchObjectsFromUserDefaults() -> [[String]] {
    if let objects = UserDefaults.standard.value(forKey: "userObjects") {
        return objects as! [[String]]
    } else {
        return []
    }
}


// Uses [[String]] values and turns them into objects by using the dictionary to determine property values 

func getObject() -> [[Object]] {
    let userObject = fetchObjectsFromUserDefaults()
    // [ [Object1, Object2], [Object1, Object2] ]

    let object = Object()

    var fetchedObject = [[Object]]()

    if !userObjects.isEmpty {
        for c in userObjects {
            var set = [Object]()
            if let val = object.available[c[0]] {
                set.append(Currency(currencyTitle: c[0], imageName: val[0] ))
            }

            if let val2 = object.available[c[1]] {
                set.append(Currency(currencyTitle: c[0], imageName: val2[0] ))
            }

            if !set.isEmpty {
                fetchedObjects.append(set)
            }
        }
        return fetchedObjects
    }

    return [[]]

}

视图控制器

在这里我将对象加载到TableView

let fetched = dataManager.getObjects
print(fetched)
self.objects = fetched()

但是这会打印出来

(功能)

我做错了什么,他们是从用户默认值中存储和检索这些数据的更好方法吗?我觉得这已经结束了,还有一种更快捷、更安全的方法。

【问题讨论】:

  • 您只调用该函数一次。看起来您至少可能想在 print 语句中调用它(print(fetched()) 以打印结果。或者打印语句甚至是您要解决的问题?
  • 您需要使您的自定义对象符合 NSCoding 并且您需要对其进行编码/解码并将其作为数据保存到 UserDefaults。顺便说一句,不要使用 value(forKey:) 方法,它仅适用于 KVO,如果您使用的是 Swift 4 或更高版本,最好使用 Codable 协议来编码/解码您的自定义对象。
  • 另外要提的是结构不能符合 NSCoding(你需要继承 NSObject)。使其符合 Codable 协议并将编码数据保存到 plist 文件中

标签: ios swift userdefaults


【解决方案1】:

第 1 步。

制作你的结构Codable。如果您的struct 的所有成员都是Codable 并且幸运的是String 是Codable,那么编译器将为您编写所有函数,所以它只是:

struct Object: Codable {
  var heading : String!
  var imageName: String!
}

第 2 步。

Codable 的问题在于它与Data 相互转换,但您想与Dictionary 相互转换。幸运的是 JSONSerialization 从 Data 转换为 Dictionary 所以创建一个新协议并给它一个带有协议扩展的默认实现:

protocol JSONRepresentable {
  init?(json: [String: Any])
  func json() -> [String: Any]
}
extension JSONRepresentable where Self: Codable {
  init?(json: [String:Any]) {
    guard let value = (try? JSONSerialization.data(withJSONObject: json, options: []))
      .flatMap ({ try? JSONDecoder().decode(Self.self, from: $0) }) else {
        return nil
    }
    self = value
  }
  func json() -> [String:Any] {
    return (try? JSONEncoder().encode(self))
      .flatMap { try? JSONSerialization.jsonObject(with: $0, options: []) } as? [String: Any] ?? [:]
  }
}

第 3 步。

使你的结构符合JSONRepresentable

struct Object: Codable, JSONRepresentable {
  var heading : String!
  var imageName: String!
}

第 4 步。

将您的对象放入 Userdefaults 并再次取出:

let o = Object.init(heading: "s", imageName: "a").json()
UserDefaults.standard.set(o, forKey: "test")
print(Object.init(json: UserDefaults.standard.dictionary(forKey: "test") ?? [:]))

如果你想试试,这里是整个游乐场:

import UIKit

struct Object: Codable, JSONRepresentable {
  var heading : String!
  var imageName: String!
}

protocol JSONRepresentable {
  init?(json: [String: Any])
  func json() -> [String: Any]
}
extension JSONRepresentable where Self: Codable {
  init?(json: [String:Any]) {
    guard let value = (try? JSONSerialization.data(withJSONObject: json, options: []))
      .flatMap ({ try? JSONDecoder().decode(Self.self, from: $0) }) else {
        return nil
    }
    self = value
  }
  func json() -> [String:Any] {
    return (try? JSONEncoder().encode(self))
      .flatMap { try? JSONSerialization.jsonObject(with: $0, options: []) } as? [String: Any] ?? [:]
  }
}

let o = Object.init(heading: "s", imageName: "a").json()
UserDefaults.standard.set(o, forKey: "test")
print(Object.init(json: UserDefaults.standard.dictionary(forKey: "test") ?? [:]))

【讨论】:

  • 谢谢!这是很大的帮助,只是试图让它完全适用于我的项目,例如添加对象时,我在 print 语句中得到以下内容 Optional(TestApp.Currency(heading: nil, imageName: nil))
  • 我还需要添加一对对象,因此在保存和检索它们时,对象的格式是一个包含两个对象的数组中的数组(我比较每个表格视图单元格中的每个对象)[[对象,对象]]
  • 只是弄清楚这些最后的部分并做一些进一步的阅读,但这更多是我想要的
  • Array 也是可编码的。所以它的工作方式相同。
猜你喜欢
  • 1970-01-01
  • 2012-06-20
  • 2017-08-30
  • 1970-01-01
  • 2019-02-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多