Welcome toVigges Developer Community-Open, Learning,Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
823 views
in Technique[技术] by (71.8m points)

json - Do all attributes with a custom type in core-data have to be a relationship?

This is a followup question from the comments in the following How to map nested complex JSON objects and save them to core data?.

Imagine that I already have this code for my app.

class Passenger{
    var name: String
    var number: String
    var image : UIImage
    // init method
}
class Trip {
    let tripNumber : Int
    let passenger : Passenger

    init(tripNumber: Int, passenger: Passenger) {
        self.tripNumber = tripNumber
        self.passenger = passenger
    }
}

Now I've decided to add persistence for my app. I just want to have a table of Trips. I want to show the passengers under trips, but don't need a table to query passengers directly. It's just a custom object/property of trip. Every time I access passenger it would be through Trips.

So is there a way that I can create a new subclass of NSManagedObject named 'TripEntity' and store my passengers — WITHOUT 1. creating another NSManagedObject subclass for 'Passenger' 2. Creating a relationship with an inverse relationship between Passenger and Trip? Simply put I just want it to be an attribute. Conceptually to me it's also just an attribute. It's not really a relationship...

Or is that once you're using Core-data then every custom type needs to be explicitly a subclass of NSManagedObject? Otherwise it won't get persisted. I'm guessing this also what object graph means. That your graph needs to be complete. Anything outside the graph is ignored...

I'm asking this because the JSON object that I actually want to store is gigantic and I'm trying to reduce the work needed to be done.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

You can add passengers to one Trip entity but as the attribute types are restricted you have to use a transformable type which can be quite expensive to archive and unarchive the objects.

The most efficient way if the source data is JSON is to create Core Data entities for Passenger and Trip and add inverse relationships. Then make all NSManagedObject classes adopt Codable and add init(from decoder and encode(to encoder: methods to each class.

For example let's assume that the Trip class has a to-many relationship to Passenger it could look like

@NSManaged public var tripNumber: Int32
@NSManaged public var passengers: Set<Passenger>

and in the Passenger class there is an attribute trip

@NSManaged public var trip: Trip?

this is the required Decodable initializer in Trip. The decoder can decode arrays as well as sets.

private enum CodingKeys: String, CodingKey { case tripNumber, passengers }

public required convenience init(from decoder: Decoder) throws {
    guard let context = decoder.userInfo[.context] as? NSManagedObjectContext else { fatalError("Context Error") }
    let entity = NSEntityDescription.entity(forEntityName: "Trip", in: context)!
    self.init(entity: entity, insertInto: context)
    let values = try decoder.container(keyedBy: CodingKeys.self)
    tripNumber = try values.decode(Int32.self, forKey: .tripNumber)
    passengers = try values.decode(Set<Passenger>.self, forKey: .passengers)
    passengers.forEach{ $0.trip = self }
}

The inverse relationship is set via the forEach line.
You have to add an extension of JSONDecoder to be able to pass the current NSManagedObjectContext in the userInfo object.

The corresponding encoder is – pretty straightforward –

public func encode(to encoder: Encoder) throws {
    var container = encoder.container(keyedBy: CodingKeys.self)
    try container.encode(tripNumber, forKey: .tripNumber)
    try container.encode(passengers, forKey: .passengers)
}

NSManagedObject classes adopting Codable are very comfortable for pre-populating the database from JSON data or making JSON backups.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to Vigges Developer Community for programmer and developer-Open, Learning and Share
...