Dispatch main async swift 4 hướng dẫn năm 2024

Mọi hệ điều hành đều cung cấp các công cụ khác nhau cho lập trình viên để sử dụng concurrency. Ở iOS, chúng ta sử dụng processe, thread và Dispatch Queues.

Process

Process hay nôm na là luồng, là một khái niệm quan trọng trong lập trình iOS nói chung và từng app nói riêng. Bản chất của nó chứa những thứ cần thiết để chạy app, bao gồm stack, heap và các tài nguyên khác. Process là quá trình hoạt động của một ứng dụng. Điều đó nghĩa là gì? Có thể lấy một ví dụ như sau, khi bạn click đúp chuột vào biểu tượng MS Word, một process chạy ứng dụng Word được khởi tạo. Mặc dù iOS là một hệ điều hành đa nhiệm, thế nhưng nó lại không hỗ trợ nhiều process trong từng ứng dụng, còn macOS thì lại khác, bạn có thể dùng class Process để sinh ra nhiều process con, chúng độc lập với process cha nhưng chứa mọi thông tin và dữ liệu của process cha. Dưới đây là code ví dụ khởi tạo một process trong macOS:

let task = Process() task.launchPath = "/bin/sh" //executable you want to run task.arguments = arguments //here is the information you want to pass task.terminationHandler = { // do here something in case the process terminates } task.launch()

Thread

Trong iOS thì các process con như trên được gọi là thread, thread có thể chia sẻ bộ nhớ với parent process của chúng, điều này có thể dẫn tới một vấn đề nghiêm trọng đó là tình huống hai thread cùng thay đổi giá trị của một variable nào đó một lúc => sai lệch giá trị của variable đó.

Thread là một tài nguyên có giới hạn trong iOS, chúng ta chỉ được phép có 64 thread cùng một lúc, mặc dù con số này là nhiều thế nhưng vẫn tồn tại khả năng khối lượng tác vụ của chúng ta vượt qua con số đó. Cách để khởi tạo và thực thi một thread như sau:

class CustomThread: Thread { override func main() {

do_something  
} } let customThread = CustomThread() customThread.start()

Dispatch Queues

Vì chúng ta bị giới hạn số lượng thread và process ở con số 64, thế nên cần phải có giải pháp để chạy đa luồng, đó chính là Dispatch queues. Bạn có thể thêm task vào trong một dispatch queue và tùy chỉnh thực thi task đó tại một thời điểm bất kỳ. Có rất nhiều kiểu dispatch queues, đầu tiên là SerialQueue, kiểu này cho phép các tác vụ thực thi theo thứ tự lần lượt giống như khi được thêm vào. Ngược lại thì với ConcurentQueue, các tác vụ được thực thi cùng một thời điểm.

Nhìn qua thì có vẻ không hẳn là concurrent, đặc biệt là với SerialQueue, vậy điểm mấu chốt ở đây là gì? Hãy thử xem xét điều gì sẽ xảy ra khi chúng ta có nhiều queue, chúng ta chỉ cần chạy một queue trên một thread, và cũng hoàn toàn có thể phân phối các task tới các queue để tối ưu tài nguyên hệ thống của mình.

Dispatch main async swift 4 hướng dẫn năm 2024

Và đó chinhs là cơ chế của Grand Central Disptach (GCD), một cơ chế rất mạnh mẽ mà Apple đã dành tặng cho các lập trình viên iOS, từ đây thì việc quản lý, phân phối các task sẽ trở nên dễ dàng hơn nhiều.

DispatchQueue.main.async {

// execute async on main thread  
}

Một cái hay nữa của Dispatch Queue đó là nó làm thay đổi cách tư duy của bạn về concurent. Thay vì quan tâm đến thread, chúng ta sẽ nghĩ về các khối công việc được phân bổ vào các queue khác nhau. Đơn giản hơn rất nhiều.

Operation Queues

GCD là một API cấp thấp của ngôn ngữ C, còn operation queues được xây dựng tầng bên trên của GCD. Điều này có nghĩa là chúng ta có thể sử dụng NSOperation để thực thi các task đồng thời giống như GCD, nhưng việc sử dụng operation queue sẽ hướng đối tượng hơn, đơn giản hơn cho lập trình viên.

Chúng ta có main queue là loại chuyên thực thi tác vụ trên main thread và custom queues thực thi trên các thread còn lại.

let operationQueue: OperationQueue = OperationQueue() operationQueue.addOperations([operation1], waitUntilFinished: false)

Một operation có thể khởi tạo bằng nhiều cách như sử dụng block, closure, subclass. Và nếu sử dụng subclass thì đừng quên gọi đến finish, nếu không operation sẽ không bao giờ dừng lại.

class CustomOperation: Operation {

override func main() {  
    guard isCancelled == false else {  
        finish(true)  
        return  
    }  
    // Do something  
    finish(true)  
}  
}

Một điểm hay nữa của operation là bạn có thể sử dụng dependency, như ở ví dụ dưới đây, operation1 sẽ thực thi trước operation2.

operation2.addDependency(operation1) //execute operation1 before operation2

Run Loops

Dispatch main async swift 4 hướng dẫn năm 2024

Run Loops tương tự với Queues, hệ thống sẽ chạy hết các tác vụ trong queue và bắt đầu lại từ đầu theo một chu kỳ. Một điều cần lưu ý ở đây đó là tác vụ được gắn vào một single thread, nhưng bạn vẫn có thể thực thi chúng bất đồng bộ với nhau.

Khi sử dụng Run Loops bạn cần lưu ý rằng chúng có các chế độ khác nhau. Ví dụ, khi bạn scroll màn hình, Run Loop ở trên Main thread sẽ thay đổi và delay các event tiếp sau đó. Và khi bạn dừng vuốt, Run Loop sẽ trở về trạng thái bình thường và các event lại tiếp tục thực thi, và một Run Loop luôn cần một input source, nếu không mọi thứ thực thi trong nó sẽ lập tức thoát ra.