✨ 만든 어플
: 페이지가 2개
1) 리스트 2) 모달(아래에서 위로 올라오는 뷰 전환 방식)으로 상세페이지 띄워서 보여주기
여러 아이템들을 리스트로 보여주는 방식
: UITableView
프로토콜: 규약, 해줘야하는 일들의 목록
-> 테이블뷰 프로토콜: 테이블뷰 서비스를 쓰기 위해 해야할 일들
여기에 대해서 코드로 답변하는 방법
: UITableViewDataSource 셀 몇 개 필요해? + 어떻게 보여줄까? 를 담당하는 파트
: UITableViewDelegate 클릭하면 어떻게 반응할거야? 를 담당하는 파트
코드 작성하고 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를 알 수 있음, 셀에 대한 정보를 줄 수 있음
}
}
커스텀 셀 뷰카운터안에 코드 작성해줌, 뭐가 들어가는지
→ 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!
}
눌렀을 때 뜰 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인!
}
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]
}