Last active
June 3, 2016 00:20
-
-
Save msanders/d14f1d9dfbe427bb9afd36ad2515ba07 to your computer and use it in GitHub Desktop.
NSCoding in Swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
import Mapper | |
protocol Archivable: Mappable { | |
func encode(archive: Archiver) | |
} | |
final class Archiver { | |
private var mapping: [String: AnyObject] = [:] | |
required init(_ object: Archivable) { | |
object.encode(self) | |
} | |
func encode(key: String, value: AnyObject?) { | |
mapping[key] = value | |
} | |
func encode<T: Archivable>(key: String, value: T?) { | |
if let value = value { | |
mapping[key] = Archiver(value).mapping | |
} | |
} | |
func encode<T: Archivable>(key: String, value: [T]?) { | |
mapping[key] = value?.map { Archiver($0).mapping } | |
} | |
} | |
private extension Mappable { | |
@warn_unused_result | |
static func from(JSON: [String: AnyObject]) throws -> Self { | |
return try self.init(map: Mapper(JSON: JSON)) | |
} | |
@warn_unused_result | |
static func from(JSON: [[String: AnyObject]]) throws -> [Self] { | |
return try JSON.map { try self.from($0) } | |
} | |
} | |
enum ArchiverError: ErrorType { | |
case ConvertibleError(value: AnyObject?, type: Any.Type) | |
} | |
extension Archivable { | |
@warn_unused_result | |
static func decode(data: NSData) throws -> Self { | |
var unarchived: AnyObject? | |
do { | |
try INSObjC.catchException { | |
unarchived = NSKeyedUnarchiver.unarchiveObjectWithData(data) | |
} | |
} catch { | |
throw error | |
} | |
guard let dict = unarchived as? [String: AnyObject] else { | |
throw ArchiverError.ConvertibleError(value: unarchived, type: [String: AnyObject].self) | |
} | |
return try Self.from(dict) | |
} | |
@warn_unused_result | |
static func decodeArray(data: NSData) throws -> [Self] { | |
var unarchived: AnyObject? | |
do { | |
try INSObjC.catchException { | |
unarchived = NSKeyedUnarchiver.unarchiveObjectWithData(data) | |
} | |
} catch { | |
throw error | |
} | |
guard let array = unarchived as? [[String: AnyObject]] else { | |
throw ArchiverError.ConvertibleError(value: unarchived, | |
type: [[String: AnyObject]].self) | |
} | |
return try Self.from(array) | |
} | |
@warn_unused_result | |
func encode() throws -> NSData { | |
var data: NSData? | |
do { | |
try INSObjC.catchException { | |
data = NSKeyedArchiver.archivedDataWithRootObject(Archiver(self).mapping) | |
} | |
} catch { | |
throw error | |
} | |
if let data = data { | |
return data | |
} else { | |
fatalError() // Impossible | |
} | |
} | |
} | |
extension SequenceType where Generator.Element: Archivable { | |
@warn_unused_result | |
func encode() throws -> NSData { | |
let mappings = map { Archiver($0).mapping } | |
var data: NSData? | |
do { | |
try INSObjC.catchException { | |
data = NSKeyedArchiver.archivedDataWithRootObject(mappings) | |
} | |
} catch { | |
throw error | |
} | |
if let data = data { | |
return data | |
} else { | |
fatalError() // Impossible | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Would be great to embed example usage as code comments for posterity.