[英]Xcode DispatchQueue.main.async inside or outside large loop?
我正在尝试编辑/插入 CoreData 对象,我正在做的是:
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)
}
}
}
但是如果 Array 有超过 500 个以上的对象,它仍然会阻塞 UI,如果我这样做是否安全?
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()
}
}
}
对于您的 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)
}
}
}
两段代码都是错误的。 allTracks
是附加到特定上下文的核心数据对象 - 这不是线程安全的。 您不能从主线程访问这些对象——无论是读还是写。 您可以保存信息 - 然后将其传递给主线程。
如果您在主线程上执行 fetch 操作,则首先不应使用后台线程。 最好只在主线程上进行提取。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.