我正在关注如何使用RKMapperOperation直接映射传入的JSON数据的一些建议帖子。我的实体对象是在数据存储中创建的,但没有正确的关系。有趣的是,如果我在映射了传入的JSON(通过websockets)后直接使用Core Data方法创建了一个对象,那么该操作似乎会“充实”我在不正确实体中的关系。
总结顺序:
这是JSON数据:
{
"checkin": {
"session_id": 1,
"attendee_id": 70,
"source": "list",
"created_at": "2015-03-26 11:53:08",
"cache_id": "9234d700852df5c7402b87adf6ecfc19",
"checkout": "0",
"updated_at": "2015-03-27 03:53:09",
"id": 359
}
}
这是我的映射函数
func mapEntityFromJson(JSONString: String, key: String, mapping: RKEntityMapping!) -> NSManagedObject? {
let MIMEType = "application/json"
var error: NSError? = nil
let data = JSONString.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
let jsonDictionary: NSDictionary = NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers, error: &error) as NSDictionary
let parsedData: AnyObject! = RKMIMETypeSerialization.objectFromData(data, MIMEType: MIMEType, error: &error)
if (parsedData == nil && error != nil) {
// Parser error...
return nil
}
let mappingsDictionary = [ key: mapping ]
let mappingDS = RKManagedObjectMappingOperationDataSource(managedObjectContext: self.objectStore.persistentStoreManagedObjectContext, cache: self.objectStore.managedObjectCache)
let mapper = RKMapperOperation(representation: parsedData, mappingsDictionary: mappingsDictionary)
mapper.mappingOperationDataSource = mappingDS
var mappingError: NSError? = nil
let isMapped = mapper.execute(&mappingError)
if (isMapped && mappingError == nil) {
// Trying to save twice per some other example
self.objectStore.persistentStoreManagedObjectContext.save(&error)
self.objectStore.persistentStoreManagedObjectContext.saveToPersistentStore(&error)
let result = mapper.mappingResult.firstObject() as NSManagedObject
return result
}
return nil
}
这是我传递给这个函数的关系映射:
func checkinMapping() -> RKEntityMapping {
let checkinMapping = RKEntityMapping(forEntityForName: "Checkin", inManagedObjectStore: objectStore)
let checkinDictionary = ["source": "source", "checkout": "checkout", "cache_id": "cacheId", "attendee_id": "attendeeId", "session_id": "sessionId"]
checkinMapping.addAttributeMappingsFromDictionary(baseRecordDictionary)
checkinMapping.addAttributeMappingsFromDictionary(checkinDictionary)
checkinMapping.addConnectionForRelationship("attendee", connectedBy: ["attendeeId": "id"])
checkinMapping.addConnectionForRelationship("session", connectedBy: ["sessionId": "id"])
checkinMapping.identificationAttributes = ["cacheId"]
checkinMapping.setDefaultValueForMissingAttributes = true
return checkinMapping
}
以下是通知websocket订阅时函数的调用方式:
let jsonString = "<the JSON data per above>"
let mappingResult = self.mapEntityFromJson(jsonString, key: "checkin", mapping: self.checkinMapping())
attendee_id
和session_id
值应该与Attendee
和Session
实体建立关系,但是当我查看基础Core数据的sqlite数据时,关系列是即使传入的attendeeId
和sessionId
字段已映射,也会显示空白一旦我在本地进行另一次保存,那么这些关系列就会被映射。
有什么想法吗?
编辑: 我应该补充一点,当从一个完整的RestKit调用(如.getObject)或.postObject的结果映射checkin时,映射可以正常工作。只有在我在这里的手动映射中,它似乎才会分崩离析。
答案 0 :(得分:0)
这是最终的解决方案,其中涉及@wain的大量帮助以及另一篇关于需要使operationQueue等待所有操作完成或者映射过程尚未完成映射关系的帖子的关键点。所以我的NSManagedObject返回时没有连接关系。正确并发和保存数据的私有子上下文与等待问题的组合解决了问题。这是最终的映射代码:
func mapEntityFromJson(JSONString: String, key: String, mapping: RKEntityMapping!) -> NSManagedObject? {
let MIMEType = "application/json"
var error: NSError? = nil
let data = JSONString.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
let jsonDictionary: NSDictionary = NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers, error: &error) as NSDictionary
let parsedData: AnyObject! = RKMIMETypeSerialization.objectFromData(data, MIMEType: MIMEType, error: &error)
if (parsedData == nil && error != nil) {
// Parser error...
return nil
}
let mapperContext = self.objectStore.newChildManagedObjectContextWithConcurrencyType(NSManagedObjectContextConcurrencyType.PrivateQueueConcurrencyType, tracksChanges: true)
let mappingsDictionary = [ key: mapping ]
let mappingDS = RKManagedObjectMappingOperationDataSource(managedObjectContext: mapperContext, cache: self.objectStore.managedObjectCache)
var mappingResult: RKMappingResult? = nil
var result: NSManagedObject? = nil
let mapper = RKMapperOperation(representation: parsedData, mappingsDictionary: mappingsDictionary)
mappingDS.operationQueue = self.operationQueue
mappingDS.parentOperation = mapper
mapper.mappingOperationDataSource = mappingDS
var mappingError: NSError? = nil
let isMapped = mapper.execute(&mappingError)
// Necessary to wait for relationships to map.
if self.operationQueue!.operationCount > 0 {
self.operationQueue!.waitUntilAllOperationsAreFinished()
}
if (isMapped && mappingError == nil) {
mapperContext.saveToPersistentStore(&error)
mappingResult = mapper.mappingResult
}
if mappingResult != nil {
result = mappingResult!.firstObject() as? NSManagedObject
}
return result
}
现在我们将它留在内存缓存中,并且看不到其他人报告的重复项。