2016-02-11 5 views
0

Я создаю новый объект NSManagedObject, называемый «перевод». В рамках перевода мне нужно создать два дополнительных NSManagedObjects, называемых фразой. Иногда одно из назначений фразы вызывает ошибку, но когда я проверяю значения, все они выглядят так, как будто они были созданы просто отлично. Что дает???Создание и назначение нового объекта NSManagedObject для нового NSManagedObject * иногда * сбой

error when adding a phrase to a translation

threads

Создание перевода объекта:

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 
    } 

} 
+0

Какой поток вы используете и как настроен контекст? – Wain

+1

Согласен. Вероятно, это может быть причиной этого кода, запущенного в другом потоке, к которому был создан файл managedObjectContext. Когда вы это делаете, он иногда работает и иногда терпит неудачу. – Michael

+0

Спасибо вам за ответы. @Wain, я добавил еще два задействованных функции и рисунок бегущих потоков в описание выше. Я * делаю * сделать вызов API, но объекты и context.save происходят до отправки. – Sean

ответ

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) 
} 
+0

Спасибо, Ахмед! Поскольку другие шаги перед отправкой были синхронными, я думал, что они будут полностью выполнены до отправки. После вашего совета у меня все еще были проблемы с другими сбережениями, и в итоге я переместил весь синтаксический анализ JSON и создание объекта в блок отправки. Сейчас работает как шарм! – Sean