utahiosmac / Marshal

Marshaling the typeless wild west of [String: Any]
MIT License
697 stars 62 forks source link

Core Data and NSManagedObject #66

Closed Tibb closed 7 years ago

Tibb commented 7 years ago

Hi, I really like your approach with Marshal and I wanted to implement it in my project. However, I'm currently using core Data and my objects are NSManagedObjects.

I'm trying to find a way to coexist Marshal and Core Data, but I haven't found any working solution yet. Did you already tried something similar?

Thanks a lot

radianttap commented 7 years ago

What's the possibility that I opened Issues to look into this and see your post, posted 20s earlier? :)

Anw, I believe the answer lies with UnmarshalingWithContext protocol that seem to fit the bill. I discovered Marshal like 2h ago so would love some guidance as well.

Tibb commented 7 years ago

Haha what a coincidence @radianttap :) Same here, I'm new with Marshal and would love a bit of help to deal with CoreData.

jarsen commented 7 years ago

Hey guys! Yes, UnmarshalingWithContext is designed for CoreData and similar situations. The idea is that since you don't really have control of the initialization phase of your NSManagedObject, that you create your managed object as usual, and then call update, passing in the desired context and MarshaledObject.

bwhiteley commented 7 years ago

Like @jarsen said, UnmarshalingWithContext and UnmarshalUpdatingWithContext might be what you want.

Look at UnmarshalingWithContextTests.swift for an example.

radianttap commented 7 years ago

Tnx guys

jarsen commented 7 years ago

I'm going to go ahead and close this issue, but feel free to ask more questions if this hasn't been helpful enough!

radianttap commented 7 years ago

I am using mogenerator to create Swift class files. Here's an (stripped down) example how I implemented Marshal on an entity called SportType. I still have to put this through full testing, but I hope it's helpful to everyone else wondering how to do this.

import Foundation
import CoreData
import Marshal

open class _SportType: NSManagedObject {
    //...
    @NSManaged open
    var sportTypeId: String!
}

@objc(SportType)
open class SportType: _SportType, Marshaling, UnmarshalingWithContext, UnmarshalUpdatingWithContext {
    public typealias MarshalType = MarshalDictionary
    public typealias ContextType = NSManagedObjectContext

    public func marshaled() -> MarshalType {
        var json = MarshalType()

        json["idfosporttype"] = sportTypeId

        return json
    }

    public static func value(from object: MarshaledObject, inContext context: NSManagedObjectContext) throws -> SportType {
        let ed = entity(managedObjectContext: context)!
        let mo = SportType(entity: ed, insertInto: context)

        mo.sportTypeId = try object.any(for: "idfosporttype") as! String

        return mo
    }

    public func update(object: MarshaledObject, inContext context: NSManagedObjectContext) throws {

        self.sportTypeId = try object.any(for: "idfosporttype") as! String
    }
}

update method works directly over the existing object, simply updating the attributes. static func value creates the NSMO and returns it back. In case anything went wrong, context will delete this object in the calling scope. I'm thinking of maybe wrapping the deletion inside value.

If you spot glaring omission, do tell :)

Tibb commented 7 years ago

thx guys and thx @radianttap, I'm not using mogenerator, but your code still helped.