Alamofire 활용하여 내 Github 만들기 (완)

어제 마무리하지 못한 Github만들기가 오늘 성공했다 🙂

어제 왜 데이터가 연결되지 않았는지 살펴보고 새로운 라이브러리인 Kingfisher도 사용해봐서 이 내용을 정리 해보고자 한다!


Github 인포 부분

Github API는 두 부분을 나눠 가져왔다, 먼저 어제 실패한 유저 정보를 가져오는 데이터를 살펴보자!

let url = "<https://api.github.com/users/SijongKim93>"

func fetchUser(completion: @escaping ((Result<githubuser, error="">) -> Void)) {
    let url = "\\(self.url)"
    
    AF.request(url).responseDecodable(of: GithubUser.self) { response in
        switch response.result {
        case .success(let user):
            completion(.success(user))
        case .failure(let error):
            completion(.failure(error))
        }
    }
}
</githubuser,>

Alamofire를 사용해 데이터를 요청하는 코드는 이렇게 구성되었다.

 

어제 데이터가 제대로 전달되지 않았던 이유는 VC에서 데이터를 다시 가져와 등록된 컴포넌트들과 연결이 제대로 되지 않았기 때문에 발생한 오류였다.

func fetchUserData() {
    networkingManager.fetchUser { [weak self] result in
        guard let self = self else { return }
        switch result {
        case .success(let user):
            self.userInfo = user
            DispatchQueue.main.async {
                self.updataUserUI(with: user)
            }
        case .failure(let error):
            print("데이터를 가져오는데 실패했습니다: \\(error)")  // 예외처리는 이용자도 어떤게 실패한건지 알 수 있게
        }
    }
}

func updataUserUI(with user: GithubUser) {
    nameLabel.text = user.login
    akaLabel.text = user.name
    introduceLabel.text = user.bio
    
    let imageUrlString = user.avatarUrl
    if let imageUrl = URL(string: imageUrlString) {
        mainImage.kf.setImage(with: imageUrl)
        mainImage.layer.cornerRadius = mainImage.frame.width / 2
        mainImage.clipsToBounds = true
    } else {
        print("실패했습니다.")
    }
}

이렇게 코드를 넣어주니 정상적으로 데이터를 연결할 수 있었다.

 

updataUserUI 쪽을 통해 받아온 데이터 user 와 현재 컴포넌트들을 연결하였다. 이 과정에서 이미지는 url 로 받아오기 때문에 이를 String으로 바꿔주는 Kingfisher를 사용하였다.

 

Kingfisher 를 사용한 부분만 다시 한번 보면

let imageUrlString = user.avatarUrl
if let imageUrl = URL(string: imageUrlString) {
    mainImage.kf.setImage(with: imageUrl)
    mainImage.layer.cornerRadius = mainImage.frame.width / 2
    mainImage.clipsToBounds = true
} else {
    print("실패했습니다.")
}

먼저 API 에는 URL로 가져오기 때문에 이를 일단 가져와서 String으로 바꿔주는 과정이다.

 

확실히 라이브러리를 사용하니 편하게 변경하여 스토리 보드에 이미지가 들어갈 부분인 mainImage에 원하는 이미지를 넣을 수 있었다.

이렇게 데이터를 요청해 VC로 가져와 연결해주니 사진과 같이 원하는 정보가 잘 들어가는 걸 볼 수 있다.

Github 레포지토리 부분

이제 인포를 다 구현했으니 테이블 뷰를 활용해 내 레포지토리를 가져와 연결해보자!

 

위에 인포와 동일하게 데이터를 먼저 요청하자

let urlreop = "<https://api.github.com/users/SijongKim93/repos>"

func fetchRepo(completion: @escaping (Result<[GithubRepository], Error>) -> Void) {
    let urlRepo = "\\(self.urlreop)"
    
    AF.request(urlRepo).responseDecodable(of: [GithubRepository].self) { response in
        switch response.result {
        case .success(let repo):
            completion(.success(repo))
        case .failure(let error):
            completion(.failure(error))
        }
    }
}

이렇게 데이터를 가져와서 정상적으로 연결 할 수 있었으나 원래는 딱 한부분 때문에 애를 많이 먹었다.

 

어떤 부분이냐면 GithubRepository 의 데이터 모델링은 테이블 뷰에 넣을 예정이기 때문에 데이터 모델링을 배열로 잡았어야 했는데 배열로 잡지 않고 이렇게 잡아 두니 제대로 연결이 되지 않았다.

// 변경 전 연결 오류
func fetchRepo(completion: @escaping (Result<GithubRepository, Error>) -> Void) {
    let urlRepo = "\\(self.urlreop)"
    
    AF.request(urlRepo).responseDecodable(of: GithubRepository.self) { response in
    
    
    
// 변경 후 정상적으로 연결
func fetchRepo(completion: @escaping (Result<[GithubRepository], Error>) -> Void) {
    let urlRepo = "\\(self.urlreop)"
    
    AF.request(urlRepo).responseDecodable(of: [GithubRepository].self) { response in

변경 전의 코드를 보면 GithubRepository 부분을 배열로 감싸주지 않아 한동안 애를 먹었다.

배열로 연결된다는 것을 깨닫고 배열로 바꿔주니 생각보다 쉽게 연결이 완료되었다!

func fetchUserRepo() {
    networkingManager.fetchRepo { [weak self] result in
        guard let self = self else { return }
        switch result {
        case .success(let repo):
            self.userRepo = repo
            DispatchQueue.main.async {
                self.mainTableView.reloadData()
            }
        case.failure(let error):
            print("데이터 가져오는데 실패: \\(error)")
        }
    }
}

VC로 넘어와 이제 레포지토리를 가져와 테이블 뷰에 연결할 수 있도록 데이터를 연결하는 함수를 넣어주니 데이터는 정상적으로 들어갔다 🙂

 

이제야 좀 익숙해진 테이블 뷰를 구성해보자

extension ViewController: UITableViewDelegate, UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        userRepo.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: "tableViewCell", for: indexPath) as? TableViewCell else {
            fatalError("오류")
        }
        
        let repo = userRepo[indexPath.row]
        
        cell.cellTitle.text = repo.name
        cell.cellDescription.text = repo.description
        
        return cell
    }
}

이렇게 데이터를 연결하니 쉽게 구현이 가능할거라고 생각했다! 그렇지만.. 생각치도 못한 부분에 오류가 발생했다..

 

계속해서 테이블 뷰 셀에서 연결이 제대로 되지 않았다는 오류가 발생했기 때문..

 

이전에 구성했던 테이블 뷰들과 비교해봐도 잘못된 부분이 없고 다 넣었는데 대체 뭐가 문제 인지 알 도리가 없었다..

 

그래서 튜터님을 찾아가니 해답을 알 수 있었다..

그것은 바로

mainTableView.register(TableViewCell.self, forCellReuseIdentifier: "tableViewCell")

여기에 문제가 있었다..

사진을 보면 스토리 보드에 테이블 뷰를 넣어두고 셀에 레이블을 넣어놨다. 이전에는 그냥 셀만 넣어두고 그 안에 레이블은 코드로 구현하는 경우가 많았지만 이번엔 그냥 귀찮아서 스토리보드에 구성을 하고 원래대로 register를 통해 셀을 연결했다.

 

근데 당연히 넣어야한다고 생각했던 register에서 문제가 발생했다..

내가 스토리보드에 이미 레이블을 넣어놨으니 이건 이미 연결이 된 상태였던 것이었다.

 

그래서 register를 또 넣으니 이게 중복으로 들어간거라 오류가 발생했던 것이었다.

 

이 부분을 제거하니 오류가 해결되고 이렇게 데이터가 연결될 수 있었다.. 뿌듯하네..

이번에 진행한 github 만들기를 통해 다양한 API를 활용해보고 네트워킹하는 과정을 다시 한번 해보면서 한번 더 경험해볼 수 있었다.