我正在嘗試撰寫自定義代碼Coder,但我無法理解某些內容,尤其是關于該Encoder部分的內容。
Encoder只需要三個函式和兩個變數:
struct MyEncoder : Encoder {
public var codingPath : [CodingKey]
public var userInfo : [CodingUserInfoKey : Any]
public func container<Key>(keyedBy type: Key.Type -> KeyedEncodingContainer<Key> where Key : CodingKey {}
public func unkeyedContainer() -> UnkeyedEncodingContainer {}
public func singleValueContainer() -> SingleValueEncodingContainer {}
}
你會注意到,它們都沒有變異。他們都回傳一些東西,就是這樣。
概括地說,容器本身具有將特定型別編碼到自身中的子功能:
struct MySingleValueContainer : SingleValueEncodingContainer {
var codingPath: [CodingKey]
mutating func encode(_ value : someType) throws {}
/// etc with a lot of different types
}
如果用戶想要自定義他們的類的編碼方式,他們可以這樣做:
func encode(to: Encoder) throws {}
這是我的問題!編碼器在呼叫后仍然存在,encode(to: Encoder)但它不會發生變異,那么編碼資料如何在其中結束?閱讀JSON 編碼器的源代碼,我可以看到他們的容器有一個包含 a 的變數Encoder,該變數被傳遞下來。但它應該像 Swift 中的其他所有內容一樣是寫時復制的,這意味著資料不應該能夠回傳到鏈上!
是否以Encoder某種方式秘密地作為參考而不是作為值傳遞?這似乎是唯一合乎邏輯的結論,但對我來說似乎很奇怪......如果不是,發生了什么?
I have also taken a look at this question and its answer, and although they have helped me they display the same behaviour of magically bringing data up the chain, except it passes down a custom type instead of the Encoder itself.
uj5u.com熱心網友回復:
是否以
Encoder某種方式秘密地作為參考而不是作為值傳遞?
關閉,但不完全。它的底層容器是用于基于參考的存盤JSONEncoder的相對薄的單板介面。在非達爾文平臺上使用的 swift-corelibs-foundation 實作中,這是使用和存盤鍵控物件來完成的;在達爾文平臺上,使用and也是如此。正是這些參考物件被傳遞和共享,因此雖然可以傳遞各個 s 和容器,但它們正在寫入共享存盤。RefArrayRefObjectNSMutableArrayNSMutableDictionaryEncoder
但它應該像 Swift 中的其他所有內容一樣是寫時復制的,這意味著資料不應該能夠沿著鏈回傳!
關于這一點的另一個注意事項:此實作內部的所有相關型別都是類(例如JSONEncoderImpl,在 swift-corelibs-foundation 中,_JSONEncoder在 Darwin 中),這意味著它們不會是寫時復制,而是通過反正參考。
關于您的編輯:這與鏈接答案使用的方法相同fileprivate final class Data- 它是在所有內部型別之間共享并傳遞的類。
uj5u.com熱心網友回復:
JSONEncoder.encode用作( source )JSONEncoderImpl的具體實作:Encoder
open func encode<T: Encodable>(_ value: T) throws -> Data {
let value: JSONValue = try encodeAsJSONValue(value)
...
}
func encodeAsJSONValue<T: Encodable>(_ value: T) throws -> JSONValue {
let encoder = JSONEncoderImpl(options: self.options, codingPath: [])
guard let topLevel = try encoder.wrapEncodable(value, for: nil) else {
...
}
return topLevel
}
wrapEncodable然后最終會呼叫encode(to: Encoder)你的Codable型別self作為引數。
是否以
Encoder某種方式秘密地作為參考而不是作為值傳遞?
請注意,這JSONEncoderImpl是一個類,所以這根本沒有什么“秘密”。在這種特殊情況下,編碼器作為參考傳遞。
不過,一般來說,Encoder實作也可以是 a struct,并按值傳遞。畢竟,它需要做的就是提供可以將資料編碼到其中的可變容器。只要你在某個地方有一個類,就可以“看似”改變一個結構,而無需mutating或使結構 a var。考慮:
private class Bar {
var magic: Int = -1
}
struct Foo: CustomStringConvertible {
private let bar = Bar()
var description: String { "\(bar.magic)" }
func magicallyMutateMyself() {
bar.magic = Int.random(in: 0..<100)
}
}
let foo = Foo()
print(foo) // -1
foo.magicallyMutateMyself()
print(foo) // some other number
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/440608.html
