DispatchQueue.main
let mainQueue = DispatchQueue.main
DispatchQueue.global()
let userInteractiveQueue = DispatchQueue.global(qos: .userInteractive)
let defaultQueue = DispatchQueue.global() // 디폴트 글로벌큐
DispatchQueue(label: "...")
let privateQueue = DispatchQueue(label: "com.inflearn.serial")
/*Ex 1*/
// UI 관련 작업들은 메인 쓰레드에서 처리하지 않으면 에러가 발생한다 (메인 쓰레드가 아닌 쓰레드는 그림을 다시 그리지 못한다)
DispatchQueue.global(qos: .utility).async {
...
...
self.textLabel.text = "New post updated!"
} // -> 에러
// UI 관련 작업들을 메인쓰레드에서 처리할 수 있도록 메인큐를 통해 작업을 다시 메인쓰레드로 보내준다
DispatchQueue.global(qos: .utility).async {
...
...
DispatchQueue.main.async {
self.textLabel.text = "New post updated!"
}
}
/*Ex 2*/
var imageView: UIImageView? = nil
let url = URL(string: "https://bit.ly/32ps0DI")!
// URL세션은 내부적으로 비동기로 처리된 함수임. -> 메인 쓰레드가 아닌 다른 쓰레드에서 작동하고 있다고 이해하기
URLSession.shared.dataTask(with: url) { (data, response, error) in
if error != nil{
print("에러있음")
}
guard let imageData = data else { return }
// 즉, 데이터를 가지고 이미지로 변형하는 코드
let photoImage = UIImage(data: imageData)
// 🎾 이미지 표시는 DispatchQueue.main에서 🎾
DispatchQueue.main.async {
imageView?.image = photoImage
}
}.resume()
다른 쓰레드에서 작업을 시킬 때, 그게 언제 끝나는지에 대해 생각해야 한다
또한, 다른 쓰레드에서의 작업이 끝나면, return으로 전달하는 게 아니고 클로저로 전달해야 한다
콜백함수를 통해, 작업이 끝난 뒤의 결과를 받아야 한다. (작업을 시작하고 바로 리턴하기 때문에 return x)
return : 비동기 작업을 기다리지 않고 바로 반환 -> nil
return이 아닌 콜백함수를 통해, 끝나는 시점을 알려줘야 한다
// 잘못된 함수 설계
// 비동기적인 작업을 해야하는 함수를 설계할 때 return을 통해 데이터를 전달하려면 항상 nil이 return된다
func getImages(..., c..: String) -> UIImage? {
...
URLSession.shared.dataTask(..) {
...
}.resume()
...
...
return photoImage // 함수 내부의 일이 끝나기 전에 return하기 때문에 무조건 nil이 return된다
}
// 올바른 함수 설계
// 비동기적인 작업을 해야하는 함수는 항상 클로저를 호출할 수 있도록 함수를 설계해야 한다
func getImages(..., completionHandler: @escaping (UImage?) -> Void) {
...
URLSession.shared.dataTask(..) {
...
...
completionHandler(photoImage) // 함수 내부의 일이 끝나면 completionHandler 호출한다
}.resume()
}
// full code는 자료에 있으니까 실행시켜보기
// 작업을 오랫동안 실행하는 함수
func longtimePrint(name: String) -> String {
print("프린트 - 1")
sleep(1)
print("프린트 - 2")
sleep(1)
print("프린트 - 3 이름:\(name)")
sleep(1)
print("프린트 - 4")
sleep(1)
print("프린트 - 5")
return "작업 종료"
}
longtimePrint(name: "잡스")
// 비동기함수로 변형
func asyncLongtimePrint(name: String, completion: @escaping (String) -> Void) {
DispatchQueue.global().async {
let n = longtimePrint(name: name)
completion(n)
}
}
asyncLongtimePrint(name: "잡스") { (result) in
print(result)
// 메인쓰레드에서 처리해야하는 일이라면,
// DispatchQueue.main.async {
// print(result)
// }
}
var array = [String]() // 빈 배열 -> 메모리 공간에 하나만 존재
let serialQueue = DispatchQueue(label: "serial") // 직렬 큐 하나 생성
for i in 1...20 { // 1부터 20까지 비동기적으로 실행 -> 여러 쓰레드에서 배열에 접근
DispatchQueue.global().async {
print("\(i)")
//array.append("\(i)") // <===== 동시큐에서 실행하면 동시다발적으로 배열의 메모리에 접근 -> append가 제대로 작동이 되지 않는다. 중간중간 빠진 숫자가 존재
// 직렬 큐를 통해 한 번에 하나의 쓰레드에서만 접근할 수 있도록 한다!!
serialQueue.async { // 올바른 처리 ⭐️
array.append("\(i)")
}
}
}