iOS

[iOS] SDWebImage 이미지 다운로드 오류 (Downloaded image decode failed)

i-moo 2024. 1. 3. 20:31
반응형

SwiftUI를 사용하는 프로젝트에서
SDWebImage 라이브러리는 SDWebImageSwiftUI 를 사용해야한다.
(SDWebImageSwiftUI를 설치하면 자동으로 SDWebImage도 설치됨)

https://github.com/SDWebImage/SDWebImageSwiftUI

 

GitHub - SDWebImage/SDWebImageSwiftUI: SwiftUI Image loading and Animation framework powered by SDWebImage

SwiftUI Image loading and Animation framework powered by SDWebImage - GitHub - SDWebImage/SDWebImageSwiftUI: SwiftUI Image loading and Animation framework powered by SDWebImage

github.com

 

SDWebImageSwiftUI에서 제공해주는 WebImage를 통해 서버 이미지를 가져오게 되어있는데
채팅에서 사용자가 직접 업로드 해준 이미지에대해서만 다운로드를 못받아오는 현상이 있었는데
(사실 직접 업로드 여부는 관련 없었음)
사파리나 크롬에서는 해당 이미지가 정상적으로 보임.

 

WebImage(url: self.url, options: options, context: context)
    .onProgress { receivedSize, totalSize in
    }
    .onFailure { error in
        loadError = error
    }
    .onSuccess { image, data, cacheType in
    }
    .placeholder {
        ZStack {
            placeholder()
        }
    }
    .resizable()

 

일단, onProgress에서 receivedSize가 0 -> totalSize 까지 사이즈는 정상적으로 내려왔다.

처음엔 onFailure 에서 나오는 에러가 "Downloaded image decode failed" 였기때문에
데이터 다운로드는 정상적으로 되었는데 이미지로 전환하면서 문제가 있나 싶어서
WebCoder를 설정해주는 방식으로 진행 해봤다.

 

1. AppDelegate에 앱 시작시, Coder 적용 > 동일 에러 발생

SDImageCodersManager.shared.addCoder(SDImageAWebPCoder.shared)

 

2. WebImage 생성할 때, context 설정 > 동일 에러 발생

WebImage(url: getImageURL(), options: .retryFailed, context: [.imageCoder: SDImageAWebPCoder.shared])

여기서 별개로 .retryFailed 를 options으로 설정해줬는데,
계속 실패하는 요청을 여러번 하다보니
WebImage 내부에서 해당 URL를 SDWebImage 블랙리스트로 추가하여 요청을 막는 현상이 발생되었다.
retryFailed 설정은 블랙리스트를 비활성화하는 설정이라 해당 현상은 방지할 수 있어서 추가했다.

SDWebImageRetryFailed : By default, when a URL fail to be downloaded, the URL is blacklisted so the library won’t keep trying. This flag disable this blacklisting.

https://github.com/SDWebImage/SDWebImage/blob/fd010e54231331fc19338f81c6d072cd9ace2825/SDWebImage/Core/SDWebImageDefine.h#L57C1-L58C1

 


 

다시 돌아와서 이미지 자체를 어디서 못받아오는지 확인하려고 라이브러리 내부 코드를 확인하니
애초에 requestImageWithURL로 이미지를 받아오는 부분에서 이미지 자체를 못받아 오고 있었다.

에러 코드는 SDWebImageErrorDomain - code: 1001

downloadedImage = nil, downloadedData = nil

 

 

흠,, 애초에 이미지를 못받아오는 거였네 🥲

SDWebImageErrorDomain - code: 1001 을 검색하니 해당 내용 발견!

https://github.com/SDWebImage/SDWebImage/issues/2824#issuecomment-527724645

 

Error Domain=SDWebImageErrorDomain Code=1001 "Image data is nil" · Issue #2824 · SDWebImage/SDWebImage

the imageUrl is 'https://www.cyzone.cn/upload/2019/0902/b0085277de84f5a27b9b54196160bc97.png' the code is : UIImageView *view = [[UIImageView alloc] init]; [self.view addSubview:view]; view.frame =...

github.com

생각해보니,, web으로 접속할 때 항상 로그인하고 시도했고, 쿠키 연동이 되었을터,,,

 

SDWebImage 공식 문서를 찾아보니 SDWebImageDownloaderRequestModifier 를 통해서 요청을 변경할 수 있다.

https://github.com/SDWebImage/SDWebImage/wiki/How-to-use#use-request-modifier-50

 

How to use

Asynchronous image downloader with cache support as a UIImageView category - SDWebImage/SDWebImage

github.com

 

친절하게 샘플 코드도 존재함.
(위에 링크 접속하면 Objective-C 코드도 존재)

let requestModifier = SDWebImageDownloaderRequestModifier { (request) -> URLRequest? in
    if (request.url?.host == "foo") {
        var mutableRequest = request
        mutableRequest.setValue("foo=bar", forHTTPHeaderField: "Cookie")
        return mutableRequest
    }
    return request
};
SDWebImageDownloader.shared.requestModifier = requestModifier

 

3. 로그인할 때 인증 토큰을 세팅해주고,
로그아웃할 때 requestModifier를 초기화 해주었다. > 이미지 정상 다운로드

참고로, requestModifier 디폴트 값도 nil.

 

// 로그인
func login(_ info: MeResponse) {
    me = info
    
    let requestModifier = SDWebImageDownloaderRequestModifier { (request) -> URLRequest? in
        if let accessToken = UserData.shared.accessToken {
            var mutableRequest = request
            mutableRequest.setValue(accessToken, forHTTPHeaderField: "Authorization")
            return mutableRequest
        }
        
        return request
    }
    SDWebImageDownloader.shared.requestModifier = requestModifier
}

// 로그아웃
func logout() {
    me = nil
    SDWebImageDownloader.shared.requestModifier = nil
}

 

반응형