본문 바로가기
Xcode/Swift - PlayGround

PlayGround) DispatchGroup이란???

by 후르륵짭짭 2020. 11. 8.
728x90
반응형

 

안녕하세요 후르륵짭잡 입니다!

오늘은 DispatchGroup이라는 것을 가져왔습니다!

사실 DispatchGroup을 아직 실제로 사용해본 적은 없습니다.

그런데 대용량 처리를 할 때는 자주 사용할 것 같은 기술이라는 느낌을 많이 받았습니다.

 

** DispatchGroup 이란 **

DispatchGroup은 작업의 그룹 이라 칭하고 있습니다.

그리고 Over View를 보면  Group은 하나의 작업으로 모아주고 하나의 그룹의 행동으로 동기화 시켜준다고 되어 있습니다.

즉, 하나의 그룹으로 동기화 시켜주는 작업을 의미합니다!

 

** 사용하기 ** 

만약, 우리가 Networking 작업을 사용하는데, 여러개의 이미지를 다운 받고 난 다음에

화면에 보여주기 위해서는 하나하나 DispatchQueue를 사용한다.

그런데,,, 각각의 이미지 용량이 다르기 때문에 끝나는 순서를 알 수가 없다,,,

이럴 때! DispatchGroup을 이용하면 된다!!!

DispatchGroup은 하나의 작업을 묶어서 그 묶음의 작업이 모두 종료 될 때 작동 할 수 있게 한다.

class ViewController: UIViewController {
    
    @IBOutlet weak var tableView: UITableView!
    
    var items : [String] = []
    
    let inputDatas : [[String]] = [["1 : Swift", "Xcode"], ["2: JAVA", "Eclips"], ["3: C++", "Visual Studio"]]
    
    let times : [Int] = [2,5,3]
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        
        setDelegate()
    }

    @IBAction func downLoadBtn(_ sender: UIButton) {
        
//        fetchItemsWithNormal()
        fetchItmesWithGroup()
    }
    
}

//ETC Function
extension ViewController {
    
    func run(time : Int , completeHandler : @escaping () -> ()){
        
        let dispatchTime : DispatchTime = .now() + .seconds(time)
        
        DispatchQueue.global().asyncAfter(deadline: dispatchTime) {
            completeHandler()
        }
    
    }
    
    //일반적인 DispatchQueue 사용한 방법
    func fetchItemsWithNormal(){,,,}
    //DispatchGroup을 사용한 방법
    func fetchItmesWithGroup(){,,,}
    
    
}

extension ViewController : UITableViewDelegate , UITableViewDataSource {
    
    //위임을 받도록 한다.
    func setDelegate(){
        tableView.delegate = self
        tableView.dataSource = self
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return items.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
        guard let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") as? TableViewCell else {return UITableViewCell()}
        
        cell.updateLabel(text: items[indexPath.row])
        
        return cell
    }
    
}


class TableViewCell : UITableViewCell {
    
    @IBOutlet weak var label : UILabel!
    
    override func prepareForReuse() {
        label.text = nil
    }
    
    func updateLabel(text : String){
        label.text = text
    }
    
}

일반적인 셋팅을을 저렇게 했을 때, 우리가 주목해야할 부분은 fetchItemsWithNormal() 과 fetchItmesWithGroup()의 차이 이다.

 

fetchItemsWithNormal()함수는 일반적인 DispatchQueue방법으로 했을 때 발생하는 문제점을 보도록 하겠다.

func fetchItemsWithNormal(){
    
        for (index ,input) in inputDatas.enumerated() {
            
            run(time: times[index]) {
                self.items.append(contentsOf: input)
                
                print("Complete fetch Data \(index) : \(self.times[index])")
                
                    DispatchQueue.main.async {
                        self.tableView.reloadData()
                    }
                    
            }
            
        }
        
    }

이 코드를 보면 run()이 끝날 때 매번 main 함수랑 reloadData()를 수행하는 것을 알 수 있습니다. 

이렇게 코드와 자원 낭비를 하게 되는 이유는 각각의 데이터가 언제 수행을 마치는 알 수 없기 때문 입니다.

따라서 이런 경우에 DispatchGroup을 사용하면 좋습니다.

 func fetchItmesWithGroup(){
        
        let dispatchGroup = DispatchGroup()
        
        for (index ,input) in inputDatas.enumerated() {
            
            dispatchGroup.enter()
            run(time: times[index]) {
                self.items.append(contentsOf: input)
                print("Complete fetch Data \(index) : \(self.times[index])")
                dispatchGroup.leave()
            }
            
        }
        
        dispatchGroup.notify(queue: .main) {
            self.tableView.reloadData()
        }
        
        
    }

일단 DispatchGroup 객체를 생성 해줍니다!

그리고 각 Background 작업을 수행하기 전에 enter()라는 함수를 수행 시켜 주고 끝나면 leave()를 수행 합니다.

애플 공식 문서에 저렇게 정의가 되어 있습니다.

그러니깐 enter()는 DispatchGroup에 넣어주는 것이고 leave()는 그룹의 작업이 마쳤을 때, Group에서 나오도록 하는 것 입니다.

그리고 마지막에 포문 밖에 notify() 함수를 줬습니다.

즉, group안에 어떠한 작업도 남아 있지 않으면 우리가 수행한 작업을 수행하는 것 입니다.

결국 위에서 적은 코드를 보면 inputDatas 작업을 모두 끝 마쳤을 때, notify함수가 작동 하고 그 때 tableView에 보여주도록 한 것 입니다.

 

이렇게 DispatchGroup에 대해서 알아 봤습니다.

이것 외에도 DispatchWorkItem과 세마포어도 있으니, 나중에 공부하고 알려드리겠습니다.

 

소스 코드 :

github.com/HururuekChapChap/Xcode_TestProj/tree/master/DispatchGroup_Tuto/DispatchGroup_Tuto

 

참고 사이트 :

동영상 강의 1

www.youtube.com/watch?v=4zsNgBhDs0M

 

동영상 강의 2

www.youtube.com/watch?v=lOI0aUkeuLw

 

애플 공식 문서

developer.apple.com/documentation/dispatch/dispatchgroup

 

Apple Developer Documentation

 

developer.apple.com

 

728x90
반응형

댓글