์ด๋ฏธ์ง ๋ ๋๋?
๊ฑฐ์ ๋ชจ๋ ์ดํ๋ฆฌ์ผ์ด์ ์์ ์ด๋ฏธ์ง๋ฅผ ํ์ํฉ๋๋ค. ์ฌ์ค์ ์ด๋ฏธ์ง๊ฐ ์๋ ์ฑ์ ์๋ค๊ณ ๋ณผ ์ ์์ฃ . ๊ทธ๋ฆฌ๊ณ ์์ด์ฝ, ๋ก๊ณ ๋ฑ์ ์ ์ธํ ์ด๋ฏธ์ง๋ ์๊ฒฉ ์๋ฒ์์ ๊ฐ์ ธ์ค๋ ๊ฒฝ์ฐ๊ฐ ๋๋ถ๋ถ์ ๋๋ค. ์ด๋ฏธ์ง๊ฐ ์๊ฒฉ ์๋ฒ์ ์๋ค๋ ์๋ฏธ๋ ์ด๋ค ์๋ฏธ์ผ๊น์? ๊ฒฐ๊ตญ ๊ทธ ์ญ์ ๋คํธ์ํฌ ์์ฒญ์ด๊ธฐ ๋๋ฌธ์ ์ผ์ ์๊ฐ์ด ์์๋๊ณ ๋น์ฉ์ด ๋ ๋ค๋ ์ด์ผ๊ธฐ์ ๋๋ค.
์๊ฐ๊ณผ ๋น์ฉ์ด ๋๋ ์์ ์ด๊ธฐ ๋๋ฌธ์ ์ฐ๋ฆฌ๋ ์์ฒญ ํ์๋ฅผ ์ต์ํํ๊ฑฐ๋, ์ ์ ํ ํ์ด๋ฐ์ ์์ฒญ์ ํด์ผ ํฉ๋๋ค.
์ด๋ฏธ์ง ์์ฒญ ์ทจ์(Cancel) ์์ ์ ํ์์ฑ
๊ทธ๋ฆฌ๊ณ ์ด๋ฏธ์ง ์์ฒญ์ ๊ฒฝ์ฐ ์๊ฐ์ด ๊ฑธ๋ฆฌ๋ ๋น๋๊ธฐ ์์ ์ด๊ธฐ ๋๋ฌธ์ ์ ํ๋ฆฌ์ผ์ด์ ๋ด์์ ๊ฒฝ์ ์กฐ๊ฑด์ด ๋ฐ์ํ ์ ์์ต๋๋ค. ์ด๋ค ์์ฒญ ์์ ์ด ๋จผ์ ๋๋ ์ง ์์ธกํ๊ธฐ๋ ์ด๋ ต์ฃ . ํ ์ด๋ธ ๋ทฐ๋ ์ปฌ๋ ์ ๋ทฐ ์ฒ๋ผ ๋ง์ ์ ์ ๊ฐ์ง ์ ์๋ ์ํฉ์์๋ ์์์น ๋ชปํ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์๋ ์์ต๋๋ค. ์ง๊ธ ์ ์์ ๋ณด์ฌ์ ธ์ผ ํ๋ ์ด๋ฏธ์ง๊ฐ ์๋ ๋ค๋ฅธ ์ด๋ฏธ์ง๊ฐ ๋ณด์ฌ์ง ์๋ ์๋ ๊ฒ์ ๋๋ค. ์ข ๋ ์ด์ผ๊ธฐํด๋ณด๋ฉด ํ๋ฉด ๋ฐ์ผ๋ก ๋ฒ์ด๋ ์ ์์ ์งํ๋ ์์ฒญ ์์ ์ด ์ด์ ๋ง ๋๋์ ํ๋ฉด์ ๋ณด์ฌ์ง๊ณ ์๋ ์ ์ ์ด๋ฏธ์ง๋ฅผ ์ ๋ฌํด๋ฒ๋ฆฌ๋ ์ํฉ์ด ์๊ธฐ๋ ๊ฒ์ ๋๋ค.
์ด๋ฏธ์ง ์์ฒญ ์ทจ์(Cancel) ์์
๊ทธ๋ฌ๋ฉด ์ด๋ป๊ฒ ์ทจ์ ์์ ์ ์ํํ ์ ์์๊น์?
๊ฐ๋ น URLSession์ ์ด์ฉํ๋ ์ํฉ์ด๋ผ๊ณ ์๊ฐํด๋ณด๋ฉด URLSessionDataTask๋ฅผ ๋ฐํํ๋ dataTask ๋ฉ์๋๋ฅผ ์ฌ์ฉํด์ ์ฒ๋ฆฌ๋ฅผ ํด๋ณผ ์ ์์ด์.
open func dataTask(with url: URL, completionHandler: @escaping @Sendable (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTask
task๋ฅผ ๋ณ์์ ์์ ์ ์ฅํด์ ์ฌ์ฉํ ๊ฑด๋ฐ, ์ด task์ ๋ํด์ ๋ค์๊ณผ ๊ฐ์ ์์ ๋ค์ ์ํํ ์ ์์ต๋๋ค:
resume() : ์์ ์์
cancel() : ์์ ์ทจ์
suspend() : ์์ ์ผ์์ค์ง
์ด ์์ ์ค์์ cancel() ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ฉด ๋ฉ๋๋ค.
์๋ฅผ ๋ค์ด์ Image ์์ฒญ์ ํ๊ณ ๊ฐ์ ธ์ค๋ ์๋น์ค ๊ฐ์ฒด๊ฐ ์๋ค๊ณ ํด๋ณผ๊ฒ์.
final class ImageService {
func image(for url: URL, completion: @escaping((UIImage?) -> Void)) -> URLSessionDataTask {
let dataTask = URLSession.shared.dataTask(with: url) { data, _, _ in
var image: UIImage?
defer {
DispatchQueue.main.async {
completion(image)
}
}
if let data {
image = UIImage(data: data)
}
}
dataTask.resume()
return dataTask
}
}
// cell
var task: URLSessionDownloadTask?
let service = ImageService()
task = service.image(url: imageURL) {
// work
}
// cell reuse or collection view end displaying
task.cancel()
๊ทธ๋ฆฌ๊ณ ์ฌ์ฉํ๋ ์ชฝ์์๋ ๋๋ต ์์ ๊ฐ์ด ํด์ค ์ ์๊ฒ ์ฃ . image๋ฅผ ์์ฒญํ๋ ์์ ์์ฒด๋ฅผ task์ ๋ด์๋๊ณ , ์ทจ์ํด์ผ ํ๋ ์ํฉ์์๋ cancel ๋ฉ์๋๋ฅผ ํธ์ถํด์ฃผ๋ฉด ๋ฉ๋๋ค.
์ฝ๋๋ฅผ ๊ฐ์ ํด๋ณผ๊น์?
์ ๋ ์ง๊ธ๋ถํฐ Cancellable์ด๋ ํ๋กํ ์ฝ์ ๋ง๋ค ๊ฒ์
๋๋ค. ์ด ํ๋กํ ์ฝ์ ์ทจ์ ๊ฐ๋ฅํ ํ์
์ ๋ํ๋
๋๋ค.
์์ ํ๋กํ ์ฝ์ ๋ง๋ค์ด์ ์ฌ์ฉํ๋ ์ด์ ์๋ ์ฌ๋ฌ๊ฐ์ง๊ฐ ์์ ์ ์์ง๋ง ์ ๋ ์๋์ ๊ฐ์ด ์ค๋ช
ํ๊ฒ ์ต๋๋ค:
1. ์ฌ์ฉํ๋ ๊ณณ์์ ๊ตฌ์ฒด์ ์ธ ํ์ ์ ์์ง ๋ชปํ๊ฒ ํฉ๋๋ค. ์ด๋ ์๋์ ๋ค๋ฅด๊ฒ ๋ค๋ฅธ ์์ ๋ค์ ์ํํ ์ ์๊ฒ ํฉ๋๋ค. ์ฐ๋ฆฌ๋ ์ทจ์ ์์ ๋ง ์ํํ๊ฒ ํ๊ณ ์ถ์ต๋๋ค.
2. ๋น์ฅ์ ์ด๋ฏธ์ง๋ฅผ ๊ฐ์ ธ์ค๋ ์์ ๋ง ๋ค๋ฃจ๊ณ ์์ง๋ง, ์ฑ ๋ด์์๋ ์ ๋ง ๋ค์ํ ๋น๋๊ธฐ ์์ ์ ์ํํฉ๋๋ค. ์ผ๊ด์ ์ผ๋ก ๋ค์ํ ์์ ์ ์ทจ์ํ๊ณ ์ถ์ ์๋ ์์ต๋๋ค.
์ด๋ฆ์ Combine์ ํ๋กํ ์ฝ๊ณผ ์ค๋ณต๋๋, ๋น์ฅ์ ๋ค๋ฅธ ์ด๋ฆ์ ์ฌ์ฉํ๊ฒ ์ต๋๋ค.
protocol WorkCancellable {
func cancel()
}
extension URLSessionTask: WorkCancellable {}
๊ทธ๋ฆฌ๊ณ URLSessionTask์ WorkCancellable์ ์ฑํํ๊ฒ ์ต๋๋ค. (URLSessionDataTask๋ URLSessionTask๋ฅผ ์์ํ๊ณ ์์ต๋๋ค.) URLSessionTask๋ ์ด๋ฏธ ๋ด๋ถ์ ์ผ๋ก cancel()๋ฉ์๋๋ฅผ ๋ค๊ณ ์๊ธฐ ๋๋ฌธ์ ์๋์ผ๋ก ํ๋กํ ์ฝ์ ์ค์ํ๊ฒ ๋ฉ๋๋ค.
final class ImageService {
func image(for url: URL, completion: @escaping((UIImage?) -> Void)) -> WorkCancellable {
let dataTask = URLSession.shared.dataTask(with: url) { data, _, _ in
var image: UIImage?
defer {
DispatchQueue.main.async {
completion(image)
}
}
if let data {
image = UIImage(data: data)
}
}
dataTask.resume()
return dataTask
}
}
๋ง๋ฌด๋ฆฌ
์๊ฐ์ ํด๋ณด๋ฉด ์์ ์ ์ทจ์ํ๋ค๋ ๊ฒ์ ๋๊ฒ ์๊ฐํด๋ณด๋ฉด ๋ถํ์ํ ๋ฆฌ์์ค๋ฅผ ์ค์ด๊ณ , ์ฑ์ ์ฑ๋ฅ์ ๊ฐ์ ํ ์ ์๋๋ก ํด์ฃผ๋ ์ค์ํ ์์ ์ธ ๊ฒ ๊ฐ์ต๋๋ค. ํนํ ๋น๋๊ธฐ ์์ ๊ณผ ๋งค์ฐ ๋ฐ์ ํ ๊ด๋ จ์ด ์์ฃ . ์๋ง์ ์คํ์์ค, ๊ทธ๋ฆฌ๊ณ ๋น์ฅ Combine๊ณผ ๊ฐ์ ํ๋ ์์ํฌ๋ง ํ๋๋ผ๋ ์ทจ์ ๊ฐ๋ฅํ ํ์ ์ ์ ์ํด๋๊ณ ์ฌ์ฉํฉ๋๋ค. ํ ๋ฒ์ ๊ณ ๋ฏผํด๋ณด๊ณ ๋์ด๊ฐ ์ค์ํ ์ง์ ์ด๋ผ๊ณ ์๊ฐ์ด ๋๋ค์.
'๐ iOS & Swift' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[iOS] commit hitch ์ ๊ฑฐํ๊ธฐ (6) | 2023.10.26 |
---|---|
[iOS] ๋ฐ๋์ ๋์ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋ 91% ๊ฐ์์ํค๊ธฐ (2) | 2023.09.07 |
[Swift] Stored Property vs Computed Property vs Method (2) | 2022.11.04 |
[iOS] ๋คํธ์ํฌ ํต์ ํบ์๋ณด๊ธฐ๋ฅผ ์์ํ๊ธฐ ์ ์(0) (3) | 2022.11.04 |
[RxSwift] Disposable๊ณผ DisposeBag (0) | 2022.10.26 |