Swift 3, Swift 4 ve ötesinde nasıl_satchc, dispatch_async, dispatch_after, vb. Gönderirim?


243

Swift 2.x (hatta 1.x) projelerinde şöyle görünen bir sürü kod var:

// Move to a background thread to do some long running work
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
    let image = self.loadOrGenerateAnImage()
    // Bounce back to the main thread to update the UI
    dispatch_async(dispatch_get_main_queue()) {
        self.imageView.image = image
    }
}

Veya yürütmeyi geciktirmek için bunun gibi şeyler:

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(0.5 * Double(NSEC_PER_SEC))), dispatch_get_main_queue()) {
    print("test")
}

Ya da Grand Central Dispatch API'sının diğer her türlü kullanımından ...

Artık Swift 3 için projemi Xcode 8'de (beta) açtığım için her türlü hatayı alıyorum. Bazıları kodumu düzeltmeyi teklif ediyor, ancak tüm düzeltmeler çalışma kodu üretmiyor. Bununla ilgili ne yapacağım?


Burada
cevaplandı

Yanıtlar:


343

Başından beri Swift, ObjC ve C'yi daha Swifty yapmak için bazı olanaklar sağladı ve her versiyona daha fazlasını ekledi. Şimdi, Swift 3'te, yeni "üye olarak içe aktar" özelliği, bir sınıf gibi çalışan bir veri türüne ve onunla çalışmak için bir grup küresel işleve sahip olan belirli C API stilleriyle çerçevelere izin verir - daha çok Swift-yerli API'leri gibi davranır. Veri türleri Swift sınıfları olarak içe aktarılır, ilgili küresel işlevleri bu sınıflar üzerinde yöntem ve özellikler olarak içe aktarılır ve sabitler gibi bazı ilgili şeyler uygun olduğunda alt türler haline gelebilir.

Xcode 8 / Swift 3 beta sürümünde Apple, Dispatch çerçevesini çok daha Swifty yapmak için bu özelliği (birkaç diğerleri ile birlikte) uyguladı. (Ve Core Graphics de.) Swift açık kaynak çabalarını izliyorsanız, bu bir haber değil , ama şimdi Xcode'un ilk kez bir parçası.

Herhangi bir projeyi Swift 3'e taşımak için ilk adımınız Xcode 8'de açmak ve menüde Düzen> Dönüştür> Geçerli Swift Sözdizimine ... 'i seçmek olmalıdır . Bu, yeniden adlandırılan tüm API'lar ve diğer değişiklikler için gereken değişiklikleri (inceleme ve onayınızla birlikte) bir kerede uygulayacaktır. (Çoğu zaman, bir kod satırı bu değişikliklerin birden fazlasından aynı anda etkilenir, bu nedenle hata düzeltmesine tek tek yanıt vermek her şeyi doğru işlemeyebilir.)

Sonuç olarak, işi arka plana ve geriye sıçramak için ortak desen şu şekilde görünür:

// Move to a background thread to do some long running work
DispatchQueue.global(qos: .userInitiated).async {
    let image = self.loadOrGenerateAnImage()
    // Bounce back to the main thread to update the UI
    DispatchQueue.main.async {
        self.imageView.image = image
    }
}

.userInitiatedEski DISPATCH_QUEUE_PRIORITYsabitlerden biri yerine kullandığımızı unutmayın . Hizmet Kalitesi (QoS) belirleyicileri, OS X 10.10 / iOS 8.0'da tanıtıldı ve sistemin çalışmaya öncelik vermesi ve eski öncelik belirteçlerini kaldırması için daha net bir yol sağladı. Ayrıntılar için Apple'ın arka plan çalışması ve enerji verimliliği dokümanlarına bakın.

Bu arada, işi düzenlemek için kendi kuyruklarınızı tutuyorsanız, bir tane almanın yolu şu şekilde görünür (bunun DispatchQueueAttributesbir olduğuna dikkat edin OptionSet, böylece seçenekleri birleştirmek için koleksiyon stili değişmezleri kullanırsınız):

class Foo { 
    let queue = DispatchQueue(label: "com.example.my-serial-queue",
                           attributes: [.serial, .qosUtility])
    func doStuff() {
        queue.async {
            print("Hello World")
        }
    }
}

Daha dispatch_aftersonra çalışmak için mi kullanıyorsunuz? Bu da kuyruklarda bir yöntemdir ve DispatchTimeçeşitli sayısal türler için işleçlere sahip bir a alır , böylece tam veya kesirli saniye ekleyebilirsiniz:

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

Arayüzünü Xcode 8'de açarak yeni Dispatch API'sinde yolunuzu bulabilirsiniz - Dispatch modülünü bulmak için Hızlı Aç'ı kullanın veya DispatchQueueSwift projenize / oyun alanınıza bir sembol (gibi ) koyun ve komuta tıklayıp brouse yapın oradan modül. (Swift Dağıtım API'sını Apple'ın gösterişli yeni API Referansı web sitesinde ve X-kodu doküman görüntüleyicide bulabilirsiniz, ancak C sürümündeki doküman içeriği henüz buraya taşınmamış gibi görünüyor.)

Daha fazla ipucu için Taşıma Kılavuzu'na bakın .


3
Xcode 8 Beta 6'ya gelince, .serial özniteliği gitti ve varsayılan davranış - forums.developer.apple.com/message/159457#159457
hyouuu

6
Bu, XCode 8.1'den beri bir güncellemeye ihtiyaç duyuyor .. öznitelik etiketi kayboldu ve onun yerine 'DispatchQueue.global (qos: .background) .async'
Mike M

2
Harika cevap. Gerçekten kafamı bulamamda bana yardımcı oldu.
Mohsin Khubaib Ahmed

Bunun qos:yerine kullanmak zorunda kaldımattributes:
İslam S.

O gerekmiyor myQueue.async {içinde class Fooörneğin?
vacawama

142

Xcode 8'de beta 4 çalışmıyor ...

kullanın:

DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
    print("Are we there yet?")
}

eşzamansız iki yol için:

DispatchQueue.main.async {
    print("Async1")
}

DispatchQueue.main.async( execute: {
    print("Async2")
})

Yani kullanıcı arayüzünü engellemiyor mu?
user25

72

Bu seferki için iyi bir örnektir Swift 4hakkında async:

DispatchQueue.global(qos: .background).async {
    // Background Thread
    DispatchQueue.main.async {
        // Run UI Updates or call completion block
    }
}

hi DispatchQueue.main.async {// Kullanıcı Arabirimi Güncellemelerini Çalıştır} arka plan iş parçacığından önce yürütülüyor
Uma Achanta

coroutines ile benzer
user25

40

Xcode 8'de şunları kullanın:

DispatchQueue.global(qos: .userInitiated).async { }

26

Swift 5.2, 4 ve üstü

Ana ve Arka Plan Kuyrukları

let main = DispatchQueue.main
let background = DispatchQueue.global()
let helper = DispatchQueue(label: "another_thread") 

Zaman uyumsuz ve senkronize iş parçacıkları ile çalışma !

 background.async { //async tasks here } 
 background.sync { //sync tasks here } 

Zaman uyumsuz iş parçacıkları ana iş parçacığı ile birlikte çalışır.

Senkronizasyon iş parçacıkları yürütülürken ana iş parçacığını engeller.


1
Ve ana iş parçacığı (UI) engellemeden Sync iş parçacığı nasıl kullanılır? Arka planda bir dizi şey yürütmek istiyorum - ama bu şeyler senkronize bir şekilde birbiri ardına yürütülmelidir. Bu süre zarfında kullanıcı arayüzü duyarlı kalmalıdır .... Bunu nasıl yapardınız?
iKK

NSOperationQueue kullanın. Hangi her görev bir NSOperation temsil. Bakınız stackoverflow.com/a/19746890/5215474
Saranjith

12

Swift 4.1 ve 5. Kodlarımızda birçok yerde kuyruk kullanıyoruz. Böylece, tüm kuyruklarla Threads sınıfı oluşturdum. Threads sınıfını kullanmak istemiyorsanız, sınıf yöntemlerinden istediğiniz kuyruk kodunu kopyalayabilirsiniz.

class Threads {

  static let concurrentQueue = DispatchQueue(label: "AppNameConcurrentQueue", attributes: .concurrent)
  static let serialQueue = DispatchQueue(label: "AppNameSerialQueue")

  // Main Queue
  class func performTaskInMainQueue(task: @escaping ()->()) {
    DispatchQueue.main.async {
      task()
    }
  }

  // Background Queue
  class func performTaskInBackground(task:@escaping () throws -> ()) {
    DispatchQueue.global(qos: .background).async {
      do {
        try task()
      } catch let error as NSError {
        print("error in background thread:\(error.localizedDescription)")
      }
    }
  }

  // Concurrent Queue
  class func perfromTaskInConcurrentQueue(task:@escaping () throws -> ()) {
    concurrentQueue.async {
      do {
        try task()
      } catch let error as NSError {
        print("error in Concurrent Queue:\(error.localizedDescription)")
      }
    }
  }

  // Serial Queue
  class func perfromTaskInSerialQueue(task:@escaping () throws -> ()) {
    serialQueue.async {
      do {
        try task()
      } catch let error as NSError {
        print("error in Serial Queue:\(error.localizedDescription)")
      }
    }
  }

  // Perform task afterDelay
  class func performTaskAfterDealy(_ timeInteval: TimeInterval, _ task:@escaping () -> ()) {
    DispatchQueue.main.asyncAfter(deadline: (.now() + timeInteval)) {
      task()
    }
  }
}

Ana kuyruk kullanımını gösteren örnek.

override func viewDidLoad() {
    super.viewDidLoad()
     Threads.performTaskInMainQueue {
        //Update UI
    }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.