Codableから説明
関連するファイルは二つあります:
- gybにユーザーに公開しているprotocolおよびCodabelを実現しているSwiftのタイプ
- JSONEncoder.swift。JSONEncoderとJSONDecoderを実現しているファイルです。
続きましては、Codableの定義はここです:
public typealias Codable = Encodable & Decodable
Encodable
Encodableのタイプはなんでしょうか?実際、encode(to:)
メソッドを提供しているだけです。
public protocol Encodable {
/// Encodes this value into the given encoder.
///
/// If the value fails to encode anything, `encoder` will encode an empty
/// keyed container in its place.
///
/// This function throws an error if any values are invalid for the given
/// encoder's format.
///
/// - Parameter encoder: The encoder to write data to.
func encode(to encoder: Encoder) throws
}
ここまで、三つの質問を思い出すと:
1.SwiftがサポートしているEncodableのタイプは全部このメソッドを実現していますか?
2.SwiftではデフォルトでEncodableをサポートしているメソッドはなんでしょうか?
3.Encoderは何ですか?
質問1の答えはイエスです。Codable.swift.gybファイルにデフォルトタイプの実現があります。
例えば、Intのデフォルト実現は:
extension Int : Codable {
public func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
try container.encode(self)
}
}
Arrayのデフォルト実現は:
extension Array : Encodable where Element : Encodable {
public func encode(to encoder: Encoder) throws {
var container = encoder.unkeyedContainer()
for element in self {
try container.encode(element)
}
}
}
なるほど、Swiftでは本当にEncodableのタイプはメソッドを実現しています。
そしたら、Swiftでは、Encodableをサポートしているタイプはどれくらいありますか?
Codable.swift.gybファイルに下記のコードがあります。
%{
codable_types = ['Bool', 'String', 'Double', 'Float',
'Int', 'Int8', 'Int16', 'Int32', 'Int64',
'UInt', 'UInt8', 'UInt16', 'UInt32', 'UInt64']
}%
上記以外、ファイルの一番下に、Array / Set / Dictionary / Optionalなどもあります。
ここまで、質問3だけ残ってます。
encodeメソッドのEncoderはなんでしょうかね。ブラックボックスとして考えれば、結果的にSwiftのオブジェクトをJSON文字列にエンコディングされています。
#JSONEncoder
JSONEncodeの定義:
- JSONエンコーディング結果の出力フォマット(public struct OutputFormatting)
- Dateタイプのエンコーディング方式(public enum DateEncodingStrategy)
- Dataタイプのエンコーディング方式(public enum DataEncodingStrategy)
- 例外的な浮動小数点エンコーディング方式(public enum NonConformingFloatEncodingStrategy)
- JSONのkeyのエンコーディング方式(public enum KeyEncodingStrategy)
続きましては、JSONEncoderを使用してエンコーディングする時、デフォルト使用するプロパティ:
open class JSONEncoder {
open var outputFormatting: OutputFormatting = []
open var dateEncodingStrategy: DateEncodingStrategy = .deferredToDate
open var dataEncodingStrategy: DataEncodingStrategy = .base64
open var nonConformingFloatEncodingStrategy:
NonConformingFloatEncodingStrategy = .throw
open var keyEncodingStrategy: KeyEncodingStrategy = .useDefaultKeys
}
デフォルトのプロパティを便利に使う為、内部タイプの_Optionsと内部プロパティのoptionsも定義されています。
open class JSONEncoder {
fileprivate struct _Options {
let dateEncodingStrategy: DateEncodingStrategy
let dataEncodingStrategy: DataEncodingStrategy
let nonConformingFloatEncodingStrategy:
NonConformingFloatEncodingStrategy
let keyEncodingStrategy: KeyEncodingStrategy
let userInfo: [CodingUserInfoKey : Any]
}
fileprivate var options: _Options {
return _Options(dateEncodingStrategy: dateEncodingStrategy,
dataEncodingStrategy: dataEncodingStrategy,
nonConformingFloatEncodingStrategy: nonConformingFloatEncodingStrategy,
keyEncodingStrategy: keyEncodingStrategy,
userInfo: userInfo)
}
}
そして、JSONEncoderのコンストラクタ(only one):
open class JSONEncoder {
public init() {}
}
最後は、我々が使用するencodeメソッド:
open func encode<T : Encodable>(_ value: T) throws -> Data
__JSONEncoder
これから、JSONEncoder.encodeメソッドの実現から見てみましょう。関数定義はここです。
実行ロジック:
open func encode<T : Encodable>(_ value: T) throws -> Data {
let encoder = __JSONEncoder(options: self.options)
guard let topLevel = try encoder.box_(value) else {
/// throw exception
}
/// Handle invalid box value.
let writingOptions =
JSONSerialization.WritingOptions(
rawValue: self.outputFormatting.rawValue)
do {
return try JSONSerialization.data(
withJSONObject: topLevel, options: writingOptions)
} catch {
/// throw exception
}
}
encodeの実現:
- まず、Encoderタイプの__JSONEncoderオブジェクトを作る
- そして、box_メソッドでパラメーターvalueをJSONエンコーディングできるデーターに変換する
- エラーチェックなどされたら、FoundationのJSONSerialization.dataを呼び出し、データーのエンコーディングできて、エンコーディング結果のDataオブジェクトをreturn