2017-10-29 113 views
1

我試圖編輯/插入CoreData對象,我在做什麼是這樣的:Xcode DispatchQueue.main.async內部或外部大循環?

DispatchQueue.main.async { 
    for track in allTracks 
    { 
    if let i = allObjects.index(where: { $0.sid == ddTools().md5("\(track.song_name)\(track.artist_name)") }) 
    { 
     self.log("[NEW][\(i)] Already in DB : \(track.song_name)") 
    }else 
    { 
     self.insert_track(track) 
    } 
    } 
} 

,但它仍然阻塞UI,如果陣列有超過500多個對象,它是安全的,如果我這樣做呢?

for track in allTracks 
    { 
    DispatchQueue.main.async { 
     if let i = allObjects.index(where: { $0.sid == ddTools().md5("\(track.song_name)\(track.artist_name)") }) 
     { 
      self.log("[NEW][\(i)] Already in DB : \(track.song_name)") 
     }else 
     { 
      self.insert_track(track) 
     } 
    } 
    } 

我可以在循環的CoreData對象內使用DispatchQueue.main.async!排尿阻塞UI

一些建議後,我也有功能更新,這

func insert_or_update_songs(tracks:[DTO_SONG],onComplete:(()->())!) 
{ 

    let allTasksGroup  = DispatchGroup() 
    var totalFinished:Int = 0 


    for track in tracks 
    { 
     DispatchQueue.main.async 
     { 
      allTasksGroup.enter() 

      //Fetch if Exists 
      let context    = (UIApplication.shared.delegate as! AppDelegate).managedObjectContext 
      let songHash   = ddTools().md5("\(track.song_name)\(track.artist_name)") 
      let request    = NSFetchRequest<NSFetchRequestResult>(entityName: "Song_Entity") 
       request.predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [NSPredicate(format:"sid = %@", songHash), 
                         NSPredicate(format:"sid != %@", "")]) 

      do{ 

        if try context.count(for:request) > 0 
        { 
        //Update the Track 
        if let _tracks:[Song_Entity] = try context.fetch(request) as? [Song_Entity] 
        { 
         self.update_track(track, _tracks[0]) 
        } 

        }else 
        //Insert as new track 
        { 
        self.insert_track(track,context :context) 
        } 

       if context.hasChanges 
       { 
        do { 
          try context.save() 
          self.log(" New Changes has been Saved.") 
         } catch let error as NSError { self.log(" Could not save. \(error), \(error.userInfo)") } 
       } 

       totalFinished += 1 
       print(" \(totalFinished)/\(tracks.count)") 
       allTasksGroup.leave() 

      }catch let error as NSError { self.log("[HASH] Error while checking Track if in DB: \(error), \(error.userInfo)") } 

     } 
    } 

    //When all done 
    allTasksGroup.notify(queue: .main) { 
     self.log("[INSERT OR UPDATE BATCH] Total Finished : \(totalFinished)/\(tracks.count) ") 

     if totalFinished == tracks.count 
     { 
      if onComplete != nil 
      { 
       onComplete() 
      } 
     } 
    } 

回答

0

的代碼片段兩者都是錯誤的。 allTracks是連接到特定上下文的核心數據對象 - 這不是線程安全的。您無法從主線程訪問這些對象 - 無論是讀取還是寫入。您可以保存信息 - 然後將其傳遞給主線程。

如果你在主線程上使用fetch,你不應該首先使用後臺線程。在主線程上執行取指令會更好。

+0

allTracks不coredata對象,allObjects是。所以你的意思是我必須循環所有曲目,並在循環內使coredata獲取並保存每個曲目? – Jack

+0

那麼你無法訪問主線程上的所有對象。但它是一樣的想法。我沒有看到您的代碼中的任何地方正在寫入核心數據。 –

+0

我已經更新了問題和函數後,你的意見,與coredata – Jack

1

對於UI的兩個CoreData胎面的安全性和反應能力,我會跟在insert點做線程切換去:

for track in allTracks 
{ 
    if let i = allObjects.index(where: { $0.sid == ddTools().md5("\(track.song_name)\(track.artist_name)") }) { 
     self.log("[NEW][\(i)] Already in DB : \(track.song_name)") 
    } else { 
     DispatchQueue.main.async { 
      self.insert_track(track) 
     } 
    } 
} 
+0

self.insert_track已經在DispatchQueue.main.async表單 – Jack

+0

裏面是的,但是這個從右邊的線程獲取CoreData的項目,然後在主線程中使用。 –

+0

,我應該在循環之後使用context.save嗎?或每個循環內部 – Jack

相關問題