2017-10-29 213 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