Closed minuscorp closed 8 years ago
You should be able to click a dropdown next to that error in Xcode within the issue navigator to see exactly what parts of the protocol are missing. It certainly looks to me like everything is correct as I glance at it, so I'm very curious what information the error will tell us. Please gather more info and let me know!
Additionally, if you post the model object and DateMapping
code here I can try it out on my end and let you know what I see.
It seems like it was an issue with the code is necessary to include in the project, maybe the code in the README
is wrong. I copied the code from the tests and now is working, thank you!
Altough I've finally made it compile, I'm unable to run properly the testing...
override func spec(){
describe("User spec"){
var realmUser: User!
var realm: Realm!
var adaptor: RealmAdaptor!
beforeEach{
Realm.Configuration.defaultConfiguration.inMemoryIdentifier = self.name
realm = try! Realm()
adaptor = RealmAdaptor(realm: realm)
}
it("Should decode JSON User objects"){
let json: Dictionary<String, AnyObject> = ["data": ["id_hash": 170, "user_name": "Jorge", "user_surname": "Revuelta", "birthdate": "1991-03-31", "height": 175, "weight": 60, "sex": 2]]
let mapping = CRMapper<User, UserMapping>()
let jsonValue = try! JSONValue(object: json)
let realmUser = try! mapping.mapFromJSONToNewObject(jsonValue, mapping: UserMapping(adaptor: adaptor))
try! adaptor.saveObjects([ realmUser ])
expect(realm.objects(User).count) == 1
}
}
}
I get the next error in the mapFromJSONToNewObject
method:
fatal error: 'try!' expression unexpectedly raised an error: Error Domain=CRMappingDomain Code=-1 "(null)": file /Library/Caches/com.apple.xbs/Sources/swiftlang/swiftlang-700.1.101.15/src/swift/stdlib/public/core/ErrorType.swift, line 50
EDIT
It seems like if I skip the DateMapping
it works fine, is necessary to do something special to make a custom transform to work with RealMapping
?
This is my custom DateMapping
Transform
:
extension NSDate: AnyMappable { }
class DateMapping: Transform {
typealias MappedObject = NSDate
let dateFormatter: NSDateFormatter
init(dateFormatter: NSDateFormatter){
self.dateFormatter = dateFormatter
}
func fromJSON(json: JSONValue) throws -> MappedObject {
switch json {
case .JSONString(let date):
return self.dateFormatter.dateFromString(date) ?? NSDate()
default:
throw NSError(domain: "", code: 0, userInfo: nil)
}
}
func toJSON(obj: MappedObject) -> JSONValue {
return .JSONString(self.dateFormatter.stringFromDate(obj))
}
}
EDIT 2
Also you asked for the Realm Object
implementation:
public class User: Object {
public dynamic var identifier: Int = 0
public dynamic var name: String? = nil
public dynamic var surname: String? = nil
public dynamic var birthDate: NSDate = NSDate()
// Function i'd like to use but it seems to crash also the RealmCrust with 'Primary key can't be changed after an object is inserted.'
/*override public static func primaryKey() -> String? {
return "identifier"
}*/
}
Thanks for the info. I'm pretty busy the rest of the week, if you figure out anything soon feel free to open a pull request.
I'll work this weekend to fix
Function i'd like to use but it seems to crash also the RealmCrust with 'Primary key can't be changed after an object is inserted.'
Seems like something I just need to special case.
And for the crash you're experiencing I'll run an equivalent test with the code you provided and see where the error lies. Nothing looks incorrect from what I can tell. We'll get this figured out.
I've been trying to debug this several times. I get lost when method mapping
gets called and when returns to the mapper, context
has an error != nil
but I haven't found where it gets set so I'm out of clues of where to start and so on.
Also, maybe it should be an enchancement for Crust itself, Realm supports other types like Int64
that doesn't seem to be supported by mapping
or even for JSONValuesRX
when it finds an mapping like toMap.identifier <- "data.identifier" >*<
and identifier
is an Int64
type.
Ok, so as far as I've got, no custom DateMapping
is being called but the NSDate
mapping from JSONValueRX
so that's the main reason why it fails:
private func mapFromJson<T: JSONable where T.ConversionType == T>(json: JSONValue, inout toField field: T?) throws {
if case .JSONNull = json {
field = nil
return
}
// This next line calls NSDate.fromJSON defined in JSONValueRX instead of mine...
if let fromJson = T.fromJSON(json) {
field = fromJson
} else {
throw NSError(domain: CRMappingDomain, code: -1, userInfo: nil)
}
}
Should the second or the fourth one being called when using a KeyExtensions.Mapping
? They're not being called at all:
// Map arbitrary object.
public func <- <T: JSONable, C: MappingContext where T == T.ConversionType>(inout field: T, map:(key: JSONKeypath, context: C)) -> C {
return mapField(&field, map: map)
}
// Map a Mappable.
public func <- <T: Mappable, U: Mapping, C: MappingContext where U.MappedObject == T>(inout field: T, map:(key: KeyExtensions<U>, context: C)) -> C {
return mapField(&field, map: map)
}
// NOTE: Must supply two separate versions for optional and non-optional types or we'll have to continuously
// guard against unsafe nil assignments.
public func <- <T: JSONable, C: MappingContext where T == T.ConversionType>(inout field: T?, map:(key: JSONKeypath, context: C)) -> C {
return mapField(&field, map: map)
}
public func <- <T: Mappable, U: Mapping, C: MappingContext where U.MappedObject == T>(inout field: T?, map:(key: KeyExtensions<U>, context: C)) -> C {
return mapField(&field, map: map)
}
public func <- <T: JSONable, C: MappingContext where T == T.ConversionType>(inout field: T?, map:(key: JSONKeypath, context: C)) -> C {
return mapField(&field, map: map)
}
This gets called when trying to map with the DateMapping
. I think it should call the KeyExtensions<U>
ones?
This is the backtrace:
Printing description of map:
(key: JSONKeypath) map = {
key = {
payload_data_0 = 0x00007fb94b30ea20 -> 0x0000000108028ba0 "data.birthdate"
payload_data_1 = 0x00000000000014e8
payload_data_2 = 0x00000001086c63d7 Crust`ext.Crust.Crust.Mapping<A where A: Crust.Mapping>.startMappingWithContext <A where A: Crust.Mapping> (A)(Crust.MappingContext) throws -> () + 903 at CRMapper.swift:114
instance_type = 0x000000011cb57138
protocol_witness_0 = 0x00000001086eeb28 Crust`protocol witness table for <A where A: Crust.Mapping> Crust.KeyExtensions<A> : JSONValueRX.JSONKeypath in Crust
}
}
Printing description of map.key.Mapping.1:
(Ebikemotion.DateMapping) 1 = 0x00007fb948c65240 {
dateFormatter = 0x00007fb948c18910 {
Foundation.NSFormatter = {
ObjectiveC.NSObject = {}
}
}
}
I think it's fixed with the PR opened in Crust https://github.com/rexmas/Crust/pull/31
Ya, I tried your example on one of my model objects and it worked fine. Then I tried your test verbatim and I ended up with the same crash. Seems like this is a case where the compiler resolves the operator of choice different just based on some internal context we aren't aware of. Thanks for looking into this. Going to review your PR.
I have a class created with a
RealmMapping
:And I'm writing a test to check everything's working fine with the JSON decoding but when I create the
CRMapper
compiler fails:let userMapper = CRMapper<User, UserMapping>
-> `Type 'UserMapping' does not conform to protocol 'Mapping'I've added the file that is required in the
Readme.md``Any clue?