从 JSON + Swift 或 ObjC 检索数据时如何处理 CoreData 中的关系

Posted

技术标签:

【中文标题】从 JSON + Swift 或 ObjC 检索数据时如何处理 CoreData 中的关系【英文标题】:How handling relationships in CoreData while retrieving data from JSON + Swift Or ObjC 【发布时间】:2014-12-09 09:52:25 【问题描述】:

我实际上想在解析 Json 数据并创建子对象、保存和管理关系时处理关系。

我使用 findOrCreat 函数来验证我的对象是否已经存在,如果它存在,我会从 JSON 数据更新,如果不存在,我创建对象。当我使用 NSAsynchnonusFetchRequest 时,我不知道如何处理这些关系。另外,关系必须在父对象之前创建,所以当我在异步调用中创建父对象时,如何管理子对象和关系的创建?

在这里你可以找到我的 findOrCreat 函数:

// Asynchronous fetch
    let asyncFetch = NSAsynchronousFetchRequest(fetchRequest: fetchRequest) 
        (result:NSAsynchronousFetchResult!)-> Void in
        if result.finalResult!.count <= 0 
            var eventToSave:Events!;
            eventToSave = NSEntityDescription.insertNewObjectForEntityForName(Entities.Event.rawValue, inManagedObjectContext: self.cdhUser.backgroundContext!) as Events;
            eventToSave.setValue(eventId, forKey: "id");
            eventToSave.setValue((dictionary.objectForKey("title") as NSString), forKey: "title");
            eventToSave.setValue((dictionary.objectForKey("exclusive") as Bool), forKey: "isExclusive");
            eventToSave.setValue(0, forKey: "latitude");
            eventToSave.setValue(0, forKey: "longitude");
            eventToSave.setValue("", forKey: "details");
            eventToSave.setValue((dictionary.objectForKey("summary") as NSString), forKey: "summary");
            eventToSave.setValue((NSDate(timeIntervalSince1970: dictionary.objectForKey("date") as Double)), forKey: "date");
            eventToSave.setValue(NSDate(), forKey: "validFrom");
            eventToSave.setValue(NSDate(), forKey: "validTo");

            // Get url of image
            var pictureUrl:NSString!;
            if let pictureDictionary:NSDictionary = dictionary.objectForKey("main_media") as? NSDictionary 
                if let endUrlString:NSString = pictureDictionary.objectForKey("url") as? NSString 
                    pictureUrl = endUrlString;
                
            
            eventToSave.setValue((pictureUrl != nil ? pictureUrl : ""), forKey: "picture"); // Default Image Url

            self.cdhUser.saveContext(self.cdhUser.backgroundContext!);
        
        else if result.finalResult!.count > 0 
            var eventToUpdate = result.finalResult?.first as Events;
            eventToUpdate.setValue((dictionary.objectForKey("title") as NSString), forKey: "title");
            eventToUpdate.setValue((dictionary.objectForKey("exclusive") as Bool), forKey: "isExclusive");
            eventToUpdate.setValue(0, forKey: "longitude");
            eventToUpdate.setValue(0, forKey: "latitude");
            eventToUpdate.setValue("", forKey: "details");
            eventToUpdate.setValue((dictionary.objectForKey("summary") as NSString), forKey: "summary");
            eventToUpdate.setValue((NSDate(timeIntervalSince1970: dictionary.objectForKey("date") as Double)), forKey: "date");
            eventToUpdate.setValue((NSDate()), forKey: "validTo");
            eventToUpdate.setValue((NSDate()), forKey: "validFrom");

            // Get url of image
            var pictureUrl:NSString!;
            if let pictureDictionary:NSDictionary = dictionary.objectForKey("main_media") as? NSDictionary 
                if let endUrlString:NSString = pictureDictionary.objectForKey("url") as? NSString 
                    pictureUrl = endUrlString;
                
            
            eventToUpdate.picture = pictureUrl;
            println(eventToUpdate);
            self.cdhUser.saveContext(self.cdhUser.backgroundContext!);
            NSLog("Update is done!");
        
    
    self.cdhUser.backgroundContext!.performBlock 
        var result = self.cdhUser.backgroundContext!.executeRequest(asyncFetch, error: &error) as NSAsynchronousFetchResult;
    

这是我的 JSON 示例:


   "id": 1,
   "title": "Inauguration",
   "summary": "Evenement",
   "main_media": 
       "url": "c75b931abb131e9d091882c3638aca9fe0ecdee6.jpeg",
       "name": "99.JPG",
       "type": 2,
       "created_at": 1415377363
   ,
   "date": 1412174799,
   "duration": 6483600,
   "exclusive": true,
   "geo_location": [],
   "open": true,
   "description": "Evenement",
   "interested": true,
   "medias": [
       "url": "1c3f251b7bccd3bd4337852538fe7ba0accefa77.jpeg",
       "name": "b90mq.jpg",
       "type": 2,
       "created_at": 1415375677,
       "main_media": false
   , 
       "url": "c75b931abb131e9d091882c3638aca9fe0ecdee6.jpeg",
       "name": "woodstock-99.JPG",
       "type": 2,
       "created_at": 1415377363,
       "main_media": true
   ]

那么,如何在创建事件对象时创建媒体对象? 我什么时候可以调用 findOrCreate 函数来创建 Medias 对象?以及如何管理关系?

非常感谢

【问题讨论】:

【参考方案1】:

您应该在 xcdatamodeld 中添加从事件到媒体的一对多关系。

let manyRelation = eventToSave.valueForKeyPath("medias") as NSMutableSet
for dict : NSDictionary in dictionary.objectForKey("main_media") as? [NSDictionary] 
    let media : Media = Media()
    media.url = dict.objectForKey("url")
    media.name = dict.objectForKey("name")
    ....
    manyRelation.addObject(media)

此代码需要在创建根对象后保存上下文前添加

【讨论】:

非常感谢。只是一件事,我想检查一下这个媒体是否已经存在!?为此,我必须为 Medias 调用 findOrCreate 函数。你怎么看? 有两种解决方案:1)您可以找到并更新创建的对象 2)您可以删除所有现有对象并重新创建它们。在您的情况下,第二种解决方案比第一种更简单。 非常感谢,我会做的。 我得到:由于未捕获的异常 'NSInvalidArgumentException' 导致应用程序终止,原因:'-[Media setPath:]: unrecognized selector sent to instance 0x19b676e0' 我认为这是因为没有创建对象“媒体”在 CoreData... 我们没有 setEntitiyDescription(Media...) !你有什么想法 ?!感谢您的帮助 是的,您应该使用 insertNewObjectForEntityForName。 (您可以在 Media 的 init 方法中添加它)您应该在 xcdatamodeld 中添加从事件到媒体的一对多关系。 - 这意味着您需要在 xcdatamodeld 中创建媒体实体。

以上是关于从 JSON + Swift 或 ObjC 检索数据时如何处理 CoreData 中的关系的主要内容,如果未能解决你的问题,请参考以下文章

如何从 JSON 对象 Swift 4 中检索值

在 Swift 中使用带有 UnsafeMutableRawPointer 或 UnsafeMutablePointer 参数的 ObjC 函数?

在 Swift 中解析 JSON API [关闭]

从 Objc 超类继承的 Swift 子类中未调用 viewDidLoad

如何从 Swift 3 上的响应字符串中检索标题字段?

如何从 swift 代码中获得有用的 objc 枚举打印输出?