스파르타 코딩 클럽 - iOS 스타터 6기/본 캠프

34. 스파르타 코딩 클럽 - 포켓몬 연락처 앱 만들기 (1)

seongpil Heo 2025. 4. 17. 21:52

  📞  PokeAPI를 사용해서 연락처 앱 만들기

PokéAPi

 

PokéAPI

Try it now! Need a hint? Try pokemon/ditto, pokemon-species/aegislash, type/3, ability/battle-armor, or pokemon?limit=100000&offset=0. Direct link to results: https://pokeapi.co/api/v2/pokemon/ditto Resource for ditto { "abilities": [ { "ability": { "name"

pokeapi.co

PokeAPI를 사용하여 포켓몬 이미지를 랜덤으로 받아온 뒤 연락처 앱에서 이미지로 사용할 예정이다.

  💾  데이터 저장은 CoreData를 사용

 

CoreData를 사용해서 사용자가 입력한 연락처들을 내부저장소에 저장해서 사용 할 예정이다.


 🧑‍💻 오늘까지 진행한 요구사항

 

오늘은 Level 1 ~ 3까지 진행하였는데

데이터 통신과 CoreData를 사용하여 C.R.U.D 기능을 구현하기 전에

기본적인 연락처 앱의 UI를 만드는 작업이다.

 

[ ViewController ]

// 연락처를 표시할 테이블 뷰
    private lazy var tableView: UITableView = {
        let tableView = UITableView()
        tableView.register(ContactsTableViewCell.self, forCellReuseIdentifier: ContactsTableViewCell.identifier)
        tableView.dataSource = self
        tableView.delegate = self
        return tableView
    }()

테이블 뷰를 하나 만들고, register과 dataSource와 delegate를 self로 지정하였다.

extension ViewController: UITableViewDelegate, UITableViewDataSource {
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 70
      
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        testData.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: ContactsTableViewCell.identifier, for: indexPath) as? ContactsTableViewCell else { return UITableViewCell() }
        cell.configureUI()
        let contact = testData[indexPath.row]
        cell.nameLabel.text = contact.name
        cell.phoneNumberLabel.text = contact.phoneNumber
        return cell
    }
    
}

ViewController는 UITableViewDelegate와 UITableViewDataSource를 채택하여 아래에서 필수 메서드를 구현하였다.

테이블 뷰는 ContactsTableViewCell을 새로 만들어서 Custom 테이블 뷰로 제작하였다.

테이블의 Row의 개수는 더미 데이터로 테스트 해보았기 때문에

testData배열의 count만큼 만들었다.

 

// 추가 버튼
    private lazy var button: UIButton = {
        let button = UIButton()
        button.setTitle("추가", for: .normal)
        button.setTitleColor(.blue, for: .normal)
        button.addTarget(self, action: #selector(buttonTapped), for: .touchDown)
        return button
    }()

@objc private func buttonTapped() {
        print("버튼 클릭")
        self.navigationController?.pushViewController(ContactsViewController(), animated: true)
    }

그리고 버튼을 클릭했을 때 이벤트 컨트롤로 buttonTapped()라는 함수를 하나 작성하였고,

추가 버튼을 클릭했을 때, pushViewController메서드를 이용해서 ViewController에서 ContactsViewController로 화면을

이동시켜주는 기능을 구현하였다.

[ 🎯 Trouble Shooting 1 ]

평화롭게 UI를 배치하고 코드를 작성하는 중에 문제가 발생했다.

 

이번에는 여러개의 ViewController를 사용하다 보니 UINavigationController를 사용하였는데

네비게이션 컨트롤러를 사용하면 자동으로 화면 위쪽 다이나믹 아일랜드 아래 부분에 투명하게 네비게이션바 영역이 잡혀버린다.

 

 

View Hierarchy로 살펴보면 파란색 부분의 네비게이션 바 영역이 잡혀서 친구 목록 라벨과 추가 버튼이

내가 생각했던 위치보다 아래로 위치하게 되는 문제가 있었고, 네비게이션 바에 추가 버튼이 가려져서

버튼 클릭이 되지 않는 문제도 있었다.

 

이 문제를 해결하기 위해 튜터님께 방문했는데

튜터님께서 아래와 같은 힌트를 주셨다.

self.navigationController?.navigationBar.isHidden = true

 

이 코드는 해당 네비게이션 바를 숨길 수 있는 코드인데

뷰의 생명주기를 잘 사용하여 코드를 작성하면 네비게이션 바가 필요한 뷰 컨트롤러에서는 보이게 설정하고,

네비게이션 바가 필요없는 뷰 컨트롤러에서는 안 보이게 설정할 수 있다고 하셨다.

 

override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        self.navigationController?.navigationBar.isHidden = true
    }

 

그래서 ViewController 에서는 viewWillAppear (뷰가 화면에 나타나기 직전에 호출되는 메서드) 에서

네비게이션 바의 isHidden의 값을 true로 설정하면서 두가지의 문제를 해결하였다.


[ ContactsViewController ]

override func viewDidLoad() {
        super.viewDidLoad()
        self.navigationController?.navigationBar.isHidden = false
        configureUI()
    }
    
    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        self.navigationController?.navigationBar.isHidden = true
    }

ContactsViewController에서는 네비게이션 바가 필요하기 때문에

ViewDidLoad 부분에는 isHidden을 false를 주고

ViewDidDisappear 부분에는 isHidden을 true를 주었다.

 

@objc private func naviButtonTapped() {
        print("네비게이션 버튼 클릭")
        self.navigationController?.popViewController(animated: true)
    }

사용자가 네비게이션 우측에 있는 추가 버튼을 클릭했을 때는 navigationController?.popViewController 메서드를 사용하여

현재 네비게이션 컨트롤러에서 push 된 뷰 컨트롤러를 pop하여 제거하는 기능으로

이전에 있던 화면으로 돌아가도록 구현하였다.

 

private func configureUI() {

        view.backgroundColor = .white
        // 네비게이션 타이틀 작성
        self.title = "연락처 추가"  
        // 네비게이션 우측 버튼 만들기
        self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "적용", style: .plain, target: self, action: #selector(naviButtonTapped))
        
        // 이미지 뷰를 원형으로 만들기
        circleImageView.layer.cornerRadius = 75
        circleImageView.clipsToBounds = true
        circleImageView.contentMode = .scaleAspectFill
        // 이미지 뷰의 테두리 선을 gray 색상으로
        circleImageView.layer.borderColor = UIColor.gray.cgColor
        // 이미지 뷰의 테두리 선의 두께를 2로 설정
        circleImageView.layer.borderWidth = 2.0
        
        nameTextField.layer.borderColor = UIColor.gray.cgColor
        nameTextField.layer.borderWidth = 1.0
        nameTextField.layer.cornerRadius = 3
}

네비게이션의 title을 작성하는 방법은 self.title에 "" 으로 원하는 값을 넣어주면 된다.

 

그리고 네비게이션의 버튼은 self.navigationItem.rightBarButtonItem 또는 self.navigationItem.leftBarButtonItem으로

구현이 가능하다.


 📱 Simulator