์ด๋ฒ์ unsplash์ api๋ฅผ ๋ฐ์์ json ๋ฐ์ดํฐ๋ฅผ ํ์ธํด๋ณด๋ ์ ๊ธฐํ ์ ์ด ์์๋ค. image๋ ๋ฐ๋ก url ์ข ๋ฅ๋ก ์ฃผ์ด์ง๊ณ , ํด๋น url์ ๋ค์ ๋ฐ์์์ ์ฌ์ฉํด์ผ ํ๋ค๋ ๊ฒ! ๋๋ฌธ์ image๋ฅผ ๋ค์ด๋ก๋ ํ์ฌ imageView์ ๋ฃ์ด์ฃผ๋ protocol์ ํ๋ ๋ง๋ค์๋ค.
protocol ImageViewDownloadable {
var imageView: UIImageView { get set }
}
๊ทธ๋ฆฌ๊ณ extension์ผ๋ก ์ด ํ๋กํ ์ฝ์ ์ฑํํ๊ณ ์๋ค๋ฉด image๋ฅผ ๋ณด์ฌ์ค ์๋ ์๊ณ , ๊ฐค๋ฌ๋ฆฌ์ ๋ค์ด๋ฐ์ ์๋ ์๋ ๋ฉ์๋๋ค์ ๊ฐ๊ฐ ๊ตฌํํ์๋ค.
1. URLSession.shared.dataTask , @escaping closure
๊ทธ๋ ๊ฒ ๋ง๋ ์ฒซ ๋ฐฉ๋ฒ์ dataTask์ @escaping closure๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด๋ค.
func downloadImageUseDataTaskCallBack(url: URL) {
let dataTask = URLSession.shared.dataTask(with: url) { data, response, error in
if let error = error as NSError? {
print(error.localizedDescription)
self.imageView.image = UIImage(named: "noImage")
return
}
guard let data,
let image = UIImage(data: data) else {
self.imageView.image = UIImage(named: "noImage")
print("download error: \(String(describing: error?.localizedDescription))")
return
}
Task { @MainActor in
self.imageView.image = image
}
}
dataTask.resume()
}
func downloadImageToGalleryUseDataTaskCallBack(url: URL) {
let dataTask = URLSession.shared.dataTask(with: url) { data, response, error in
if let error = error as NSError? {
print(error.localizedDescription)
return
}
guard let data,
let image = UIImage(data: data) else {
print("download error: \(String(describing: error?.localizedDescription))")
return
}
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)
}
dataTask.resume()
}
๋ค๋ง ์ด๋ ๋ฌด์กฐ๊ฑด protocol์ imageView๋ฅผ ๊ฐ์ง๊ณ ์์ด์ผ ํ๊ณ ๊ฐ์ ๋ด์ฉ์ด ๋ฐ๋ณต๋์ด์ผ ํ๋ค.
๊ฐ๋ ์ฑ์ด ์ข์ง๋ ์์๊ณ , ๊ธฐ๋ณธ์ ์ผ๋ก dispatchQueue๋ฅผ ์ฌ์ฉํ๊ณ ์๊ธฐ์ Swift concurrency๋ณด๋ค ์ค๋ ๋๋ฅผ ๊ณผํ๊ฒ ์ฌ์ฉํ๊ฒ ๋๋ ์ฑ๋ฅ์ ์ข์ง ์์ ๊ฒ ๊ฐ์๋ค. ๊ฑฐ๊ธฐ๋ค๊ฐ imageView์ image์ ํ ๋นํด์ฃผ๊ธฐ ์ํด @MainActor๋ฅผ ์ฌ์ฉํ๊ณ ์๋๋ฐ View๋ View์ ๋จ์์ ๋ณ๊ฒฝํด์ฃผ๋ ๊ฒ์ด ๋ง์ ๊ฒ ๊ฐ์์ ๋ณ๊ฒฝํ์๋ค.
2. Async await ์ฌ์ฉ
protocol ImageViewDownloadable { }
extension ImageViewDownloadable {
func downloadImage(url: URL) async throws -> UIImage {
let (data, response) = try await URLSession.shared.data(from: url)
guard let httpResponse = response as? HTTPURLResponse,
(200...299).contains(httpResponse.statusCode) else {
throw NetworkError.invalidURL
}
guard let image = UIImage(data: data) else {
throw NetworkError.noData
}
return image
}
}
๋๋ฌธ์ async awiat์ ์ฌ์ฉํ์ฌ UIImage๋ฅผ ๋ฐํํ๋ ํ์์ผ๋ก ๋ฐ๊พธ์๋ค.
์ด๋ ๊ฒ ํ๋ฉด ํ๋กํผํฐ๋ก imageView๋ฅผ ๊ฐ์ง๊ณ ์์ ํ์๋ ์์ด์ ๋ง์ผ private ์ฒ๋ฆฌ๊ฐ ๊ฐ๋ฅํ๋ค๋ฉด ํด์ค ์ ์๋ค.
func configureImage(title: String, url: URL) {
Task {
do {
let image = try await downloadImage(url: url)
imageView.image = image
} catch {
imageView.image = UIImage(named: "noImage")
}
}
}
๋ํ ์ฌ์ฉํ๋ ๊ณณ์์ ์ด๋ ๊ฒ ์๋ฌ๋ฅผ ๋ง๋๋ฉด "noImage"์ ์ด๋ฏธ์ง๋ก ๋ฐ๊พธ๋๋ก ํด์ค ์ ์๊ณ , ๋ค์ด๋ก๋ํ๋ ๋ถ๋ถ์ ๋ ๊ฐ๋จํด์ง๋ค.
@objc private func tappedDownloadButton() {
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)
}
์ฌ์ค ์ด ๋ค์ด๋ก๋ ๋ถ๋ถ์ ๋ฐ๋ก ์ ๋นผ๋ ๋์์ ๊ฒ ๊ฐ๋ค ๊ทธ์ ์๋...
๋ณ๊ฒฝ ๋!
'๐ iOS > ๐ฅ ํธ๋ฌ๋ธ ์ํ ' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[iOS/Swift]๋ฒํผ์ ํ ๋ฒ๋ง ๋๋ ๋๋ฐ View๊ฐ ๋ ๋ฒ ๋ถ๋ฆฐ๋ค? (0) | 2024.07.04 |
---|---|
[iOS/Swift] UIView to UIImage without Display (0) | 2024.07.02 |
[iOS] UICollectionViewFlowLayout์ผ๋ก Pinterest Layout ๊ตฌํํ๊ธฐ (0) | 2024.01.31 |
[iOS] Test ํ์ผ์ ๋ฃ์ Asset ์์ฑ์ ์ค๋ฅ_ Bundle ์ฌ์ฉ (1) | 2024.01.28 |
[iOS] TableViewCell์์ layoutMarginsGuide ์ฌ์ฉ (0) | 2024.01.06 |