Reputation: 14390
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
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