suvera-dev ๐Ÿฅฆ

iOS ) GCD ์‚ฌ์šฉ์‹œ ์ฃผ์˜ํ•ด์•ผํ•  ์‚ฌํ•ญ ๋ณธ๋ฌธ

iOS

iOS ) GCD ์‚ฌ์šฉ์‹œ ์ฃผ์˜ํ•ด์•ผํ•  ์‚ฌํ•ญ

suvera 2022. 2. 6. 01:08

1) ๋ฐ˜๋“œ์‹œ ๋ฉ”์ธํ์—์„œ ์ฒ˜๋ฆฌํ•ด์•ผํ•˜๋Š” ์ž‘์—… : UI๊ด€๋ จ์ผ๋“ค์€ '๋ฉ”์ธํ' ์—์„œ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•œ๋‹ค. 

DispatchQueue.global().async{
	// ์ด๋ฏธ์ง€ ๋‹ค์šด๋กœ๋“œ ๋“ฑ ๊ด€๋ จ ์ฝ”๋“œ 
    // ์˜ค๋ž˜๊ฑธ๋ฆฌ๋Š” ์ž‘์—…์ด๋‹ˆ, ๋น„๋™๊ธฐ๋กœ ๋ถ„์‚ฐํ•ด์„œ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•˜๊ณ  ์‹ถ์Œ 
    ์ฝ”๋“œ 1
    ์ฝ”๋“œ 2
    ...
    
    DispatchQueue.main.async{
   		// ๋‹ค์šด๋กœ๋“œํ•œ ์ด๋ฏธ์ง€๋ฅผ ํ‘œ์‹œํ•˜๋Š” ์ฝ”๋“œ 
        // UI ๊ด€๋ จ ์ž‘์—…์€ ๋‹ค์‹œ ๋ฉ”์ธํ๋กœ 
        self.imageView.image = image
        }
}

๋‚ด๋ถ€์ ์œผ๋กœ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๊ฐ€ ๋˜์–ด์žˆ๋Š” URLSession ์ฝ”๋“œ์—์„œ๋„ ๋‹ค์‹œ main ํ๋กœ ๋ณด๋‚ธ๋‹ค. 

// ์ด๋ฏธ์ง€์บ์‹œ ์ฒ˜๋ฆฌํ•˜๋Š” ์˜ˆ์ œ
var imageCache = [String: UIImage]()

class CustomImageView: UIImageView {
    
    var lastImgUrlUsedToLoadImage: String?
    
    func loadImage(with urlString: String) {
        
        self.image = nil
        
        // ๋งˆ์ง€๋ง‰์œผ๋กœ ์ด๋ฏธ์ง€๋ฅผ ๋‹ค์šด๋กœ๋“œํ•œ String๊ฒฝ๋กœ
        lastImgUrlUsedToLoadImage = urlString
        
        // ์ด๋ฏธ์ง€๊ฐ€ ์บ์‹œ์— ๋“ค์–ด ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๊ธฐ
        if let cachedImage = imageCache[urlString] {
            self.image = cachedImage
            return
        }
        
        // url
        guard let url = URL(string: urlString) else { return }
        
        // ๐ŸŽพ URL์„ธ์…˜์€ ๋‚ด๋ถ€์ ์œผ๋กœ ๋น„๋™๊ธฐ๋กœ ์ฒ˜๋ฆฌ๋œ ํ•จ์ˆ˜์ž„.
        URLSession.shared.dataTask(with: url) { (data, response, error) in

            if let error = error {
                print("Failed to load image with error", error.localizedDescription)
            }
            
            if self.lastImgUrlUsedToLoadImage != url.absoluteString {
                return
            }
            
            guard let imageData = data else { return }
            
            let photoImage = UIImage(data: imageData)
            
            imageCache[url.absoluteString] = photoImage
            
            // ๐ŸŽพ ์ด๋ฏธ์ง€ ํ‘œ์‹œ๋Š” DispatchQueue.main์—์„œ ๐ŸŽพ
            DispatchQueue.main.async {
                self.image = photoImage
            }
            
        }.resume()
    }
}

 

 

2) sync๋ฉ”์„œ๋“œ์— ๋Œ€ํ•œ ์ฃผ์˜์‚ฌํ•ญ : sync ๋ฉ”์„œ๋“œ์™€ ๊ด€๋ จํ•ด ์ ˆ๋Œ€ ํ•ด์„œ๋Š” ์•ˆ๋˜๋Š” ์ฝ”๋“œ 2๊ฐ€์ง€ 

- ๋ฉ”์ธํ์—์„œ๋Š” ๋‹ค๋ฅธ ํ๋กœ ๋ณด๋‚ผ ๋•Œ sync ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์„œ๋Š” ์•ˆ๋œ๋‹ค

- ๋ฉ”์ธํ์—์„œ๋Š” ํ•ญ์ƒ ๋น„๋™๊ธฐ์ ์œผ๋กœ ๋ณด๋‚ด์•ผํ•œ๋‹ค. 

 

- ํ˜„์žฌ์˜ ํ์—์„œ ํ˜„์žฌ์˜ ํ๋กœ ' ๋™๊ธฐ์ ์œผ๋กœ ' ๋ณด๋‚ด์„œ๋Š” ์•ˆ๋œ๋‹ค.

- ํ˜„์žฌ์˜ ํ๋ฅผ ๋ธ”๋ฝํ•˜๋Š” ๋™์‹œ์— ๋‹ค์‹œ ํ˜„์žฌ์˜ ํ์— ์ ‘๊ทผํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ต์ฐฉ์ƒํ™ฉ ๋ฐœ์ƒ 

 

 

 

3) weak, strong ์บก์ฒ˜ ์ฃผ์˜ 

- ARC, ํด๋กœ์ € ์บก์ฒ˜ ๊ด€๋ จ ๊ณต๋ถ€ํ•˜๊ธฐ 

DispatchQueue.global(qos:.utility).async{[weak self] in
	guard let self = self else { return }
    
    DispatchQueue.main.async{
    	self.textLabel.text = "new posts updated!"
    }
}

 

 

 

4) ๋น„๋™๊ธฐ ์ž‘์—…์—์„œ ์ปดํ”Œ๋ฆฌ์…˜ํ•ธ๋“ค๋Ÿฌ์˜ ์กด์žฌ์ด์œ  

- ๋น„๋™๊ธฐ๋กœ ์ž‘์—…์„ ์‹œํ‚ค๊ณ  ๋‚˜์„œ, ์ž‘์—…์— ํ•ด๋‹นํ•˜๋Š” ๊ฐ’์„ ๋ฐ”๋กœ ์‚ฌ์šฉํ•˜๋ฉด ์•ˆ๋œ๋‹ค. 

- ์ž‘์—…์ด ์•„์ง ์ข…๋ฃŒ๋˜์ง€ ์•Š์•˜๋Š”๋ฐ ํ•ด๋‹น ๊ฐ’์— ์ ‘๊ทผํ•˜๋ฉด, ์ž˜๋ชป๋œ ๊ฐ’์„ ์‚ฌ์šฉํ•  ํ™•๋ฅ ์ด ๋†’๋‹ค

- ๊ทธ๋ž˜์„œ ํ•ด๋‹น ๋น„๋™๊ธฐ ์ž‘์—…์ด ๋๋‚ฌ๋‹ค๋Š” ๊ฒƒ์„ ์ •ํ™•ํžˆ ์•Œ๋ ค์ฃผ๋Š” ์‹œ์ ์ด ์ปดํ”Œ๋ฆฌ์…˜ ํ•ธ๋“ค๋Ÿฌ

 

 

 

5) ๋™๊ธฐ์  ํ•จ์ˆ˜๋ฅผ ๋น„๋™๊ธฐํ•จ์ˆ˜ ์ฒ˜๋Ÿผ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ• 

- ์—ฌ๋Ÿฌ๋ฒˆ ์žฌํ™œ์šฉํ•˜๊ธฐ ์œ„ํ•ด 

- URLSession๊ณผ ๊ฐ™์€ ์ด๋ฏธ ๋น„๋™๊ธฐ ํ•จ์ˆ˜๋Š” GCD/Operation์ด ํ•„์š”์—†๋‹ค

 

 

 

 

 

๐Ÿงธ weak self ์ถ”๊ฐ€ ๊ณต๋ถ€ 

 

- ARC(Automatic Reference Counting) : ์ž๋™ ์ฐธ์กฐ ์นด์šดํŒ…

- Heap(ํž™)๋ฉ”๋ชจ๋ฆฌ์— ํ• ๋‹น๋˜๋Š” ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•ด ARC ๋ฐฉ๋ฒ•์œผ๋กœ ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ => ๊ฐ•ํ•œ ์ฐธ์กฐ ์‚ฌ์ดํด์ด ์ผ์–ด๋‚  ๊ฐ€๋Šฅ์„ฑ(Memory Leak)

- weak / unowned ์‚ฌ์šฉํ•ด์„œ ํ•ด๊ฒฐ

- ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค(๊ฐ์ฒด), ํด๋กœ์ € => ํž™ ๋ฉ”๋ชจ๋ฆฌ์— ํ• ๋‹น

 

 

1) ํด๋ž˜์Šค ์ธ์Šคํ„ด์Šค

- ๋ณ€์ˆ˜๋ฅผ weak, unowned๋กœ ์„ ์–ธ

=> ์ธ์Šคํ„ด์Šค๋ฅผ ์ฐธ์กฐํ•˜๋˜, RC๊ฐ€ ์˜ฌ๋ผ๊ฐ€์ง€ ์•Š๊ฒŒ ํ•˜๋ฏ€๋กœ ๊ฐ•ํ•œ ์ฐธ์กฐ ์‚ฌ์ดํด ์ผ์–ด๋‚˜์ง€ ์•Š์Œ

 

 

2) ํด๋กœ์ €

- ํด๋กœ์ €์˜ ์บก์ฒ˜๋ฆฌ์ŠคํŠธ๋‚ด์—์„œ + weak, unowned๋กœ ์„ ์–ธ

=> ์ธ์Šคํ„ด์Šค๋ฅผ ์ฐธ์กฐํ•˜๋˜, RC๊ฐ€ ์˜ฌ๋ผ๊ฐ€์ง€ ์•Š๊ฒŒ ํ•˜๋ฏ€๋กœ ๊ฐ•ํ•œ ์ฐธ์กฐ ์‚ฌ์ดํด ์ผ์–ด๋‚˜์ง€ ์•Š์Œ

 

- ํด๋กœ์ €์—์„œ weak self ์‚ฌ์šฉ ์˜ˆ์‹œ + guard ๋ฌธ ์‚ฌ์šฉํ•˜์—ฌ ์˜ต์…”๋„ ์ฒ˜๋ฆฌ 

class ViewController2: UIViewController {
    
    var name: String = "๋ทฐ์ปจ"
    
    func doSomething() {
        // ๊ฐ•ํ•œ ์ฐธ์กฐ ์‚ฌ์ดํด์ด ์ผ์–ด๋‚˜์ง€ ์•Š์ง€๋งŒ, ๊ตณ์ด ๋ทฐ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ๊ธธ๊ฒŒ ์žก์•„๋‘˜ ํ•„์š”๊ฐ€ ์—†๋‹ค๋ฉด
        // weak self๋กœ ์„ ์–ธ
        DispatchQueue.global().async { [weak self] in
            sleep(3)
            guard let weakSelf = self else { return }
            print("๊ธ€๋กœ๋ฒŒํ์—์„œ ์ถœ๋ ฅํ•˜๊ธฐ: \(weakSelf.name)")
            DispatchQueue.main.async {
                print("๋ฉ”์ธํ์—์„œ ์ถœ๋ ฅํ•˜๊ธฐ: \(weakSelf.name)")
            }
        }
    }
    
    deinit {
        print("\(name) ๋ฉ”๋ชจ๋ฆฌ ํ•ด์ œ")
    }
}


func localScopeFunction2() {
    let vc = ViewController2()
    vc.doSomething()
}


localScopeFunction2()

 

 

 

 

 

์•จ๋Ÿฐ๋‹˜์˜ ๋™์‹œ์„ฑ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๊ฐ•์˜๋ฅผ ์ฐธ๊ณ ํ•˜์—ฌ ์ •๋ฆฌํ•˜์˜€์Šต๋‹ˆ๋‹ค ! 

 

 

iOS Concurrency(๋™์‹œ์„ฑ) ํ”„๋กœ๊ทธ๋ž˜๋ฐ, ๋™๊ธฐ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ๊ทธ๋ฆฌ๊ณ  GCD/Operation - ๋””์ŠคํŒจ์น˜ํ์™€ ์˜คํผ๋ ˆ์ด์…˜

๋™์‹œ์„ฑ(Concurrency)ํ”„๋กœ๊ทธ๋ž˜๋ฐ - iOSํ”„๋กœ๊ทธ๋ž˜๋ฐ์—์„œ ํ•„์š”ํ•œ ๋™๊ธฐ, ๋น„๋™๊ธฐ์˜ ๊ฐœ๋… ๋ฐ ๊ทธ๋ฅผ ํ™•์žฅํ•œ GCD ๋ฐ Operation์— ๊ด€ํ•œ ๋ชจ๋“  ๋‚ด์šฉ์„ ๋‹ค๋ฃน๋‹ˆ๋‹ค., - ๊ฐ•์˜ ์†Œ๊ฐœ | ์ธํ”„๋Ÿฐ...

www.inflearn.com

 

'iOS' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

iOS) WKWebView  (0) 2022.03.28
iOS) Modal dismissํ•œ ํ›„ CollectionView reload ํ•˜๊ธฐ  (0) 2022.03.28
iOS ) URLSession ์•Œ์•„๋ณด๊ธฐ  (2) 2022.02.28
iOS ) iOS 15 UIButton.ConfigurationUpdateHandler  (0) 2022.02.05
iOS) CollectionView Cell - Drag & Drop  (0) 2022.02.01
Comments