XLOG

원티드 프리온보딩 챌린지 iOS 2차과정 사전 과제 본문

Swift/UIKit

원티드 프리온보딩 챌린지 iOS 2차과정 사전 과제

X_PROFIT 2023. 2. 26. 16:45

https://yagomacademy.notion.site/iOS-2-3f670cc9788f4384b000bfe940447d59

 

원티드 프리온보딩 챌린지 iOS 2차과정 사전과제

- 사전과제는 자신의 GitHub의 공개 저장소에 작성하여 링크를 전달주세요. [제출 링크] - 사전 과제는 챌린지를 준비하며 스스로의 학습 수준을 점검하기 위한 용도입니다. - 학습 커리큘럼은 사

yagomacademy.notion.site

 

커리어 전환을 위해 작년 Apple Developer Academy 1기를 수료 후, 취업 준비를 하는도중 원티드에서 프리온보딩 iOS 챌린지가 열린다는 소식을 들었다. 참가신청을 하려고 했더니 동시성 프로그래밍 관련 과제가 있었다.

 

과제는 GCD 를 이용하여 이미지를 불러오는 것이었다. 사실 동시성 프로그래밍이란 조건만 붙었더라면 가독성이 훨씬 좋은 concurrency를 쓸까 생각했지만.....

 

많은 기업들이 동시성 프로그래밍을 중요시 생각한다. 애플 HIG 에서도 유저와의 Interaction 은 끊어지면 안된다고 한다. 

그렇기에 iOS 에서는 메인스레드가 UI 업데이트를 담당하기를 권장한다.

 

과제에서 이미지는 웹의 이미지를 다운로드 받는 것으로 구현한다고 한다.

 

URLSession 은 자체적으로 background 동작을 한다고 한다. 그렇다면 나는 data 를 받아와서 UIImage를 반환하는 함수를 만들고, 동작시 UIImageView의 view를 바꿔주는 작업만 main thread에서 진행을 하면 될 것으로 보인다.

 

우선 네트워크 모델에서 URLSession을 이용하여 이미지 데이터를 다운로드 후 컴플리션 핸들러를 이용하여 image를 셋팅해주는 함수를 만들었다.

    func fetchImage(from url: String, completion: @escaping (UIImage) -> ())  {
        let url = URL(string: url)!
        let dataTask = URLSession.shared.dataTask(with: url, completionHandler: { data, _, error in
            guard let data = data, error == nil else { return }
            guard let image = UIImage(data: data) else { return }
            completion(image)
        })
        dataTask.resume()
    }

 

그 후 ViewController 에서 load all images 버튼과, 각 버튼의 기능을 추가해줘야 했다.

또한 Delegate 패턴을 사용하여 각 셀의 버튼을 ViewController의 액션과 연결해주었다.

    @objc func fetchImages() {
        for i in 0..<stringData.count {
            model.fetchImage(from: stringData[i], completion: { image in
                self.images[i] = image
                DispatchQueue.main.async {
                    self.collectionView.reloadItems(at: [IndexPath(row: i, section: 0)])
                }
                
            })
        }
    }
    
    
    
    
    
    extension ViewController: CustomDelegate {
    func fetchImage(_ index: IndexPath) {
        model.fetchImage(from: stringData[index.row], completion: { image in
            self.images[index.row] = image
            DispatchQueue.main.async {
                self.collectionView.reloadItems(at: [index])
            }
        })
    }
}

여기서 reloadData가 아닌 reloadItems 를 사용한 이유는, 영상에서 전체 load하는 버튼을 클릭하면 이미지가 다운로드되는 순서대로 collectionView의 이미지를 세팅해줘야 했다. reloadData의 경우 컬렉션뷰 전체를 새로 고치기 때문에 비효율적이라고 생각했다.

 

또한 컬렉션뷰 아이템을 새로고치는 작업은 UI를 업데이트 하는 것이니 main thread에서 동작하게 하였다.

 

물론 DiffableDataSource 를 이용하여, 바뀐 데이터에 대한 부분에 대해서 수정하도록 하는 방법도 있을 것이라 생각한다.

하지만 과제 제출기간이 있으니, 우선 제출 후 Diffable Data Source를 적용해 보도록 해야겠다.

 

 

전체코드: https://github.com/profit0124/WantedFreeOnBoarding1/tree/main