Swift: 是否可以将另一个 class 的静态 属性 传递给方法?

Swift: Is it possible to pass a static property of another class to a method?

我有以下方法可以从 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 由另一个 class 处理,其中一些属性有自己的 getter 和 setter。是否仍然可以使用这种通用的下载方法并使用一个参数来告诉它应将解码数据分配给存储 class 的哪个 属性?如果不是,我在想我可以有一个基于数据类型的 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 

}

您应该使用完成处理程序 return 解码结果,然后处理其中的任何进一步逻辑。此外,您不需要数据类型 属性,您可以在调用函数时隐式告诉编译器 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<T, Error>) -> Void 但我将其留给您研究