본 글에서는 Swift 기반의 iOS Application에서 Thread(동시성 프로그래밍, 동기/비동기 프로그래밍 등)를 관리하는 방법 중 DispatchQueue에 대해 다룹니다.
1. Main Thread
•
UI와 관련된 모든 작업은 Main Thread에서 동작하게 됩니다.
•
Background Thread에서 UI 관련된 작업을 진행하게 될 경우, 아래와 같은 Exception이 발생합니다.
•
따라서 UI 관련된 작업은 Main Thread에서 진행하는 것이 바람직합니다.
•
아래는 올바른 예시입니다.
// Distpach Queue - Thread 관리
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var finishLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func action(_ sender: Any) {
// Main Thread 에서 동작 - UI
simpleClosure {
DispatchQueue.main.async {
self.finishLabel.text = "끝"
}
}
}
func simpleClosure(completion: @escaping () -> Void) {
// Background Thread 에서 동작
DispatchQueue.global().async {
for index in 0..<10 {
Thread.sleep(forTimeInterval: 0.2)
print(index)
}
completion()
}
}
}
Swift
복사
2. DispatchGroup
•
DispatchGroup은 다중 Thread의 큐를 그룹 단위로 묶을 수 있고, Qos(작업 우선 순위)를 부여할 수 있습니다.
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func action(_ sender: Any) {
let dispatchGroup = DispatchGroup()
let queue1 = DispatchQueue(label: "q1")
let queue2 = DispatchQueue(label: "q2")
let queue3 = DispatchQueue(label: "q3")
queue1.async(group: dispatchGroup, qos: .background) {
dispatchGroup.enter()
DispatchQueue.global().async(qos: .background) {
for index in 100..<120 {
Thread.sleep(forTimeInterval: 0.1)
print("queue1's internal queue - \(index)")
}
dispatchGroup.leave()
}
}
queue2.async(group: dispatchGroup, qos: .userInteractive) {
for index in 10..<20 {
Thread.sleep(forTimeInterval: 0.2)
print("queue2 - \(index)")
}
}
queue3.async(group: dispatchGroup) {
for index in 20..<30 {
Thread.sleep(forTimeInterval: 0.2)
print("queue3 - \(index)")
}
}
dispatchGroup.notify(queue: DispatchQueue.main) {
print("끝")
}
}
}
Swift
복사
3. 동기 처리(Sync)와 DeadLock(교착 상태)
•
교착 상태란, Thread가 다음 작업을 진행하지 못하고 계속 대기하고 있는 상태를 말합니다.
•
sync로 작업 하게 될 경우, 모든 작업을 중지하고 기다리게 됩니다. 따라서 DeadLock이 발생할 확률이 있습니다.
•
그러므로 굉장히 중요한 작업일 때(해당 작업이 끝나고 다음 작업을 진행해야 할 때) 사용하는 것이 바람직하겠습니다.
•
또한, Main Thread는 앱이 사용되는 한 계속 작업을 진행하기 때문에 async(비동기)를 사용하는 것이 바람직하겠습니다.
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func action(_ sender: Any) {
let queue1 = DispatchQueue(label: "q1")
// 다른 작업을 다 멈추게 함
queue1.sync {
for index in 10..<20 {
Thread.sleep(forTimeInterval: 0.2)
print("queue1 - \(index)")
}
// Dead Lock -> 다음 작업을 진행하지 못하고 계속 기다리고 있는 상태
// Dead Lock이 발생할 수 있기 때문에 sync로 작업 하는 경우는,
// 굉장히 중요한 작업일 때(해당 작업이 끝나고 다음 작업을 진행해야 할 때) 사용하는 것이 안전함(많이 사용하지는 않음)
// queue1.sync {
// for index in 20..<30 {
// Thread.sleep(forTimeInterval: 0.2)
// print("queue2 - \(index)")
// }
// }
}
}
}
Swift
복사