๐Ÿ“š [iOS] UITableView

su_veraยท2021๋…„ 10์›” 24์ผ

iOS

๋ชฉ๋ก ๋ณด๊ธฐ
2/6

๐Ÿ“Œ UITableView ?

์—ฌ๋Ÿฌ ์•„์ดํ…œ์„ ํ…Œ์ด๋ธ” ํ˜•ํƒœ๋กœ ๋ณด์—ฌ์ฃผ๊ธฐ ์œ„ํ•œ ๋ทฐ

iOS ๊ฐœ๋ฐœ์„ ํ•˜๋‹ค๋ณด๋ฉด ์ž์ฃผ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜๋Š” ์ธํ„ฐํŽ˜์ด์Šค์ธ UITableView ! ๋ฆฌ์ŠคํŠธ ํ˜•ํƒœ๋กœ ์ด๋ฃจ์–ด์ ธ ์žˆ์œผ๋ฉด ์Šคํฌ๋กค์ด ๊ฐ€๋Šฅํ•˜๊ณ  ๋ฐ์ดํ„ฐ๋ฅผ ๋™์ ์œผ๋กœ ๋ฐ›์•„์„œ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. UIScrollView์˜ ์ƒ์†์„ ๋ฐ›์€ ๊ฐ์ฒด์ด๋ฉฐ, Delegate Pattern์„ ์‚ฌ์šฉํ•ด ๊ตฌํ˜„ํ•˜๋Š” ์ธํ„ฐํŽ˜์ด์Šค ๐Ÿ•ถ

โœ… UITableView ๊ตฌ์„ฑ์š”์†Œ !

ํ•˜๋‚˜์˜ table view -> ์—ฌ๋Ÿฌ๊ฐœ์˜ tableview section -> ์—ฌ๋Ÿฌ๊ฐœ์˜ tableview cell -> tableview cell ๋งˆ๋‹ค ํ•˜๋‚˜์”ฉ์˜ content view -> contents

  1. ๊ฐ๊ฐ์˜ section์—๋Š” header์™€ footer ๊ฐ€ ๋ถ™์„ ์ˆ˜ ์žˆ๋‹ค.
  2. TableView์—๋„ Header์™€ Footer๊ฐ€ ๋ถ™์„ ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์Šคํฌ๋กค ์˜์—ญ์— ํฌํ•จ๋จ.

์ž์ฃผ์“ฐ๋Š” ๋ฉœ๋ก ์ด๋‚˜ ์•ฑ์Šคํ† ์–ด์—๋„ ์š”๋กœ์ฝ”๋กฌ ํ…Œ์ด๋ธ” ๋ทฐ๊ฐ€ ์ ์šฉ๋œ ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋Š”๋ฐ์šฉ! ๐Ÿ˜‰ ์ž์„ธํžˆ ๋ณด์‹œ๋ฉด ํ…Œ์ด๋ธ” ๋ทฐ์˜ ์…€๋“ค์ด ๋ฐ์ดํ„ฐ๋งŒ ๋ฐ”๋€Œ๊ณ  ๋ชจ๋‘ ๋™์ผํ•œ layout ์œผ๋กœ ๋ฐ˜๋ณต๋˜๊ณ  ์žˆ๋‹ค๋Š” ์‚ฌ์‹ค์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค ! ๊ทธ๋Ÿฐ๋ฐ.. ๐Ÿ˜… ์ด๊ฑธ ํ•˜๋‚˜ํ•˜๋‚˜ ๋‹ค ์งค ์ˆ˜ ์—†์ž๋‚˜์š” ! ์ด๋Ÿด๋•Œ tableview์™€ tableview cell ์ด ๋งค์šฐ ์œ ์šฉํ•˜๋‹ต๋‹ˆ๋‹ค โœจ

๐Ÿ“Œ UITableViewCell ?

  • ํ…Œ์ด๋ธ” ํ–‰์˜ ๋‚ด์šฉ์„ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋˜๋Š” ํด๋ž˜์Šค
  • ํ…Œ์ด๋ธ” ๊ด€๋ จ ๋™์ž‘์„ ์ง€์›ํ•˜๊ธฐ ์œ„ํ•ด ๋ช‡ ๊ฐ€์ง€ ํŠน์ • ์‚ฌ์šฉ์ž ์ง€์ •์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค !

๐Ÿ”ฎ TableView Cell์„ ๊ตฌํ˜„ํ•˜๋Š” 3๊ฐ€์ง€ ๋ฐฉ๋ฒ•

  1. ์Šคํ† ๋ฆฌ๋ณด๋“œ ๋‚ด์—์„œ TableviewCell ํ™œ์šฉํ•ด์„œ ๊ตฌ์„ฑ - prototype cell
  2. Xib ํŒŒ์ผ๋กœ ๋”ฐ๋กœ ๋ถ„๋ฆฌํ•ด์„œ Cell UI ๊ตฌ์„ฑ
  3. Code base๋กœ Cell ๊ตฌ์„ฑ

์ด ์ค‘์—์„œ ์ €๋Š” ํ˜‘์—…์—์„œ ๋งŽ์ด ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ธ 2๋ฒˆ ๋ฐฉ๋ฒ•์œผ๋กœ ์‹ค์Šต์„ ํ•ด๋ดค์Šต๋‹ˆ๋‹น !


๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป Xib๋ฅผ ํ™œ์šฉํ•ด์„œ Tableview cell ๋งŒ๋“ค๊ธฐ

๋จผ์ € ์ƒˆ๋กœ์šด ํŒŒ์ผ์„ ์ถ”๊ฐ€ํ•˜๊ธฐ ์œ„ํ•ด Cocoa Touch Class ํŒŒ์ผ ์„ ํƒ ํ›„ UITableVIewCell๋กœ ์„ค์ •, Also create XIB file์„ ์ฒดํฌ !

๊ทธ ๋‹ค์Œ์—” ์•„์ด์ฝ˜ ์ถ”๊ฐ€, autolayout, identifier ์„ค์ •ํ•˜๊ธฐ ๐Ÿ˜‰

๐Ÿ“Œ RankingTableViewCell

class RankingTableViewCell: UITableViewCell {
    static let identifier = "RankingTableViewCell"

    @IBOutlet weak var appIconImageView: UIImageView!
    @IBOutlet weak var rankLabel: UILabel!
    @IBOutlet weak var titleLabel: UILabel!
    @IBOutlet weak var subTitleLabel: UILabel!
    @IBOutlet weak var openButton: UIButton!
    
    override func awakeFromNib() {
        super.awakeFromNib()
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)
    }
    
    func setData(rank: Int, appData: AppContentData) {
        rankLabel.text = "\(rank)"
        appIconImageView.image = appData.makeImage()
        titleLabel.text = appData.appName
        subTitleLabel.text = appData.description
    }
    
}

1๏ธโƒฃ TableViewCell ์•ˆ์— ๋‚ฏ์„  ํ•จ์ˆ˜ ๋“ฑ์žฅ...? awakeFromNib()
์ด ์นœ๊ตฌ๋Š” ๊ฐ์ฒด๊ฐ€ ์ดˆ๊ธฐํ™”๋œํ›„ ํ˜ธ์ถœ๋˜๋Š” ๋ฉ”์„œ๋“œ ! viewDidLoad() ์™€ ๋น„์Šทํ•œ ๊ฐœ๋…์œผ๋กœ ์ƒ๊ฐํ•˜๋ฉด ๋œ๋‹ต๋‹ˆ๋‹น .. xib๋กœ ๊ตฌ์„ฑํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” init์„ ๋”ฐ๋กœ ํ•ด์ฃผ์ง€ ์•Š๋”๋ผ๋„ ์ž๋™์œผ๋กœ awakeFromNib()์œผ๋กœ ํ˜ธ์ถœ์ด ๋ฉ๋‹ˆ๋‹ค ๐Ÿ’ฅ

2๏ธโƒฃ func setData : cell ๋ณ„๋กœ ๋‹ค๋ฅธ ๋ฐ์ดํ„ฐ๊ฐ€ ๋“ค์–ด์™€์•ผํ•˜๋ฏ€๋กœ, AppContentData๋ฅผ ํ•จ์ˆ˜ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ฐ›๊ณ  ์ด ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ํ†ตํ•ด outlet ๋ณ€์ˆ˜๋“ค์— ๋ฐ์ดํ„ฐ๋ฅผ ๋„ฃ์–ด์คŒ !

( tableview cell์— ์‹ค์ œ ๊ตฌ์กฐ์ฒด ๋ฐ์ดํ„ฐ๋ฅผ ๋„ฃ๋Š” ๊ณผ์ •์€ ์ƒ๋žต .. )


โœ… TableView๋ฅผ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ์ฑ„ํƒํ•ด์•ผ ํ•˜๋Š” 2๊ฐœ์˜ Protocol

UITableViewDelegate ์™€ UITableViewDataSource !!

์—ฌ๊ธฐ์„œ ! ์•Œ๊ณ  ๋„˜์–ด๊ฐ€์•ผํ•  ํ…Œ์ด๋ธ” ๋ทฐ์˜ ๋™์ž‘์›๋ฆฌ ^^...

  • ํ…Œ์ด๋ธ” ๋ทฐ๋Š” ์žฌ์‚ฌ์šฉํ๋ฅผ ํ™œ์šฉํ•ด์„œ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํšจ์œจ์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ฃผ๋Š” ํด๋ž˜์Šค
  • ์šฐ์„  ํ™”๋ฉด์— ๋ณด์ด๋Š” ๋ฐ์ดํ„ฐ ๋จผ์ € ์ƒ์„ฑํ•˜๊ณ , ์Šคํฌ๋กค์„ ํ•˜๋ฉด ๋ณด์ด์ง€ ์•Š๋Š” ์˜์—ญ์€ Reuse Queue์˜ ํ’€์— ๋“ค์–ด๊ฐ€๊ณ  ์ƒˆ๋กญ๊ฒŒ ๋ณด์ด๋Š” cell์— ํ•ด๋‹น ํ’€์—์„œ ๊บผ๋‚ด์™€์„œ ์ƒˆ๋กญ๊ฒŒ ๋ณด์—ฌ์คŒ
  • ์ด๋ ‡๊ฒŒ ์žฌ์‚ฌ์šฉ๋˜๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ cell์˜ identifier๊ฐ€ ๊ต‰์žฅํžˆ ์ค‘์š” !

๐Ÿ“‘ ๋ทฐ/์…€์˜ ์žฌ์‚ฌ์šฉ์— ๊ด€ํ•œ ํ‹ฐ์Šคํ† ๋ฆฌ ํฌ์ŠคํŒ…

์ด์ œ 2๊ฐ€์ง€ ํ”„๋กœํ† ์ฝœ์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์ž๋ฉด ..

1๏ธโƒฃ UITableViewDelegate : ํ…Œ์ด๋ธ” ๋ทฐ์˜ ๋™์ž‘๊ณผ ๋ชจ์–‘์„ ๊ด€๋ฆฌ
-> cell์˜ ๋†’์ด์™€ cell์„ ํƒ ์‹œ ๋ฌด์—‡์„ ํ• ์ง€ ?

2๏ธโƒฃ UITableViewDataSource : ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์„œ ๋ทฐ๋ฅผ ๊ทธ๋ ค์ฃผ๋Š” ์—ญํ• 
-> ์ด ์„น์…˜๊ณผ ๊ทธ ์„น์…˜ ์•ˆ์— ๋“ค์–ด๊ฐ€๋Š” cell์˜ ๊ฐœ์ˆ˜, ๊ฐ row์— ์–ด๋–ค cell์„ ๋ณด์—ฌ์ค„๊ฑด์ง€ ?

extension RankingVC: UITableViewDelegate {
// heightForRowAtํ•ด์„œ indexPath๋ณ„์˜ ๋†’์ด๋งŒ ์ง€์ •ํ•˜๋Š” ํ•จ์ˆ˜
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 80
    }
    
}

extension RankingVC: UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return appContentList.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: RankingTableViewCell.identifier) as? RankingTableViewCell else {return UITableViewCell()}
        
        cell.setData(rank: indexPath.row + 1, appData: appContentList[indexPath.row])
        return cell
    }
}

tableview์—๊ฒŒ ํ•ด๋‹น identifier๋ฅผ ๊ฐ€์ง„ cell์ด ์žฌ์‚ฌ์šฉ ํ์— ์žˆ๋Š”์ง€ ๋ฌผ์–ด๋ณด๊ณ  ์žˆ์œผ๋ฉด, UITableViewCell ๊ฐ์ฒด๊ฐ€ ๋„˜์–ด์˜ค๊ณ  ์•„๋‹ˆ๋ฉด nil ! ๊ทธ๋ฆฌ๊ณ  ๋„˜์–ด์˜จ ๊ฐ์ฒด๋ฅผ as?๋ฅผ ํ†ตํ•ด ์›ํ•˜๋Š” ํ•˜์œ„ํด๋ž˜์Šค๋กœ ํƒ€์ž…๋ณ€ํ™˜. ์ด๋ ‡๊ฒŒ ๋˜๋ฉด, cell์€ RankingTableViewCell ๊ฐ์ฒด์ด๊ธฐ ๋•Œ๋ฌธ์— ์ด์ „์— ์ •์˜ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌ๋ฐ›๋Š” ํ•จ์ˆ˜ ์‚ฌ์šฉ ๊ฐ€๋Šฅ !!

โœ… ์ด๋ฒˆ ์‹ค์Šตํ•˜๋ฉด์„œ ์ถ”๊ฐ€์ ์œผ๋กœ ๋ฐฐ์šด ๊ฒƒ

1๏ธโƒฃ ๋ฐ”๋กœ๋ฐ”๋กœ ๋ฐ์ดํ„ฐ ์ „๋‹ฌ์„ ์œ„ํ•ด์„œ ๊ตฌ์กฐ์ฒด๋กœ ์ƒˆ๋กœ์šด ๋ฐ์ดํ„ฐํ˜•์„ ๋งŒ๋“œ๋Š” ๊ฒƒ์ž„๋‹ˆ๋‹ค ! AppContentDataModel.swift ๋ผ๋Š” ์ƒˆ๋กœ์šด ์Šค์œ„ํ”„ํŠธ ํŒŒ์ผ์„ ๋งŒ๋“ค์–ด์„œ ์•ฑ ์ด๋ฆ„, ์„ค๋ช…, ์•„์ด์ฝ˜ ์ด๋ฏธ์ง€ ์ด๋ฆ„์„ ๋„ฃ๋Š” AppContentData ๋ชจ๋ธ์„ ์ถ”๊ฐ€ํ•ด์ค๋‹ˆ๋‹ค !

import UIKit

struct AppContentData{
    let appName: String
    let description: String
    let appIconName: String
    
    func makeImage() -> UIImage? {
        return UIImage(named: appIconName)
    }
}

2๏ธโƒฃ Cell์„ ๊ตฌ๋ถ„ํ•˜๊ธฐ ์œ„ํ•œ idenntifier์„ static์„ ํ™œ์šฉํ•ด ํƒ€์ž… ํ”„๋กœํผํ‹ฐ๋กœ ์„ ์–ธ !! ์ด๊ฑด ์˜คํƒ€๋กœ ์ธํ•œ ์˜ค๋ฅ˜๋ฅผ ์ค„์ด๋Š”๋ฐ ์ข‹๋‹ค๊ณ  ํ•ฉ๋‰˜๋‹ค ๐Ÿ’ก

class RankCollectionViewCell: UICollectionViewCell {
    static let identifier = "RankCollectionViewCell"
    ...
    }

3๏ธโƒฃ xib ํŒŒ์ผ๋กœ Cell UI ๊ตฌ์„ฑ์‹œ, ํ…Œ์ด๋ธ” ๋ทฐ๋งˆ๋‹ค cell๋กœ์„œ ์‚ฌ์šฉํ•  nib ๊ฐ์ฒด๋ฅผ ๋“ฑ๋กํ•ด ์ฃผ์–ด์•ผํ•จ.

func registerXib(){
        let xibName = UINib(nibName: RankingTableViewCell.identifier, bundle: nil)
        rankTableView.register(xibName, forCellReuseIdentifier: RankingTableViewCell.identifier)
    }

์‰ฝ..์ง€ ์•Š์•˜๋˜ ํ…Œ์ด๋ธ” ๋ทฐ.. ใ„ดใ…•์„.. ^^ .. ๋‹ค์Œ์— ๋” ์•Œ์•„๋ณด๋„๋กํ•˜๊ณ  .. ์—ฌ๊ธฐ์„œ ์ด๋งŒ.. ๐Ÿ’ฅ

profile
iOS ๊ฐœ๋ฐœ์ผ๊ธฐ โœจ

4๊ฐœ์˜ ๋Œ“๊ธ€

comment-user-thumbnail
2022๋…„ 1์›” 31์ผ

su_vera ๋‹˜ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค! ๋•๋ถ„์— xib๋กœ cell ์„ ๋งŒ๋“œ๋Š” ์—ฐ์Šต์ด ๋˜์—ˆ์–ด์š”!
์—ฌ๊ธฐ์„œ cell์„ ๋ˆ„๋ฅด๋ฉด ๋‹ค์Œ ํ™”๋ฉด์œผ๋กœ ์ „ํ™˜ํ•˜๊ณ  ์‹ถ์€๋ฐ ๊ทธ๋Ÿด ๊ฒฝ์šฐ๋Š”, ์–ด๋–ป๊ฒŒ ํ•˜๋ฉด ์ข‹์„๊นŒ์š”?!
์Šคํ† ๋ฆฌ๋ณด๋“œ๋กœ ํ•  ๋•Œ๋Š” ์Šคํ† ๋ฆฌ๋ณด๋“œ์— cell ์ด ์žˆ์–ด์„œ segue ๋กœ ํ–ˆ์—ˆ๋Š”๋ฐ xib๋กœ ํ•˜๋‹ˆ ์Šคํ† ๋ฆฌ๋ณด๋“œ์—๋Š” cell ์ด ์—†์–ด ์—ฐ๋™์„ ์–ด๋–ป๊ฒŒ ํ•˜๋ฉด ์ข‹์„์ง€ ๊ณ ๋ฏผ์ด๋„ค์š”!

1๊ฐœ์˜ ๋‹ต๊ธ€