Я возился с URLSession и, по сути, создавал супер простое приложение для загрузки файла JSON в ContentView, вроде списка друзей из Facebook, и хотел прояснить не какие-либо ошибки, которые у меня есть, а скорее внутреннюю работу Swift Codable протокол. Вот код и пояснения:

struct User: Identifiable, Codable {
    struct Friend : Identifiable, Codable {
        var name : String
        var id : String
    }

    var id : String
    var isActive: Bool
    var name : String
    var age: Int
    var company : String
    var address : String
    var about : String
    var registered : String
    
    var friends : [Friend]
    
    var checkIsActive: String {
        return self.isActive ? "🟢" :"🔴"
    }
    
}

Итак, чтобы подвести итог выше, у меня есть структура User, которая содержит набор свойств, соответствующих Codable.

class UsersArrayClass: ObservableObject {
    @Published var userArray = [User]() 
}

Однако у меня есть другой класс, UsersArrayClass, который создает @Published var userArray из User объектов структуры. Этот класс соответствует протоколу @ObservableObject, но, конечно, когда я пытаюсь сделать его совместимым с Codable, ему это не нравится, вероятно из-за того, что оболочка свойств @Published применяется к сам массив ... Это то, что меня по существу сбивает с толку, хотя если структура User соответствует Codable, почему userArray, которая содержит User объекты, автоматически не соответствует Codable также?

Я думал, что, возможно, загрузка всего этого в модель Core Data решит мои проблемы, но я все еще не могу двигаться дальше, пока не пойму, что мне здесь не хватает, поэтому заранее спасибо за любой вклад.

0
Adam 5 Окт 2020 в 06:04

2 ответа

Лучший ответ
/*
 Cannot automatically synthesize 'Encodable' because 'Published<[User]>'
 does not conform to 'Encodable' @Published var userArray = [User]()
 */

// Published declaration
@propertyWrapper struct Published<Value> { ... }

Опубликованные в настоящее время не соответствуют Codable или любому другому общему протоколу Foundation

Попытка заставить Published соответствовать Codeable приведенной ниже ошибке:

/*
 Implementation of 'Decodable' cannot be
 automatically synthesized in an extension in a different file to the type
 */
extension Published: Codable where Value: Codable {}
0
duytph 7 Окт 2020 в 06:57

Это хакерство, но мы можем с помощью расширения добавить соответствие Codable к Published, несмотря на отсутствие доступа к внутренним компонентам Published.

extension Published: Codable where Value: Codable {
    public func encode(to encoder: Encoder) throws {
        guard
            let storageValue =
                Mirror(reflecting: self).descendant("storage")
                .map(Mirror.init)?.children.first?.value,
            let value =
                storageValue as? Value
                ??
                (storageValue as? Publisher).map(Mirror.init)?
                .descendant("subject", "currentValue")
                as? Value
        else { fatalError("Failed to encode") }
        
        try value.encode(to: encoder)
    }
    
    public init(from decoder: Decoder) throws {
        self.init(initialValue: try .init(from: decoder))
    }
}

Быстрая проверка:

class User: ObservableObject, Codable {
    @Published var name = "Paul"
}

struct ContentView: View {
    @ObservedObject var user = User()
    var body: some View {
        let data = try? JSONEncoder().encode(user)
        let dataFromStr = """
                {
                    "name": "Smith"
                }
                """
            .data(using: .utf8)
        let decoded = try! JSONDecoder().decode(User.self, from: dataFromStr!)
        return
            VStack{
                Text(verbatim: String(data: data!, encoding: .utf8) ?? "encoding failed")
                Text(decoded.name)
            }
    }
}
0
Paul B 21 Ноя 2020 в 09:11