Làm cách nào để tôi gửi_s_sync, Clark_async, Clark_after, v.v. trong Swift 3, Swift 4 và hơn thế nữa?


243

Tôi có rất nhiều mã trong các dự án Swift 2.x (hoặc thậm chí 1.x) trông như thế này:

// 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
    }
}

Hoặc những thứ như thế này để trì hoãn thực hiện:

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

Hoặc bất kỳ loại sử dụng nào khác của API Grand Central Dispatch ...

Bây giờ tôi đã mở dự án của mình trong Xcode 8 (beta) cho Swift 3, tôi nhận được tất cả các loại lỗi. Một số trong số họ đề nghị sửa mã của tôi, nhưng không phải tất cả các bản sửa lỗi đều tạo ra mã làm việc. Tôi phải làm gì về điều này?


Đã trả lời tại đây: stackoverflow.com/questions/37805885/ trên
t1ser

Câu trả lời:


343

Ngay từ đầu, Swift đã cung cấp một số phương tiện để làm cho ObjC và C thêm Swifty, bổ sung thêm với mỗi phiên bản. Giờ đây, trong Swift 3, tính năng "nhập làm thành viên" mới cho phép các khung với các kiểu C API nhất định - nơi bạn có một kiểu dữ liệu hoạt động giống như một lớp và một loạt các hàm toàn cầu để hoạt động với nó - hành động giống như API gốc của Swift. Các kiểu dữ liệu nhập dưới dạng các lớp Swift, các hàm toàn cầu có liên quan của chúng nhập dưới dạng các phương thức và thuộc tính trên các lớp đó và một số thứ liên quan như các bộ hằng có thể trở thành các kiểu con khi thích hợp.

Trong Xcode 8 / Swift 3 beta, Apple đã áp dụng tính năng này (cùng với một vài tính năng khác) để làm cho khung công tác Swatch nhiều hơn Swifty. (Và Đồ họa lõi cũng vậy.) Nếu bạn đã theo dõi các nỗ lực nguồn mở Swift, đây không phải là tin tức , nhưng đây là lần đầu tiên nó là một phần của Xcode.

Bước đầu tiên của bạn khi chuyển bất kỳ dự án nào sang Swift 3 là mở nó trong Xcode 8 và chọn Chỉnh sửa> Chuyển đổi> Cú pháp Swift hiện tại ... trong menu. Điều này sẽ áp dụng (với đánh giá và phê duyệt của bạn) tất cả các thay đổi cùng một lúc cần thiết cho tất cả các API đã đổi tên và các thay đổi khác. (Thông thường, một dòng mã bị ảnh hưởng bởi nhiều hơn một trong những thay đổi này cùng một lúc, do đó, việc phản hồi sửa lỗi - cá nhân nó có thể không xử lý mọi thứ đúng.)

Kết quả là mô hình phổ biến cho công việc nảy lên nền và trở lại trông như thế này:

// 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
    }
}

Lưu ý rằng chúng tôi đang sử dụng .userInitiatedthay vì một trong các DISPATCH_QUEUE_PRIORITYhằng số cũ . Các công cụ xác định chất lượng dịch vụ (QoS) đã được giới thiệu trong OS X 10.10 / iOS 8.0, cung cấp một cách rõ ràng hơn cho hệ thống để ưu tiên công việc và không dùng các công cụ xác định ưu tiên cũ. Xem tài liệu của Apple về công việc nền và hiệu quả năng lượng để biết chi tiết.

Nhân tiện, nếu bạn đang giữ hàng đợi của riêng mình để sắp xếp công việc, thì cách để có được một hàng bây giờ trông như thế này (chú ý DispatchQueueAttributesOptionSet, vì vậy bạn sử dụng các chữ theo kiểu bộ sưu tập để kết hợp các tùy chọn):

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

Dùng dispatch_afterđể làm việc sau? Đó cũng là một phương pháp trên hàng đợi và cần một DispatchTimetoán tử có các toán tử cho các loại số khác nhau để bạn có thể chỉ cần thêm toàn bộ hoặc một phần giây:

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

Bạn có thể tìm đường xung quanh API công văn mới bằng cách mở giao diện của nó trong Xcode 8 - sử dụng Mở nhanh để tìm mô-đun công văn hoặc đặt một biểu tượng (như DispatchQueue) trong dự án / sân chơi Swift của bạn và nhấp vào lệnh, sau đó phân nhóm các mô-đun từ đó. (Bạn có thể tìm thấy API Swift Dispatch trong trang web Tham khảo API mới của Apple và trình xem tài liệu trong Xcode, nhưng có vẻ như nội dung tài liệu từ phiên bản C chưa được chuyển vào.)

Xem Hướng dẫn di chuyển để biết thêm mẹo.


3
Đối với Xcode 8 Beta 6, thuộc tính .serial là ra đi và hành vi mặc định - forums.developer.apple.com/message/159457#159457
hyouuu

6
Điều này cần một bản cập nhật kể từ XCode 8.1 .. nhãn thuộc tính đã biến mất và ở vị trí của nó, chúng ta có thể sử dụng 'DispatchQueue.global (qos: .background) .async'
Mike M

2
Câu trả lời tuyệt vời. Thực sự đã giúp tôi có được đầu của tôi xung quanh nó.
Mohsin Khubaib Ahmed

Tôi đã phải sử dụng qos:thay vìattributes:
Hồi giáo Q.

Không nên có myQueue.async {trong class Fooví dụ?
vacawama

142

Trong Xcode 8 beta 4 không hoạt động ...

Sử dụng:

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

cho async hai cách:

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

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

Vì vậy, nó không chặn UI?
dùng25

72

Đây là một ví dụ tốt Swift 4về async:

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

hi DispatchQueue.main.async {// Chạy Cập nhật giao diện người dùng} đang thực thi trước luồng nền
Uma Achanta

tương tự với các coroutines của Kotlin
user25

40

trong Xcode 8 sử dụng:

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

26

Swift 5.2, 4 trở lên

Hàng đợi chính và nền

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

Làm việc với các chủ đề không đồng bộđồng bộ !

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

Chủ đề Async sẽ hoạt động cùng với chủ đề chính.

Đồng bộ hóa luồng sẽ chặn luồng chính trong khi thực hiện.


1
Và bạn sẽ sử dụng các luồng Sync như thế nào mà không chặn luồng chính (UI) ?? Tôi muốn thực thi một hàng các thứ trong nền - nhưng các thứ phải được thực hiện lần lượt từng cái một theo cách đồng bộ. Trong thời gian này, UI nên phản hồi nhanh .... Bạn sẽ làm thế nào?
iKK

Sử dụng NSOperationQueue. Mà mỗi nhiệm vụ của bạn đại diện cho một NSOperation. tham khảo stackoverflow.com/a/19746890/5215474
Saranjith

12

Swift 4.1 và 5. Chúng tôi sử dụng hàng đợi ở nhiều nơi trong mã của chúng tôi. Vì vậy, tôi đã tạo lớp Chủ đề với tất cả các hàng đợi. Nếu bạn không muốn sử dụng lớp Chủ đề, bạn có thể sao chép mã hàng đợi mong muốn từ các phương thức lớp.

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()
    }
  }
}

Ví dụ cho thấy việc sử dụng hàng đợi chính.

override func viewDidLoad() {
    super.viewDidLoad()
     Threads.performTaskInMainQueue {
        //Update UI
    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.