오늘도 어김없이 오류를 내었음.
높은 우선순위의 작업(User-initiated)이 낮은 우선순위 작업(default)을 기다리고 있으니까 이 우선순위 역전을 피할 수 있는 방법을 찾아라 뭐 그런거 같음
오류를 보면 Data(ContentsOf)에서 나는 것을 볼 수 있었음.
Thread Performance Checker:
Thread running at User-initiated quality-of-service class waiting on a lower QoS thread running at Default quality-of-service class. Investigate ways to avoid priority inversions
[NSData(NSData) initWithContentsOfURL:options:maxLength:error:]
전체적인 로직은 아래와 같음
좋아요를 누르면 -> 이미지를 dataContentsOf로 다운로드 후 FileManager에 저장
좋아요를 해제하면 -> 이미지를 FileManager에서 삭제
두 장의 이미지를 받아야 하기 때문에 DispatchGroup을 통해서 둘 다 정상적으로 다운받지 못할 경우 Toast를 출력하도록 했음
func downloadImage(imageURL: String, profileURL: String, imageID: String){
let group = DispatchGroup()
var isFailed = false
group.enter()
DispatchQueue.global().async(group: group) {
print("DispatchQueue", Thread.current.qualityOfService.rawValue)
imageURL.loadImage { result in
switch result {
case .success(let value):
ImageFileManager.saveImageToDocument(image: value, filename: imageID)
case .failure:
isFailed = true
}
group.leave()
}
}
//DispatchQueue 로직 생략//
group.notify(queue: .main){
if isFailed {
self.showToast("이미지를 다운받지 못했습니다")
}
}
}
여기가 오류의 발생지인데, Data(ContentsOf)를 사용하는 곳임
자세히 모르겠지만 Data(ContentsOf) 가 실행되는 스레드의 qos가 default이고
qos가 userInitiated인 스레드가 이 다운로드가 끝날때까지 기다리고 있는 것임
원래대로라면 userInitiated스레드의 작업 이후, default 스레드의 작업이 이루어져야 하지만 반대로 되고 있네? 라는 것임
func loadImage(completion: @escaping (Result<UIImage, Error>) -> Void) {
guard let url = URL(string: self) else {
completion(.failure(LoadImageError.invalidURL))
return
}
if let data = try? Data(contentsOf: url) {
if let image = UIImage(data: data) {
completion(.success(image))
}
}else{
DispatchQueue.main.async {
completion(.failure(LoadImageError.failedDownload))
}
}
}
ViewController 호출부의 실행- UserInteractive
DispatchQueue 안 코드들의 실행 - UserInitiated
dataContentsOf - default
아래 그림과 같은 상황임. qos가 높은 스레드의 실행순서가 더 낮아짐 > 우선순위 역전
우선순위 역전 문제에서는 낮은 우선순위의 작업을 높은 우선순위로 변경한다고 함.
Data(ContentsOf) 작업의 우선순위를 높일수가 없을 것 같아서 높은 우선순위의 작업을 우선순위를 낮추어서 해결해볼 수 있지 않을까 생각함
DispatchQueue의 qos를 utility로 변경해서 default보다 낮춰주니 해당 오류가 사라짐
func downloadImage(imageURL: String, profileURL: String, imageID: String){
let group = DispatchGroup()
var isFailed = false
group.enter()
DispatchQueue.global(qos: .utility).async(group: group) {
print("DispatchQueue", Thread.current.qualityOfService.rawValue)
imageURL.loadImage { result
switch result {
case .success(let value):
ImageFileManager.saveImageToDocument(image: value, filename: imageID)
case .failure:
isFailed = true
}
group.leave()
}
}
//DispatchQueue 로직 생략//
group.notify(queue: .main){
if isFailed {
self.showToast("이미지를 다운받지 못했습니다")
}
}
}
참고자료
'iOS > iOS 지식' 카테고리의 다른 글
[Swift] Struct와 Class (1) - Class 안에 Class, Struct 안에 Class (0) | 2024.10.05 |
---|---|
[iOS] ViewController 생명주기(2) - 실험 (2) | 2024.10.04 |
[iOS] 네트워크 연결 감지 해보기 (0) | 2024.08.03 |
[WWDC2020] Advances in UICollectionView (0) | 2024.07.19 |
[iOS] Realm 사용하면서 생긴 문제들 (0) | 2024.07.05 |