Skip to content

Instantly share code, notes, and snippets.

@godrm
Created February 27, 2020 10:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save godrm/c765a8a584b1e0b50913d595dfbabc50 to your computer and use it in GitHub Desktop.
Save godrm/c765a8a584b1e0b50913d595dfbabc50 to your computer and use it in GitHub Desktop.
//
// archiver.swift
//
// Created by JK on 2020/02/27.
// Copyright © 2020 codesquad. All rights reserved.
//
import Foundation
class NBeverage : NSObject, NSCoding, Codable {
private var brand : String = ""
private enum CodingKeys: String, CodingKey {
case brand
}
init(brand : String) {
self.brand = brand
}
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.brand = try container.decode(String.self, forKey: .brand)
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(brand, forKey: .brand)
}
required init?(coder: NSCoder) {
self.brand = coder.decodeObject(forKey: "brand") as! String
}
func encode(with coder: NSCoder) {
coder.encode(brand, forKey: "brand")
}
override var description: String {
return "Beverage(\(brand))"
}
}
class NCoffee : NBeverage {
private var caffeine : Double = 0
private enum CodingKeys: String, CodingKey {
case caffeine
}
init(brand : String, caffeine : Double) {
self.caffeine = caffeine
super.init(brand: brand)
}
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.caffeine = try container.decode(Double.self, forKey: .caffeine)
try super.init(from: decoder)
}
override func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(caffeine, forKey: .caffeine)
try super.encode(to: encoder)
}
required init?(coder: NSCoder) {
self.caffeine = coder.decodeDouble(forKey: "caffeine")
super.init(coder: coder)
}
override func encode(with coder: NSCoder) {
coder.encode(caffeine, forKey: "caffeine")
super.encode(with: coder)
}
override var description: String {
return "Coffee(\(caffeine))-(\(super.description))"
}
}
class NSoda : NBeverage {
private var nitrogen : Double = 0
private enum CodingKeys: String, CodingKey {
case nitrogen
}
init(brand: String, nitrogen : Double) {
self.nitrogen = nitrogen
super.init(brand: brand)
}
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.nitrogen = try container.decode(Double.self, forKey: .nitrogen)
try super.init(from: decoder)
}
override func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(nitrogen, forKey: .nitrogen)
try super.encode(to: encoder)
}
required init?(coder: NSCoder) {
self.nitrogen = coder.decodeDouble(forKey: "nitrogen")
super.init(coder: coder)
}
override func encode(with coder: NSCoder) {
coder.encode(nitrogen, forKey: "nitrogen")
super.encode(with: coder)
}
override var description: String {
return "Soda(\(nitrogen))-(\(super.description))"
}
}
class NCoke : NSoda {
private var diet : Bool = false
private enum CodingKeys: String, CodingKey {
case diet
}
init(brand: String, nitrogen: Double, diet: Bool) {
self.diet = diet
super.init(brand: brand, nitrogen: nitrogen)
}
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.diet = try container.decode(Bool.self, forKey: .diet)
try super.init(from: decoder)
}
override func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(diet, forKey: .diet)
try super.encode(to: encoder)
}
required init?(coder: NSCoder) {
self.diet = coder.decodeBool(forKey: "diet")
super.init(coder: coder)
}
override func encode(with coder: NSCoder) {
coder.encode(diet, forKey: "diet")
super.encode(with: coder)
}
override var description: String {
return "Coke(\(diet))-(\(super.description))"
}
}
func archive(with things: [NBeverage]) -> Data {
do {
let archived = try NSKeyedArchiver.archivedData(withRootObject: things, requiringSecureCoding: false)
return archived
}
catch {
print(error)
}
return Data()
}
func unarchive(with text: Data) -> [NBeverage]? {
do {
let object = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(text)
return object as? [NBeverage]
}
catch {
print(error)
}
return []
}
//
// codable.swift
//
// Created by JK on 2020/02/27.
// Copyright © 2020 codesquad. All rights reserved.
//
import Foundation
class Beverage : Codable, CustomStringConvertible {
private var brand : String = ""
private enum CodingKeys: String, CodingKey {
case brand
}
init(brand : String) {
self.brand = brand
}
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.brand = try container.decode(String.self, forKey: .brand)
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(brand, forKey: .brand)
}
var description: String {
return "Beverage(\(brand))"
}
}
class Coffee : Beverage {
private var caffeine : Double = 0
private enum CodingKeys: String, CodingKey {
case caffeine
}
init(brand : String, caffeine : Double) {
self.caffeine = caffeine
super.init(brand: brand)
}
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.caffeine = try container.decode(Double.self, forKey: .caffeine)
try super.init(from: decoder)
}
override func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(caffeine, forKey: .caffeine)
try super.encode(to: encoder)
}
override var description: String {
return "Coffee(\(caffeine))-(\(super.description))"
}
}
class Soda : Beverage {
private var nitrogen : Double = 0
private enum CodingKeys: String, CodingKey {
case nitrogen
}
init(brand: String, nitrogen : Double) {
self.nitrogen = nitrogen
super.init(brand: brand)
}
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.nitrogen = try container.decode(Double.self, forKey: .nitrogen)
try super.init(from: decoder)
}
override func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(nitrogen, forKey: .nitrogen)
try super.encode(to: encoder)
}
override var description: String {
return "Soda(\(nitrogen))-(\(super.description))"
}
}
class Coke : Soda {
private var diet : Bool = false
private enum CodingKeys: String, CodingKey {
case diet
}
init(brand: String, nitrogen: Double, diet: Bool) {
self.diet = diet
super.init(brand: brand, nitrogen: nitrogen)
}
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.diet = try container.decode(Bool.self, forKey: .diet)
try super.init(from: decoder)
}
override func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(diet, forKey: .diet)
try super.encode(to: encoder)
}
override var description: String {
return "Coke(\(diet))-(\(super.description))"
}
}
func encode(with things: [Beverage]) -> String {
let jsonEncoder = JSONEncoder()
do {
let json = try jsonEncoder.encode(things)
return String(data: json, encoding: .utf8) ?? ""
}
catch {
print(error)
}
return ""
}
func decode(with text: String) -> [Beverage] {
let jsonDecoder = JSONDecoder()
do {
let jsonObject = try jsonDecoder.decode([Beverage].self, from: text.data(using: .utf8) ?? Data())
return jsonObject
}
catch {
print(error)
}
return []
}
let ndrinks : [NBeverage] = [ NCoke(brand: "Coca", nitrogen: 50, diet: true),
NCoffee(brand: "TOP", caffeine: 256),
NCoke(brand: "Pepsi", nitrogen: 51, diet: false) ]
let archiveText = archive(with: ndrinks)
let archiveObject = unarchive(with: archiveText)
result = ""
archiveObject?.forEach{
result += $0.description + ", "
}
print(result)
let drinks : [Beverage] = [ Coke(brand: "Coca", nitrogen: 50, diet: true),
Coffee(brand: "TOP", caffeine: 256),
Coke(brand: "Pepsi", nitrogen: 51, diet: false) ]
let jsonText = encode(with: drinks)
let jsonObject = decode(with: jsonText)
var result = ""
jsonObject.forEach{
result += $0.description + ", "
}
print(result)
/*
Swift 4 Decodable Loses Subclass Type Information
https://bugs.swift.org/browse/SR-5331
This is by design — if you need the dynamism required to do this, we recommend that you adopt NSSecureCoding and use NSKeyedArchiver/NSKeyedUnarchiver, which will allow you to decode based on the class found in the archive rather than what is requested at runtime. See https://developer.apple.com/documentation/foundation/nscoding and https://developer.apple.com/documentation/foundation/nssecurecoding for more info.
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment