【问题标题】:Swift: Is it possible to pass a static property of another class to a method?Swift:是否可以将另一个类的静态属性传递给方法?
【发布时间】:2021-09-14 22:23:51
【问题描述】:

我有以下方法可以从 CloudKit 下载数据,并在完成后为其分配一个用户默认属性。

private static func download<T>(dataType: T, recordID: CKRecord.ID, completion: (@escaping () -> Void)?) {
    database.fetch(withRecordID: recordID) { record, error in
        if let record = record, error == nil {
            print("\(recordID) downloaded from iCloud")
            guard let data = record["file"] as? Data else { return }
            guard let decoded = try? JSONDecoder().decode(dataType.self, from: data) else { return }
            // Assign to UserDefaults here
            completion()
        } else {
            print("Couldn't download \(recordID) \(error.debugDescription)")
        }
    }
}

问题是 UserDefaults 由另一个类处理,该类具有一些属性,具有自己的 getter 和 setter。是否仍然可以使用这种通用下载方法并具有用于告诉它应该将解码数据分配给 Storage 类的哪个属性的参数?如果不是,我想我可以有一个基于 dataType 的 switch 语句。提前致谢。

class Storage {

static var ud = UserDefaults.standard
    
class var zones: [Zone] {
    get {
        if let data = ud.object(forKey: "zones") as? Data {
            do { return try JSONDecoder().decode([Zone].self, from: data) }
            catch { return ZoneHandler.defaultZones }
        } else { return ZoneHandler.defaultZones }
    }
    set {
        guard let data = try? JSONEncoder().encode(newValue) else { return }
        ud.set(data, forKey: "zones")
        sharedStorage?.set(data, forKey: "zones")
    }
}

class var preferences: Preferences {
    get {
        if let data = ud.object(forKey: "preferences") as? Data {
            do { return try JSONDecoder().decode(Preferences.self, from: data) }
            catch { return Preferences() }
        } else { return Preferences() }
    }
    set {
        guard let data = try? JSONEncoder().encode(newValue) else { return }
        ud.set(data, forKey: "preferences")
        sharedStorage?.set(data, forKey: "preferences")
    }
}

// Several more properties like this exist in this class 

}

【问题讨论】:

  • 将解码后的 json 传递给您的完成处理程序,这就是它的用途。
  • 谢谢@JoakimDanielson,这是个好主意。
  • 将此作为答案发布,我会接受。另外,我可以再问一件事吗?我注意到下载方法实际上并没有用我在这里写的东西编译,它说不能将类型'T'的值转换为预期的参数类型'T.Type'。您知道如何将类型作为属性传递吗? @JoakimDanielson 再次感谢。

标签: swift function methods syntax


【解决方案1】:

您应该使用完成处理程序返回解码结果,然后在其中处理任何进一步的逻辑。此外,您不需要 dataType 属性,您可以在调用函数时隐式告诉编译器 T 是什么,而且由于您正在解码,因此 T 必须符合 Decodable 协议。

private static func download<T: Decodable>(recordID: CKRecord.ID, completion: @escaping (T?, Error?) -> Void) {
    database.fetch(withRecordID: recordID) { record, error in
        if let record = record, error == nil {
            print("\(recordID) downloaded from iCloud")
            guard let data = record["file"] as? Data else { return }
            guard let decoded = try? JSONDecoder().decode(T.self, from: data) else { return }
            // Assign to UserDefaults here
            completion(decoded, nil)
        } else {
            print("Couldn't download \(recordID) \(error.debugDescription)")
            completion(nil, error)
        }
    }
}

示例用例

struct X: Codable {
    //...
}

download(recordID: someRecordId) { (record: X?, error) in
    if let x = record {
        Storage.preference = x
    }
}

您也可以考虑在声明完成处理程序时使用 Result @escaping (Result&lt;T, Error&gt;) -&gt; Void 但我留给您研究

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-02-15
    • 2015-05-08
    • 2016-06-26
    • 2011-11-30
    • 1970-01-01
    • 1970-01-01
    • 2014-04-01
    • 2011-02-17
    相关资源
    最近更新 更多