現時点では、モバイルアプリケーションの大部分はクライアントサーバーです。 読み込み、同期、イベントの送信が行われるすべての場所で、サーバーと対話する主な方法は、json形式を使用してデータを交換することです。
キー復号化
財団には、データのシリアル化とディデラミネーションのための2つのメカニズムがあります。 古いはNSJsonSerialization
、新しいはCodable
です。 利点のリストの最後には、 Codable
( Encodable
、 Decodable
)を実装する構造(またはクラス)とデータをデコードするためのDecodable
基づくjsonデータのキーの自動生成などの素晴らしいものがあります。
そして、すべてがうまくいくようで、使用して楽しむことができますが、現実はそれほど単純ではありません。
サーバーでは、次の形式のjsonを見ることができます。
{"topLevelObject": { "underlyingObject": 1 }, "Error": { "ErrorCode": 400, "ErrorDescription": "SomeDescription" } }
これは、プロジェクトサーバーの1つからのほぼ実際の例です。
JsonDecoder
クラスでは、snake_caseキーを使用して作業を指定できますが、UpperCamelCase、dash-snake-case、または一般的なhodgepodgeがあり、キーを手動で記述したくない場合はどうでしょうか。
幸いなことに、AppleはCodingKeys
を使用してCodingKeys
構造と照合する前にキーマッピングを構成する機能を提供しJSONDecoder.KeyDecodingStrategy
。 これが使用するものです。
最初に、 CodingKey
プロトコルを実装する構造を作成します。これは、標準ライブラリには何もないためです。
struct AnyCodingKey: CodingKey { var stringValue: String var intValue: Int? init(_ base: CodingKey) { self.init(stringValue: base.stringValue, intValue: base.intValue) } init(stringValue: String) { self.stringValue = stringValue } init(intValue: Int) { self.stringValue = "\(intValue)" self.intValue = intValue } init(stringValue: String, intValue: Int?) { self.stringValue = stringValue self.intValue = intValue } }
次に、キーの各ケースを個別に処理する必要があります。 主なもの:
snake_case、dash-snake-case、lowerCamelCaseおよびUpperCamelCase。 チェック、実行、すべてが機能します。
次に、かなり予想される問題に遭遇します:camelCase'ahの略語(多数のid
、 Id
、 ID
思い出してください)。 それを機能させるには、それらを正しく変換し、ルールを導入する必要があります- 略語はキャメルケースに変換され、最初の文字は大文字のままmyABBRKeyがmyAbbrKeyに変わります。
このソリューションは、いくつかのケースの組み合わせに適しています。
注:実装は、 .custom
キーデコード戦略に提供されます。
static func convertToProperLowerCamelCase(keys: [CodingKey]) -> CodingKey { guard let last = keys.last else { assertionFailure() return AnyCodingKey(stringValue: "") } if let fromUpper = convertFromUpperCamelCase(initial: last.stringValue) { return AnyCodingKey(stringValue: fromUpper) } else if let fromSnake = convertFromSnakeCase(initial: last.stringValue) { return AnyCodingKey(stringValue: fromSnake) } else { return AnyCodingKey(last) } }
日付デコード
次の日常的な問題は、日付が渡される方法です。 サーバーには多くのマイクロサービスがあり、コマンドがわずかに少ないだけでなく、適切な量であるため、「はい、標準を使用します」などの多くの日付形式に直面しています。 さらに、誰かが文字列で日付を渡し、誰かがエポック時間で渡します。 その結果、string-number-timezone-millisecond-separatorの組み合わせの寄せDateDecoder
、iOSのDateDecoder
で問題が発生し、厳密な日付形式が必要になります。 ここでの解決策は簡単です。検索するだけで特定の形式の兆候を探し、それらを組み合わせて必要な結果を得ることができます。 これらのフォーマットは私のケースを完全にカバーしました。
注:これは、カスタムDateFormatter初期化子です。 作成されたフォーマッタにフォーマットを設定するだけです。
static let onlyDate = DateFormatter(format: "yyyy-MM-dd") static let full = DateFormatter(format: "yyyy-MM-dd'T'HH:mm:ss.SSSx") static let noWMS = DateFormatter(format: "yyyy-MM-dd'T'HH:mm:ssZ") static let noWTZ = DateFormatter(format: "yyyy-MM-dd'T'HH:mm:ss.SSS") static let noWMSnoWTZ = DateFormatter(format: "yyyy-MM-dd'T'HH:mm:ss")
JSONDecoder.DateDecodingStrategy
を使用してこれをデコーダーにアタッチし、ほとんどすべてを処理し、私たちにとって消化可能な形式に変換するデコーダーを取得します。
性能試験
テストは、サイズが7944バイトのJSON文字列に対して実行されました。
ご覧のとおり、jsonの各キーを強制的にチェックして変換する必要があるため、カスタムDecoder
20%遅くなります。 ただし、これはCodable
を実装してデータ構造のキーを明示的に登録する必要がないため、少額の費用です。 このデコーダーの追加により、プロジェクトでボイラープレートの数が大幅に削減されました。 開発者の時間を節約するために使用する必要がありますが、パフォーマンスは低下しますか? それはあなた次第です。
githubライブラリの完全なサンプルコード
英語の記事