-
-
Save mishagray/3ee82a3a82f357bfbf8ff3b3d9eca5cd to your computer and use it in GitHub Desktop.
// | |
// RealmSwift+Codable.swift | |
// | |
// Created by Michael Gray on 8/16/17. | |
// | |
import Foundation | |
import RealmSwift | |
// swiftlint:disable line_length identifier_name | |
// stolen functions from the Swift stdlib | |
// https://github.com/apple/swift/blob/2e5817ebe15b8c2fc2459e08c1d462053cbb9a99/stdlib/public/core/Codable.swift | |
// | |
func assertTypeIsEncodable<T>(_ type: T.Type, in wrappingType: Any.Type) { | |
guard T.self is Encodable.Type else { | |
if T.self == Encodable.self || T.self == Codable.self { | |
preconditionFailure("\(wrappingType) does not conform to Encodable because Encodable does not conform to itself. You must use a concrete type to encode or decode.") | |
} else { | |
preconditionFailure("\(wrappingType) does not conform to Encodable because \(T.self) does not conform to Encodable.") | |
} | |
} | |
} | |
func assertTypeIsDecodable<T>(_ type: T.Type, in wrappingType: Any.Type) { | |
guard T.self is Decodable.Type else { | |
if T.self == Decodable.self || T.self == Codable.self { | |
preconditionFailure("\(wrappingType) does not conform to Decodable because Decodable does not conform to itself. You must use a concrete type to encode or decode.") | |
} else { | |
preconditionFailure("\(wrappingType) does not conform to Decodable because \(T.self) does not conform to Decodable.") | |
} | |
} | |
} | |
extension Encodable { | |
func __encode(to container: inout SingleValueEncodingContainer) throws { try container.encode(self) } | |
func __encode(to container: inout UnkeyedEncodingContainer) throws { try container.encode(self) } | |
func __encode<Key>(to container: inout KeyedEncodingContainer<Key>, forKey key: Key) throws { try container.encode(self, forKey: key) } | |
} | |
extension Decodable { | |
// Since we cannot call these __init, we'll give the parameter a '__'. | |
fileprivate init(__from container: SingleValueDecodingContainer) throws { self = try container.decode(Self.self) } | |
fileprivate init(__from container: inout UnkeyedDecodingContainer) throws { self = try container.decode(Self.self) } | |
fileprivate init<Key>(__from container: KeyedDecodingContainer<Key>, forKey key: Key) throws { self = try container.decode(Self.self, forKey: key) } | |
} | |
extension RealmOptional : Encodable /* where Wrapped : Encodable */ { | |
public func encode(to encoder: Encoder) throws { | |
assertTypeIsEncodable(T.self, in: type(of: self)) | |
var container = encoder.singleValueContainer() | |
if let v = self.value { | |
try (v as! Encodable).encode(to: encoder) // swiftlint:disable:this force_cast | |
} else { | |
try container.encodeNil() | |
} | |
} | |
} | |
extension RealmOptional : Decodable /* where Wrapped : Decodable */ { | |
public convenience init(from decoder: Decoder) throws { | |
// Initialize self here so we can get type(of: self). | |
self.init() | |
assertTypeIsDecodable(T.self, in: type(of: self)) | |
let container = try decoder.singleValueContainer() | |
if !container.decodeNil() { | |
let metaType = (T.self as! Decodable.Type) // swiftlint:disable:this force_cast | |
let element = try metaType.init(from: decoder) | |
self.value = (element as! T) // swiftlint:disable:this force_cast | |
} | |
} | |
} | |
extension List : Decodable /* where Element : Decodable */ { | |
public convenience init(from decoder: Decoder) throws { | |
// Initialize self here so we can get type(of: self). | |
self.init() | |
assertTypeIsDecodable(T.self, in: type(of: self)) | |
let metaType = (T.self as! Decodable.Type) // swiftlint:disable:this force_cast | |
var container = try decoder.unkeyedContainer() | |
while !container.isAtEnd { | |
let element = try metaType.init(__from: &container) | |
self.append(element as! Element) // swiftlint:disable:this force_cast | |
} | |
} | |
} | |
extension List : Encodable /* where Element : Decodable */ { | |
public func encode(to encoder: Encoder) throws { | |
assertTypeIsEncodable(T.self, in: type(of: self)) | |
var container = encoder.unkeyedContainer() | |
for element in self { | |
// superEncoder appends an empty element and wraps an Encoder around it. | |
// This is normally appropriate for encoding super, but this is really what we want to do. | |
let subencoder = container.superEncoder() | |
try (element as! Encodable).encode(to: subencoder) // swiftlint:disable:this force_cast | |
} | |
} | |
} |
import Foundation
import RealmSwift
// swiftlint:disable line_length identifier_name
// stolen functions from the Swift stdlib
// https://github.com/apple/swift/blob/2e5817ebe15b8c2fc2459e08c1d462053cbb9a99/stdlib/public/core/Codable.swift
//
func assertTypeIsEncodable<T>(_ type: T.Type, in wrappingType: Any.Type) {
guard T.self is Encodable.Type else {
if T.self == Encodable.self || T.self == Codable.self {
preconditionFailure("\(wrappingType) does not conform to Encodable because Encodable does not conform to itself. You must use a concrete type to encode or decode.")
} else {
preconditionFailure("\(wrappingType) does not conform to Encodable because \(T.self) does not conform to Encodable.")
}
}
}
func assertTypeIsDecodable<T>(_ type: T.Type, in wrappingType: Any.Type) {
guard T.self is Decodable.Type else {
if T.self == Decodable.self || T.self == Codable.self {
preconditionFailure("\(wrappingType) does not conform to Decodable because Decodable does not conform to itself. You must use a concrete type to encode or decode.")
} else {
preconditionFailure("\(wrappingType) does not conform to Decodable because \(T.self) does not conform to Decodable.")
}
}
}
extension Encodable {
func __encode(to container: inout SingleValueEncodingContainer) throws { try container.encode(self) }
func __encode(to container: inout UnkeyedEncodingContainer) throws { try container.encode(self) }
func __encode<Key>(to container: inout KeyedEncodingContainer<Key>, forKey key: Key) throws { try container.encode(self, forKey: key) }
}
extension Decodable {
// Since we cannot call these __init, we'll give the parameter a '__'.
fileprivate init(__from container: SingleValueDecodingContainer) throws { self = try container.decode(Self.self) }
fileprivate init(__from container: inout UnkeyedDecodingContainer) throws { self = try container.decode(Self.self) }
fileprivate init<Key>(__from container: KeyedDecodingContainer<Key>, forKey key: Key) throws { self = try container.decode(Self.self, forKey: key) }
}
extension RealmOptional : Encodable where Value : Encodable {
public func encode(to encoder: Encoder) throws {
assertTypeIsEncodable(Value.self, in: type(of: self))
var container = encoder.singleValueContainer()
if let v = self.value {
try (v as! Encodable).encode(to: encoder) // swiftlint:disable:this force_cast
} else {
try container.encodeNil()
}
}
}
extension RealmOptional : Decodable where Value : Decodable {
public convenience init(from decoder: Decoder) throws {
// Initialize self here so we can get type(of: self).
self.init()
assertTypeIsDecodable(Value.self, in: type(of: self))
let container = try decoder.singleValueContainer()
if !container.decodeNil() {
let metaType = (Value.self as! Decodable.Type) // swiftlint:disable:this force_cast
let element = try metaType.init(from: decoder)
self.value = (element as! Value) // swiftlint:disable:this force_cast
}
}
}
extension List : Decodable where Element : Decodable {
public convenience init(from decoder: Decoder) throws {
// Initialize self here so we can get type(of: self).
self.init()
assertTypeIsDecodable(Element.self, in: type(of: self))
let metaType = (Element.self as! Decodable.Type) // swiftlint:disable:this force_cast
let container = try? decoder.unkeyedContainer()
if var container = container {
while !container.isAtEnd {
let element = try metaType.init(__from: &container)
self.append(element as! Element) // swiftlint:disable:this force_cast
}
} else {
}
}
}
extension List : Encodable where Element : Decodable {
public func encode(to encoder: Encoder) throws {
assertTypeIsEncodable(Element.self, in: type(of: self))
var container = encoder.unkeyedContainer()
for element in self {
// superEncoder appends an empty element and wraps an Encoder around it.
// This is normally appropriate for encoding super, but this is really what we want to do.
let subencoder = container.superEncoder()
try (element as! Encodable).encode(to: subencoder) // swiftlint:disable:this force_cast
}
}
}
import Foundation
import RealmSwift
@objcMembers
class Book: Object, Decodable {
dynamic var name: String = ""
private(set) var optionalBool = RealmOptional<Bool>()
}
@objcMembers
class File: Object, Decodable {
dynamic var string: String = ""
dynamic var optionalString: String?
dynamic var int: Int = 0
private(set) var optionalInt = RealmOptional<Int>()
dynamic var bool: Bool = false
dynamic private(set) var optionalBool = RealmOptional<Bool>()
dynamic var optionalData: Data?
dynamic var optionalDate: Date?
dynamic var float: Float = 0.0
private(set) var optionalFloat = RealmOptional<Float>()
dynamic var book: Book?
dynamic var book2: Book?
private(set) var list = List<Book>()
private(set) var nullList = List<Int>()
}
let jsonData = """
{
"string": "struggle",
"optionalString": null,
"int": 1,
"optionalInt": null,
"bool": true,
"optionalBool": false,
"optionalData": null,
"optionalDate": null,
"float": 2.1,
"optionalFloat":null,
"book": {
"name": "sixsixsix",
"optionalBool": false
},
"book2": null,
"list": [
{
"name": "srv7",
"optionalBool": false
}
],
"nullList": null
}
""".data(using: .utf8)
do {
let x = try JSONDecoder().decode(File.self, from: jsonData!)
print(x)
} catch let e {
print(e)
}
this should works fine.
And one question:
with the entension to List:
extension List : Encodable where Element : Decodable {
...
}
Why is Decodable instead of Encodable?
@sofbix 's solution worked for me
@objcMembers
is very important
I spend hours searching for solution
because ,it always saved as Null in Realm
but when I printed it, I get value !
this only happens with String and any non-Optional value
after added @objcMembers
it finally worked !
and if you use Realm Optional you must use @sofbix solution
change let
to private(set) var
Thank you @srv7 and @sofbix and also @mishagray for this amazing Code !
Conformance of 'RealmOptional' to protocol 'Encodable' conflicts with that stated in the type's module 'RealmSwift' and will be ignored; there cannot be more than one conformance, even with different conditional bounds
Is there any way i can fix this? I am getting this warning
I'm struggling with the same issue. The init method is never called for me either.