Burada ve diğer SO sorularının yanıtlarında belirtildiği gibi, beginBackgroundTask
yalnızca uygulamanız arka plana geçeceği zaman kullanmak İSTEMEZSİNİZ; Tam tersine, bir arka plan görevi kullanmalısınız herhangi kimin tamamlama varsa uygulamanın bile sağlamak istiyoruz zaman alıcı operasyonu yapar arka gider.
Bu nedenle, kodunuzun arama beginBackgroundTask
ve arama için aynı standart kodun tekrarları ile sonuçlanması muhtemeldir.endBackgroundTask
tutarlı bir . Bu tekrarı önlemek için, ortak plakayı tek bir kapsüllenmiş varlığa paketlemek kesinlikle mantıklıdır.
Bunu yapmak için bazı mevcut cevapları seviyorum, ancak en iyi yolun bir Operasyon alt sınıfı kullanmak olduğunu düşünüyorum:
İşlemi herhangi bir OperationQueue üzerine sıraya koyabilir ve bu kuyruğu uygun gördüğünüz şekilde değiştirebilirsiniz. Örneğin, kuyruktaki mevcut işlemleri zamanından önce iptal etmekte özgürsünüz.
Yapacak birden fazla işiniz varsa, birden fazla arka plan görevi İşlemleri zincirleyebilirsiniz. İşlemler bağımlılıkları destekler.
İşlem Sırası bir arka plan sırası olabilir (ve olmalıdır); Operasyon nedeniyle böylece, görev içinde asenkron kod gerçekleştirme hakkında endişelenmeye gerek yoktur olan asenkron kodu. (Gerçekten de, bir İşlem içinde başka bir eşzamansız kod düzeyi yürütmenin bir anlamı yoktur , çünkü İşlem bu kod başlamadan önce biter. Bunu yapmanız gerekirse, başka bir İşlem kullanırsınız.)
İşte olası bir İşlem alt sınıfı:
class BackgroundTaskOperation: Operation {
var whatToDo : (() -> ())?
var cleanup : (() -> ())?
override func main() {
guard !self.isCancelled else { return }
guard let whatToDo = self.whatToDo else { return }
var bti : UIBackgroundTaskIdentifier = .invalid
bti = UIApplication.shared.beginBackgroundTask {
self.cleanup?()
self.cancel()
UIApplication.shared.endBackgroundTask(bti) // cancellation
}
guard bti != .invalid else { return }
whatToDo()
guard !self.isCancelled else { return }
UIApplication.shared.endBackgroundTask(bti) // completion
}
}
Bunun nasıl kullanılacağı açık olmalı, ancak değilse, küresel bir OperationQueue'muz olduğunu hayal edin:
let backgroundTaskQueue : OperationQueue = {
let q = OperationQueue()
q.maxConcurrentOperationCount = 1
return q
}()
Dolayısıyla, zaman alan tipik bir kod grubu için şunu söyleyebiliriz:
let task = BackgroundTaskOperation()
task.whatToDo = {
// do something here
}
backgroundTaskQueue.addOperation(task)
Zaman alan kod grubunuz aşamalara bölünebiliyorsa, göreviniz iptal edilirse erkenden vazgeçmek isteyebilirsiniz. Bu durumda, kapanıştan erken dönün. Kapanış içinde göreve referansınızın zayıf olması gerektiğini, aksi takdirde bir tutma döngüsü elde edeceğinizi unutmayın. İşte yapay bir örnek:
let task = BackgroundTaskOperation()
task.whatToDo = { [weak task] in
guard let task = task else {return}
for i in 1...10000 {
guard !task.isCancelled else {return}
for j in 1...150000 {
let k = i*j
}
}
}
backgroundTaskQueue.addOperation(task)
Arka plan görevinin zamanından önce iptal edilmesi durumunda yapmanız gereken temizlemeniz olması durumunda, isteğe bağlı bir cleanup
işleyici özelliği sağladım (önceki örneklerde kullanılmamıştır). Diğer bazı cevaplar bunu dahil etmediği için eleştirildi.