2017-10-29 1 views
1

Ich versuche, Coredata-Objekte zu bearbeiten/einfügen, was ich tue, ist dies:Xcode DispatchQueue.main.async innerhalb oder außerhalb der großen Schleife?

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

aber seine Sperr noch die Benutzeroberfläche, wenn Array 500+ Objekt über, ist es sicher, wenn ich dies tun?

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

kann ich mit DispatchQueue.main.async innerhalb Looping von Coredata-Objekte!

nach einigen Tipps i aktualisiert haben die Funktion dieser

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() 
      } 
     } 
    } 

Antwort

0

Beide Code-Schnipsel auf void UI blockiert sind falsch. allTracks sind Core-Datenobjekte, die an einen bestimmten Kontext gebunden sind - was nicht Thread-sicher ist. Sie können auf diese Objekte - weder Lesen noch Schreiben - vom Hauptthread aus zugreifen. Sie können die Informationen speichern und dann an den Hauptthread übergeben.

Wenn Sie das Fetch für den Hauptthread verwenden, sollten Sie keinen Hintergrundthread verwenden. Es ist besser, einfach den Haupt-Thread abzurufen.

+0

allTracks ist nicht Coredata-Objekte, allObjects ist. also ich meine, ich muss allTracks looping und innerhalb der loop machen coredata holen und speichern für jeden track? – Jack

+0

dann können Sie nicht auf alleObjekte im Hauptthread zugreifen. aber es ist die gleiche Idee. Ich sehe nirgends in Ihrem Code, dass Sie in Kerndaten schreiben. –

+0

Ich habe die Frage und die Funktion nach ur-Beratung aktualisiert, mit Coredata – Jack

1

Sowohl für die Coredata Trittsicherheit und Reaktionsfähigkeit Ihrer UI, würde ich mit dabei den Faden Schalter am insert Punkt gehen:

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 bereits in DispatchQueue.main.async Formular innerhalb – Jack

+0

Ja, aber dieser bekommt das Element aus CoreData in den richtigen Thread und dann im Haupt-Thread verwendet . –

+0

und sollte ich context.save nach der Schleife verwenden? oder in jeder Schleife – Jack

Verwandte Themen