Kodr.F
Kodr.F

Reputation: 14390

Xcode Core Data UI locked while working?

I am trying to save User Library songs in my application Core data to sync them with my server. My issue is: when user have 500+ tracks the UI is being locked until the Core Data loop check is finished! Is there any way to avoid UI lock while CoreData is working on big loop? Such as background none-UI thread like aSyncTask in Android.

Here is Code where the loop is located.

   /**
     - Insert or Update tracks if exists in Database
     - This function will "Not" run Sync with server once its done
     */
    func insert_or_update_songs(tracks:[DTO_SONG],onComplete:(()->())!)
    {

        self.managedContext = APP_DELEGATE.managedObjectContext

        var allTracks:[DTO_SONG]            = tracks
        var track_with_ddID:[DTO_SONG]  = []
        var sid:[String]                    = []
        var dd_song_ids:[Int32]         = []
        var allObjects:[Song_Entity]        = []

        //Get Tracks ID's to see if they already in DB
        if allTracks.count > 0
        {
            for track in tracks
            {
               //if Track has dd id ?
                if track.dd_song_id > 0
                {
                  track_with_ddID.append(track)
                  dd_song_ids.append(Int32(track.dd_song_id))
                }else
               //Match by Hash
                {
                  sid.append( ddTools().md5("\(track.song_name)\(track.artist_name)") )
                }
            }


            //[UPDATE] by HASH Now Fetch All found in DB
            if sid.count > 0
            {
                self.log("[HASH] Match by HASH : \(sid.count)")

                let request             = NSFetchRequest<NSFetchRequestResult>(entityName: "Song_Entity")
                    request.predicate   = NSCompoundPredicate(andPredicateWithSubpredicates: [NSPredicate(format:"sid IN %@", sid)])

                do{

                    if  try self.managedContext.count(for:request) > 0
                    {
                       if let _tracks:[Song_Entity] = try self.managedContext.fetch(request) as? [Song_Entity]
                       {

                        allObjects += _tracks
//                         for track in _tracks
//                         {
//                            //Remove from Array
//                            if let i = allTracks.index(where: { ddTools().md5("\($0.song_name)\($0.artist_name)") == track.sid })
//                            {
//                                //Update track info
//                               //self.update_track(allTracks[i],track)
//                               //Now remove
//                               self.log("[HASH] Removed Already exists : \(allTracks[i].song_name)")
//                               allTracks.remove(at: i)
//                            }
//                         }
                       }
                    }

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


            //[UPDATE] by ID Now Fetch All found in DB
            if dd_song_ids.count > 0
            {
                self.log("[ID] Match by dd ID : \(sid.count)")

                let request             = NSFetchRequest<NSFetchRequestResult>(entityName: "Song_Entity")
                    request.predicate   = NSCompoundPredicate(andPredicateWithSubpredicates: [NSPredicate(format:"dd_song_id IN %@", dd_song_ids)])

                do{

                    if  try self.managedContext.count(for:request) > 0
                    {
                        if let _tracks:[Song_Entity] = try self.managedContext.fetch(request) as? [Song_Entity]
                        {
                             allObjects += _tracks

//                            for track in _tracks
//                            {
//                                //Remove from Array
//                                if let i = allTracks.index(where: { $0.dd_song_id == track.dd_song_id })
//                                {
//                                    //Update track info
//                                    //self.update_track(allTracks[i],track)
//                                    //Now Remove
//                                    self.log("[ID] Removed Already exists : \(allTracks[i].song_name)")
//                                    allTracks.remove(at: i)
//                                }
//                            }
                        }
                    }

                }catch let error as NSError {  self.log("[ID] Error while checking Tracks : \(error), \(error.userInfo)") }
            }
        }

         self.log("[NEW] Tracks to check and insert  \(allTracks.count) , check with \(allObjects.count) Tracks ")


          for track in allTracks
          {
            //if not in there this insert it
            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)
            }
          }

          dd_song_ids.removeAll()
          sid.removeAll()
          track_with_ddID.removeAll()
          allTracks.removeAll()
          allObjects.removeAll()

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

          //Sync with Server
          if onComplete != nil
          {
            onComplete()
          }
     } 

Upvotes: 1

Views: 108

Answers (1)

BuLB JoBs
BuLB JoBs

Reputation: 861

You go with dispatch_async and block in iOS:

DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { 
    // in half a second...
    print("Are we there yet?") // add coreData loop
}

Or Get used like main queue asynchronously

DispatchQueue.main.async
{
   /*Write your thread code here*/
}

Upvotes: 1

Related Questions