【问题标题】:Creating and assigning a new NSManagedObject to a new NSManagedObject *sometimes* fails创建新的 NSManagedObject 并将其分配给新的 NSManagedObject *有时*会失败
【发布时间】:2016-02-11 22:55:42
【问题描述】:

我正在创建一个名为“translation”的新 NSManagedObject。在翻译中,我需要创建两个额外的 NSManagedObjects,称为“短语”。有时其中一个短语分配会引发错误,但是当我检查这些值时,它们看起来都像是被创建得很好。什么给了???

创建翻译对象:

func getOrCreateTranslation(package: Package?, data: NSDictionary) -> Translation {
        let translationId = data["id"] as! NSNumber

        if let translation = self.getTranslation(translationId) {

            return translation

        } else {

            let context = LocalDataStorage().context
            let translation = NSEntityDescription.insertNewObjectForEntityForName("Translation", inManagedObjectContext: context) as! Translation
            translation.id = translationId

            let fromPhrase = data["from_phrase"]! as! NSDictionary
            let toPhrase = data["to_phrase"]! as! NSDictionary


            let pm = PhraseManager()

            //*******
            // *SOMETIMES* ONE OF THESE LINES FAIL WITH BAD_EXC_ACCESS code=1
            translation.fromPhrase = pm.getOrCreatePhrase(fromPhrase)
            translation.toPhrase = pm.getOrCreatePhrase(toPhrase)
            //******

            if package != nil {
                package!.addTranslationObject(translation)
            }

            return translation

        }

    }

创建短语对象:

func getOrCreatePhrase(data: NSDictionary) -> Phrase {
        // check if phrase exists
        let phraseId = data["id"] as! NSNumber

        if let phrase = self.getPhrase(phraseId) {

            return phrase

        } else {

            let context = localDataStorage.context
            let lm = LanguageManager()
            let phrase = NSEntityDescription.insertNewObjectForEntityForName("Phrase", inManagedObjectContext: context) as! Phrase

            phrase.id = phraseId
            phrase.text = data["text"] as! String
            phrase.audioUrl = data["audio_url"] as? String

            let code = data["language"]!["language_code"] as! String
            phrase.language = lm.getLanguageFromCode(code)

            return phrase

        }



    }

调用 API:

func getPackageTranslations(package: Package, completion: ([Translation])-> Void) {

    let currentLanguage: Language = LanguageManager().getCurrentLanguage()!

    let urlString = baseAPIString + "/groups/\(package.id!)/translations/?language_code=\(currentLanguage.code)"


    let session = NSURLSession.sharedSession()
    let serachUrl = NSURL(string: urlString)


    let task = session.dataTaskWithURL(serachUrl!) {
        (data, response, error) -> Void in

        if error != nil {
            print(error?.localizedDescription)
        } else {



            let jsonData: NSDictionary!
            do {
                jsonData = try NSJSONSerialization.JSONObjectWithData(data!, options: .MutableContainers) as! NSDictionary
            } catch _ {
                jsonData = NSDictionary()
            }

            let groupTranslationsData = jsonData["group_translations"] as! [NSDictionary]



            var translations = [Translation]()
            let context = LocalDataStorage().context

            for groupTranslation in groupTranslationsData {

                let translationData = groupTranslation["translation"] as! NSDictionary

                let translation = TranslationManager().getOrCreateTranslation(package, data: translationData)


                if translation.packages?.containsObject(package) == false {
                    //package.addTranslationObject(translation!)
                    //translation!.addPackageObject(package)
                }

                translations.append(translation)

            }


            do {
                try context.save()
            } catch {
                print("There was a problem saving translation ")
            }




            dispatch_async(dispatch_get_main_queue(), {
                completion(translations)
            })


        }

    }
    task.resume()

}

CoreData 上下文类:

    class LocalDataStorage {
    let appDelegate: AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
    let context: NSManagedObjectContext!

    init() {
        context = appDelegate.managedObjectContext
    }

}

【问题讨论】:

  • 你在哪个线程上运行,上下文是如何配置的?
  • 同意。很可能是由于此代码在创建 managedObjectContext 的不同线程上运行造成的。当你这样做时,它有时会起作用,有时会失败。
  • 感谢两位的回复。 @Wain,我在上面的描述中添加了另外两个涉及的功能,以及正在运行的线程的图片。我确实调用了 API,但对象和 context.save 发生在调度之前。

标签: swift core-data exc-bad-access


【解决方案1】:

当您创建一个 NSManagedObjectContext 时,该上下文应与其交互的并发模式,并且您在与初始化期间指定的并发模式不同的线程上对其执行操作。

NSURLSession.dataTaskWithURL 的完成块是在另一个线程上运行的,所以你必须调度到上下文创建中指定的线程类型才能成功地对其执行任何操作。

如果您的上下文的并发类型是大多数情况下使用的 MainQueueConcurrencyType,您必须在主队列上执行上下文保存方法。

dispatch_async(dispatch_get_main_queue()) {
  do {
     try context.save()
  } catch {
     print("There was a problem saving translation ")
  }
  completion(translations)
}

【讨论】:

  • 谢谢艾哈迈德!由于调度之前的其他步骤是同步的,我认为它们会在调度之前完全执行。在您的提示之后,我仍然遇到其他保存问题,最终将整个 JSON 解析和对象创建移动到调度块。现在就像一个魅力!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-08-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-28
  • 1970-01-01
  • 2017-03-12
相关资源
最近更新 更多