swift 将自定义对象的数组存储在UserManager中

2cmtqfgy  于 12个月前  发布在  Swift
关注(0)|答案(2)|浏览(96)

我花了很长时间试图弄清楚如何在UserManager中存储我的自定义结构的数组。
下面是我的代码:

struct DomainSchema: Codable {
    var domain: String
    var schema: String
}

var domainSchemas: [DomainSchema] {
    get {
        if UserDefaults.standard.object(forKey: "domainSchemas") != nil {
            let data = UserDefaults.standard.value(forKey: "domainSchemas") as! Data
            let domainSchema = try? PropertyListDecoder().decode(DomainSchema.self, from: data)
            
            return domainSchema!
        }
        
        return nil
    }
    
    set {
        UserDefaults.standard.set(try? PropertyListEncoder().encode(newValue), forKey: "domainSchemas")
    }
}

struct SettingsView: View {
    var body: some View {
        VStack {
            ForEach(domainSchemas, id: \.domain) { domainSchema in
                HStack {
                    Text(domainSchema.domain)
                    Text(domainSchema.schema)
                }
            }
            
            // clear history button
        }
        .onAppear {
            if (domainSchemas.isEmpty) {
                domainSchemas.append(DomainSchema(domain: "reddit.com", schema: "apollo://"))
            }
        }
    }
}

字符串
它给了我这些错误:
无法将类型“DomainSchema”的返回表达式转换为返回类型“[DomainSchema]”
“nil”与返回类型“[DomainSchema]”不兼容
我真的不知道如何获得一个对象数组而不仅仅是一个对象,或者如何解决nil不兼容性错误.

eh57zj3b

eh57zj3b1#

如果你真的想使用Username持久化你的数据,最简单的方法是使用一个类并使其符合NSCoding。关于你的全局var domainSchemas,我建议使用singleton或extend Username并在那里为它创建一个computed属性:

class DomainSchema: NSObject, NSCoding {
    var domain: String
    var schema: String
    init(domain: String, schema: String) {
        self.domain = domain
        self.schema = schema
    }
    required init(coder decoder: NSCoder) {
        self.domain = decoder.decodeObject(forKey: "domain") as? String ?? ""
        self.schema = decoder.decodeObject(forKey: "schema") as? String ?? ""
    }
    func encode(with coder: NSCoder) {
        coder.encode(domain, forKey: "domain")
        coder.encode(schema, forKey: "schema")
    }
}

个字符
使用方法:

UserDefaults.standard.domainSchemas = [.init(domain: "a", schema: "b"), .init(domain: "c", schema: "d")]

UserDefaults.standard.domainSchemas  // [{NSObject, domain "a", schema "b"}, {NSObject, domain "c", schema "d"}]


如果你更喜欢Codable的方法,也可以使用UserData来持久化数据:

struct DomainSchema: Codable {
    var domain: String
    var schema: String
    init(domain: String, schema: String) {
        self.domain = domain
        self.schema = schema
    }
}
extension UserDefaults {
    var domainSchemas: [DomainSchema] {
        get {
            guard let data = UserDefaults.standard.data(forKey: "domainSchemas") else { return [] }
            return (try? PropertyListDecoder().decode([DomainSchema].self, from: data)) ?? []
        }
        set {
            UserDefaults.standard.set(try? PropertyListEncoder().encode(newValue), forKey: "domainSchemas")
        }
    }
}

使用方法:

UserDefaults.standard.domainSchemas = [.init(domain: "a", schema: "b"), .init(domain: "c", schema: "d")]

UserDefaults.standard.domainSchemas  // [{domain "a", schema "b"}, {domain "c", schema "d"}]


我认为最好的选择是不使用UserList,创建一个单例“共享示例”,在那里声明一个domainSchemas属性,并将你的json数据保存在你的应用程序支持目录的一个子目录中:

extension URL {
    static var domainSchemas: URL {
        let applicationSupport = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first!
        let bundleID = Bundle.main.bundleIdentifier ?? "company name"
        let subDirectory = applicationSupport.appendingPathComponent(bundleID, isDirectory: true)
        try? FileManager.default.createDirectory(at: subDirectory, withIntermediateDirectories: true, attributes: nil)
        return subDirectory.appendingPathComponent("domainSchemas.json")
    }
}
class Shared {
    static let instance = Shared()
    private init() { }
    var domainSchemas: [DomainSchema] {
        get {
            guard let data = try? Data(contentsOf: .domainSchemas) else { return [] }
            return (try? JSONDecoder().decode([DomainSchema].self, from: data)) ?? []
        }
        set {
            try? JSONEncoder().encode(newValue).write(to: .domainSchemas)
        }
    }
}

使用方法:

Shared.instance.domainSchemas = [.init(domain: "a", schema: "b"), .init(domain: "c", schema: "d")]

Shared.instance.domainSchemas  // [{domain "a", schema "b"}, {domain "c", schema "d"}]

lzfw57am

lzfw57am2#

不需要使用NSKeyedArchiver将自定义对象保存到UserObject中,因为需要将struct改为class,有一个更简单的解决方案,那就是JSONDecoderJSONEncoder。当您要将自定义对象保存到UserObject中时,首先使用JSONEncoder将其转换为Data,当您要检索时从Userdefaults中创建一个对象,你可以使用JSONDecoder来实现。沿着,我强烈建议你编写一个单独的类或结构来管理你的数据,这样你就可以做到:

struct DomainSchema: Codable {
        var domain: String
        var schema: String
 }

 struct PersistenceMangaer{

        static let defaults = UserDefaults.standard
        private init(){}
        
        // save Data method
        static func saveDomainSchema(domainSchema: [DomainSchema]){
          do{
             let encoder = JSONEncoder()
             let domainsSchema = try encoder.encode(domainSchema)
             defaults.setValue(domainsSchema, forKey: "yourKeyName")
          }catch let err{
             print(err)
          }
       }
       
      //retrieve data method
      static func getDomains() -> [DomainSchema]{
    
             guard let domainSchemaData = defaults.object(forKey: "yourKeyName") as? Data else{return}
             do{
                 let decoder = JSONDecoder()
                 let domainsSchema = try decoder.decode([DomainSchema].self, from: domainSchemaData)
                 return domainsSchema
             }catch let err{
                 return([])
           }
        }
 }

字符串

用法

let domains = PersistenceMangaer.standard.getDomains()
PersistenceMangaer.standard.saveDomainSchema(domainsTosave)

相关问题