iOS 9강 현상금 랭킹앱 실습

린다·2021년 1월 24일
0

iOS beginner

목록 보기
8/14
post-thumbnail

✨ 만든 어플
: 페이지가 2개
1) 리스트 2) 모달(아래에서 위로 올라오는 뷰 전환 방식)으로 상세페이지 띄워서 보여주기


1. 테이블뷰 기초 개념

여러 아이템들을 리스트로 보여주는 방식
: UITableView

  • 컬럼이 1개, 데이터들을 여러 행에 걸쳐서 보여줌
  • TableviewCell을 통해서 아이템 표현
  • cell을 재활용함(recycle cell) -> 화면에 보여지는 만큼 cell을 만들고 재사용함

2. 테이블뷰 프로토콜 개념

프로토콜: 규약, 해줘야하는 일들의 목록
-> 테이블뷰 프로토콜: 테이블뷰 서비스를 쓰기 위해 해야할 일들

  1. 필요한 셀이 몇개인지?
  2. 뷰는 어떻게 보여줄지?
    -> 이 두 개는 필수, 최소요건. (TableView가 물어보는 질문이라고 보면 됨)
  3. 클릭되면 어떻게 반응할지? (optional)

여기에 대해서 코드로 답변하는 방법
: UITableViewDataSource 셀 몇 개 필요해? + 어떻게 보여줄까? 를 담당하는 파트
: UITableViewDelegate 클릭하면 어떻게 반응할거야? 를 담당하는 파트


3. 테이블뷰 프로토콜 실습

코드 작성하고 Tableview랑 Viewcontroller 연결시켜줘야함
→ Tableview 선택 후 컨트롤 누르고 dataSource, delegate 선택 (dataSource에 대한 질문 물어보자!)
= tableview가 datasource라는 대리인을 통해서 bountyviewcontroller한테 물어보겠구나~ 라는 의미

import UIKit

class BountyViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }

    // UITableViewDataSource 대답

		//처음에 셀 몇 개를 보여줄지 설정하는 함수
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return bountyList.count
    }
    
		//뷰를 어떻게 보여줄건지 대답하는 함수
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        // 재활용되는 cell을 가져오는 함수 -> withIdentifier에 적힌 구분자를 cell을 선택한 후 Identifier에 써줘야함, indexPath는 cell의 위치표시
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        return cell // 구해지는 셀 가져와서 재활용하겠다
    }
 
		// 클릭했을 때 어떻게 반응할거야: UITableViewDelegate    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        print("---> \(indexPath.row)")
        //indexpath를 알 수 있음, 셀에 대한 정보를 줄 수 있음
    }

}

4. 커스텀 테이블뷰 셀 만들기

커스텀 셀 뷰카운터안에 코드 작성해줌, 뭐가 들어가는지
→ cell 선택 후 class를 ListCell로 연결시켜줌 (커스텀 셀로 변경)
→ 실제로 cell 안에 요소들을 넣고 오토레이아웃 시켜줌
→ 생성한 각 요소들을 뷰카운터의 커스텀셀 요소들과 연결시켜줌 (콜렉션 inspector에서 확인 가능)
→ 넣을 데이터 세팅해줌(이름, 현상금, 이미지 등등)
→ 데이터 어레이의 갯수만큼 셀 생성 return bountyList.count
→ 이미지 및 array안에 있는 데이터들과 각 셀을 연결시켜줌

import UIKit

class BountyViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
    
    let nameList = ["brook", "chopper", "franky", "luffy", "nami", "robin", "sanji", "zoro"]
    let bountyList = [33000000, 50, 4400000, 30000000, 1600000, 8000000, 7700000, 12000000]
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }

    // UITableViewDataSource 대답
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return bountyList.count // 처음에 셀이 몇개니, 어레이 갯수 가져와서 생성
    }
    
		//뷰를 어떻게 보여줄건지 대답하는 함수
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        // 재활용되는걸 가져오는 함수 : deque 머시기
				//지금 cell의 타입이 UITableViewCell인데 우리가 쓰고 싶은건 ListCell이기 때문에 바꿔줘야함 -> casting해줘야함
        guard let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as?ListCell else { //cell이 nil이 아닌 경우, 조건이 성립되면 함수 빠져나가고 밑의 코드 수행함 아니면 return으로 들어감
            return UITableViewCell() //casting이 안된 경우에는 UITableViewCell넘기도록~
        }
        //indexpath는 몇번째 셀인지 정보를 가지고 있는 변수
        let img = UIImage(named: "\(nameList[indexPath.row]).jpg")
        cell.imgView.image = img
        cell.nameLabel.text = nameList[indexPath.row]
        cell.bountyLabel.text = "\(bountyList[indexPath.row])"
        return cell // 구해지는 셀 가져와서 재활용하겠다
    }
 // 클릭했을 때 어떻게 반응할거야: UITableViewDelegate
    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        print("---> \(indexPath.row)")
        //indexpath를 알 수 있음, 셀에 대한 정보를 줄 수 있음
    }

}

//custom cell 만들어줌, ListCell이 커스텀cell의 이름, UITableViewCell 상속받음
class ListCell: UITableViewCell{
    @IBOutlet weak var imgView: UIImageView!
    @IBOutlet weak var nameLabel: UILabel!
    @IBOutlet weak var bountyLabel: UILabel!
}

5. 뷰컨트롤러 모달로 띄우기

눌렀을 때 뜰 DetailViewController 만들어야함
→ 새 파일 만들기 cocoa touch 뭐시기
→ 스토리보드에도 view controller 하나 추가하기
→ indentitiy inspector 누르고 class를 detailviewcontroller로 바꿔서 화면이랑 코드 연결시켜주기

1️⃣ close 버튼 넣고 close action 넣어주기
→ 버튼 요소 넣어주고 이미지 close로 바꿔주기 + 오토레이아웃 설정
→ 컨트롤 누르고 코드랑 연결해서 action 추가해주기 (mehtod: close)

2️⃣ 두 뷰 컨트롤러를 연결하는 방법: 세그웨이
: 뷰 컨트롤러에서 컨트롤 누르고 다른 뷰컨트롤로 연결
Present Modally 선택
→ 세그웨이 선택하고 Identifier 이름 변경 (showDetail)
→ 기존 viewcontroller 코드 중 셀을 클릭하면 어떤 변화를 보여줄지 고르는 코드에 performsegue 추가해줌

import UIKit

class DetailViewController: UIViewController {
    
override func viewDidLoad() {
        super.viewDidLoad()
        updateUI()
    }

		//close 버튼 눌렸을 때 창 닫는 액션
    @IBAction func close(_ sender: Any) {
        dismiss(animated: true, completion: nil) //사라지고나서 동작되어야 할 것들
    }
    
}
//BountyViewClass 코드

	// 클릭했을 때 어떻게 반응할거야: UITableViewDelegate -> 실제로 눌렸을 때 작동되는 코드
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        print("---> \(indexPath.row)")
        //indexpath를 알 수 있음, 셀에 대한 정보를 줄 수 있음
        performSegue(withIdentifier: "showDetail", sender: nil) //세그웨이 시행할 때 뭘 같이 껴서 보낼 수 있음
				//세그웨이를 실행해라 그 중 identifier가 showdetail인!
    }

6. 뷰컨트롤러간 데이터 전달하기

1️⃣ detailviewcontroller 스토리보드에 ui component 추가하기 + 오토레이아웃
2️⃣ detailviewcontroller 코드랑 ui component 연결시키기
3️⃣ 필요한 변수 생성, 화면이 뜨기 직전에 update 시켜주는 함수 작성

import UIKit

class DetailViewController: UIViewController {
    
    @IBOutlet weak var imgView: UIImageView!
    @IBOutlet weak var nameLabel: UILabel!
    @IBOutlet weak var bountyLabel: UILabel!
    
    //이름=이미지 이름이기 때문에 이름과 현상금 정보만 있으면 setting 가능함
    var name: String?
    var bounty: Int?

    //화면이 보이기 바로 직전에 호출되는 함수
    override func viewDidLoad() {
        super.viewDidLoad()
        updateUI()
    }
    
   //bountyviewcontroller로부터 name과 bounty data를 전달받은 경우 실행되는 함수
    func updateUI(){
	//정보들이 있을 때~ 값을 설정해줘라
        if let name = self.name, let bounty = self.bounty{
            let img =  UIImage(named: "\(name).jpg")
            imgView.image = img
            nameLabel.text = name
            bountyLabel.text = "\(bounty)"
        }
    }
    
    @IBAction func close(_ sender: Any) {
        dismiss(animated: true, completion: nil) //사라지고나서 동작되어야 할 것들
    }
}

✨ 뷰컨트롤러에서 값을 받아오는 법
세그웨이 수행 직전에 준비를 하는 method가 있음 → func prepare(for segue:~)
(원래 viewcontroller에 있는 함수여서 override를 해줘야함, 상속받은거에 있었다는 얘기임)

import UIKit

class BountyViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
    
    let nameList = ["brook", "chopper", "franky", "luffy", "nami", "robin", "sanji", "zoro"]
    let bountyList = [33000000, 50, 4400000, 30000000, 1600000, 8000000, 7700000, 12000000]
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) { //세그웨이 시행하기 직전에 준비하는 func
        //DetailViewController한테 데이터 줄거예요~
        if segue.identifier == "showDetail" { //불러오는 세그웨이가 showdetail 세그웨이인 경우
            let vc = segue.destination as?DetailViewController //세그웨이의 목적지가 detailviewcontroller
            if let index = sender as? Int { //sender는 몇번째인지 index 내용이라서 int로 다운캐스팅
                vc?.name = nameList[index]
                vc?.bounty = bountyList[index]
            }
        }
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
    }

    // UITableViewDataSource 대답
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return bountyList.count // 처음에 셀이 몇개니
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        // 재활용되는걸 가져오는 함수 : deque 머시기
        guard let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as?ListCell else { //성립되면 함수 빠져나가고 아니면 return으로 들어감
            return UITableViewCell()
        }
        //indexpath는 몇번째 셀인지 정보를 가지고 있는 변수
        let img = UIImage(named: "\(nameList[indexPath.row]).jpg")
        cell.imgView.image = img
        cell.nameLabel.text = nameList[indexPath.row]
        cell.bountyLabel.text = "\(bountyList[indexPath.row])"
        return cell // 구해지는 셀 가져와서 재활용하겠다
    }
 // 클릭했을 때 어떻게 반응할거야: UITableViewDelegate
    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        print("---> \(indexPath.row)")
        //indexpath를 알 수 있음, 셀에 대한 정보를 줄 수 있음
        performSegue(withIdentifier: "showDetail", sender: indexPath.row) //세그웨이 시행할 때 뭘 같이 껴서 보낼 수 있음
				//indexPath는 section과 row로 이뤄져있음, sender: 전달해줄 데이터에 대한 힌트
    }

}

class ListCell: UITableViewCell{
    @IBOutlet weak var imgView: UIImageView!
    @IBOutlet weak var nameLabel: UILabel!
    @IBOutlet weak var bountyLabel: UILabel!
}

테이블 뷰 중에 어떤 셀이 눌리면 세그웨이가 실행되는데 이때 몇번째 셀인지 sender에 숫자를 담아서 가져감
그 전에 실행 직전 준비하는 함수가 발동함
그 함수에서 sender에 담긴 숫자를 사용해서 name과 bounty에 대한 data를 담아놓음
세그웨이의 목적지인 detailviewcontroller에 이미 존재하는 변수인 name과 bounty에 대한 데이터를 가져가는 거임~

let vc = segue.destination as?DetailViewController //세그웨이의 목적지가 detailviewcontroller
            if let index = sender as? Int { //sender는 몇번째인지 index 내용이라서 int로 다운캐스팅
                vc?.name = nameList[index]
                vc?.bounty = bountyList[index]
            }

0개의 댓글

관련 채용 정보