๐Ÿšจ ํ•œ ๋ฒˆ์ฏค ๋งˆ์ฃผ์น˜๋Š” TableView ์ด์Šˆ ๋ชจ์Œ

SeBinยท2025๋…„ 1์›” 11์ผ
post-thumbnail

๐Ÿšจ UITableView ์ด์Šˆ ๋ชจ์Œ

ํ…Œ์ด๋ธ” ๋ทฐ์—์„œ ์‚ฌ์†Œํ•˜๋ฉด์„œ๋„ ํ”ํžˆ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ์ด์Šˆ๋“ค์„ ๋ชจ์•„๋ณด์•˜์Šต๋‹ˆ๋‹ค.


1. Optional error๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค๋ฉด?

Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value

  • ์˜ต์…”๋„ ์—๋Ÿฌ๊ฐ€ ๋‚ฌ๋‹ค๋ฉด identifier ์˜คํƒ€๊ฐ€ ๋‚ฌ๋Š”์ง€ ํ™•์ธํ•ด ๋ด…์‹œ๋‹ค.
  • identifier ์˜คํƒ€๋กœ ํ•ด๋‹น ์…€์„ ์ฐพ์ง€ ๋ชปํ–ˆ๋Š”๋ฐ, ์˜ต์…”๋„์„ ๊ฐ•์ œ๋กœ ๋ฒ—๊ฒผ์„ ๋•Œ ๋‚˜๋Š” ์ด์Šˆ์ž…๋‹ˆ๋‹ค.
extension UITableViewCell {
    static var identifier: String {
        String(describing: self)
    }
}
  • ์ด๋Ÿฌํ•œ ํœด๋จผ์—๋Ÿฌ๋ฅผ ์ค„์ด๊ธฐ ์œ„ํ•ด identifier๋ฅผ ์•„์˜ˆ ํƒ€์ž… ์†์„ฑ์œผ๋กœ ๋งŒ๋“œ์‹œ๋Š”๊ฑธ ์ถ”์ฒœ๋“œ๋ฆฝ๋‹ˆ๋‹ค.

2. Cell์ด ์•ˆ๋ณด์ธ๋‹ค๋ฉด?

let list = ["ํ”„๋กœ์ ํŠธ", "์‡ผํ•‘", "๋ฉ”์ธ ์—…๋ฌด", "๊ณผ์ œ"]

// ์…€์˜ ๊ฐœ์ˆ˜
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return 3
}
  • ๋ฐฐ์—ด์— ๋‚ด์šฉ์„ ์ถ”๊ฐ€ํ–ˆ๋Š”๋ฐ ์•ˆ๋ณด์ธ๋‹ค๋ฉด numberOfRowsInSection ๋ถ€๋ถ„์„ ์‚ดํŽด๋ด…์‹œ๋‹ค.
  • ๋ฐ์ดํ„ฐ ๊ฐœ์ˆ˜์™€ ์…€์˜ ๊ฐœ์ˆ˜๋ฅผ ๊ผญ ๋งž์ถฐ์ค˜์•ผ ํ•ฉ๋‹ˆ๋‹ค.
    • ๋ฐ์ดํ„ฐ ๊ฐœ์ˆ˜ > ์…€ ๊ฐœ์ˆ˜ โ†’ ์…€ ๊ฐœ์ˆ˜ ๋งŒํผ๋งŒ ๋‚˜์˜ต๋‹ˆ๋‹ค.
    • ๋ฐ์ดํ„ฐ ๊ฐœ์ˆ˜ < ์…€ ๊ฐœ์ˆ˜ โ†’ ์ธ๋ฑ์Šค ์—๋Ÿฌ๊ฐ€ ๋‚ฉ๋‹ˆ๋‹ค.

3. Index out of range ์ธ๋ฑ์Šค ์—๋Ÿฌ๊ฐ€ ๋‚œ๋‹ค๋ฉด?

let list = ["ํ”„๋กœ์ ํŠธ", "์‡ผํ•‘", "๋ฉ”์ธ ์—…๋ฌด"]

// ์…€์˜ ๊ฐœ์ˆ˜
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return 4
}
  • ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ numberOfRowsInSection ๋ฉ”์„œ๋“œ ๋ถ€๋ถ„์„ ํ™•์ธํ•ด๋ด…์‹œ๋‹ค.
  • ์…€ ๊ฐœ์ˆ˜ ๋งŒํผ ๋ฐ˜๋ณตํ•˜๋Š”๋ฐ ๋ฐฐ์—ด ๊ฐœ์ˆ˜๊ฐ€ ์ ๋‹ค? โ†’ list[3]์€ ์กด์žฌํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ ์ธ๋ฑ์Šค ์—๋Ÿฌ๊ฐ€ ๋‚ฉ๋‹ˆ๋‹ค.

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return list.count
}
  • ๊ทธ๋ž˜์„œ ๋ณดํ†ต list.count ๋กœ ์จ์ฃผ๋Š” ํŽธ์ž…๋‹ˆ๋‹ค.
  • ๋งŒ์•ฝ ํ•„ํ„ฐ๋ง์„ ํ•˜๊ฑฐ๋‚˜ ๋ฐฐ์—ด ๋ฒ”์œ„๋ฅผ ์ค„์—ฌ์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ, ์กฐ๊ฑด ์ฒ˜๋ฆฌ๋ฅผ ํ•ด์ฃผ์‹œ๊ฑฐ๋‚˜ ์›๋ณธ ๋ฐฐ์—ด์„ ๊ฑด๋“œ๋ฆฌ์ง€ ์•Š๋Š” ๋ฐฉํ–ฅ์œผ๋กœ ํ•ด์ฃผ์…”์•ผ ํ•ฉ๋‹ˆ๋‹ค.


4. ํ…Œ์ด๋ธ” ๋ทฐ์— ๋ฐ์ดํ„ฐ๊ฐ€ ๋ฐ˜์˜์ด ์•ˆ๋œ๋‹ค๋ฉด?

tableView.reloadData()
  • ์ด reloadData()๋ฅผ ๋น ํŠธ๋ฆฐ๊ฑด ์•„๋‹Œ์ง€ ํ™•์ธํ•ด๋ด…์‹œ๋‹ค.
  • ๋ทฐ์™€ ๋ฐ์ดํ„ฐ๋Š” ๋”ฐ๋กœ ๋†€๊ธฐ ๋•Œ๋ฌธ์— ๋ฐ์ดํ„ฐ๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค ๋‹ค์‹œ ๊ฐฑ์‹ ์‹œ์ผœ์ค˜์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ํ…Œ์ด๋ธ”์˜ ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค ๊ฐฑ์‹ ์‹œ์ผœ์ฃผ๋Š”๊ฒŒ reloadData()์ž…๋‹ˆ๋‹ค.
    • ํ…Œ์ด๋ธ” ๋ทฐ์˜ ์Šค์™€์ดํ”„ ์• ๋‹ˆ๋ฉ”์ด์…˜๊นŒ์ง€ ์—†์• ๋ฒ„๋ฆด ์ˆ˜ ์žˆ์œผ๋‹ˆ ๊ทธ๋Ÿด๋• ํ•œ ์ค„๋งŒ ๋ฆฌ๋กœ๋“œ ํ•ด์ฃผ๋Š” reloadRows๋ฅผ ์‚ฌ์šฉํ•ด๋ด…์‹œ๋‹ค.

5. ํ…Œ์ด๋ธ” Cell์˜ ๋†’์ด๊ฐ€ ๋™์ ์œผ๋กœ ๋ณ€ํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด?

Cell์— Label์ด ์žˆ๊ณ  ์ด Label์˜ ํ…์ŠคํŠธ ์–‘์ด ์ž์œ ๋กญ๊ฒŒ ์ค„์–ด๋“ค๊ณ  ๋Š˜์–ด๋‚œ๋‹ค๋ฉด, Cell ๋†’์ด ์—ญ์‹œ ๋™์ ์œผ๋กœ ๋ณ€ํ•ด์•ผ์ง€ Label์ด ์ž˜๋ฆฌ์ง€ ์•Š์„ ๊ฒ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ๋ณ€ํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด?

5-1. rowHeight๋ฅผ automaticDimension์œผ๋กœ ์„ค์ •

tableView.rowHeight = UITableView.automaticDimension
  • ๋จผ์ € ๋†’์ด๋ฅผ UITableView.automaticDimension๋กœ ์„ค์ •ํ•˜์…”์•ผ ํ•ฉ๋‹ˆ๋‹ค.

5-2. numberOfLines๋ฅผ 0์œผ๋กœ ์„ค์ •

cell.textLabel?.numberOfLines = 0
  • Label์˜ numberOfLines๋ฅผ 0์œผ๋กœ ์„ค์ •ํ•˜์…จ๋Š”์ง€ ํ™•์ธํ•ด๋ด…์‹œ๋‹ค.
  • numberOfLines๋Š” Label์˜ ์ค„ ์ˆ˜๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋Š” ์†์„ฑ์ธ๋ฐ, 0์œผ๋กœ ํ•œ๋‹ค๋Š”๊ฑด ํ…์ŠคํŠธ๋ฅผ ๋ฌดํ•œ์œผ๋กœ ๋‹ค ๋ณด์—ฌ์ฃผ๊ฒ ๋‹ค๋Š” ์˜๋ฏธ์ž…๋‹ˆ๋‹ค.
  • ์ด๊ฑธ ์„ค์ • ์•ˆํ•˜๋ฉด default๊ฐ€ 1์ด๋‹ˆ 1์ค„๋งŒ ๋ณด์—ฌ์ฃผ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
  • 0์œผ๋กœ ๋ฐ”๊ฟ”์ค˜์•ผ ์ค„ ์ˆ˜ ๋งŒํผ ๋™์ ์œผ๋กœ ๋†’์ด๊ฐ€ ๋ฐ”๋€” ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

5-3. Cell ์˜คํ† ๋ ˆ์ด์•„์›ƒ ์„ค์ •

  • ๋†’์ด๊ฐ€ ๋Š˜์–ด๋‚˜๋Š” ๊ณณ์— height์„ ๊ณ ์ •ํ•˜๋ฉด ์•ˆ๋ฉ๋‹ˆ๋‹ค.
  • ๊ทธ๊ณณ์„ ์ œ์™ธํ•˜๊ณ  ๋‚˜๋จธ์ง€๋Š” ์—ฌ๋ฐฑ๊ณผ ๋†’์ด๋ฅผ ๊ณ ์ •์‹œ์ผœ์•ผํ•ฉ๋‹ˆ๋‹ค.
    • ํ…์ŠคํŠธํ•„๋“œ๋„ ํฐํŠธ ํฌ๊ธฐ๋ฅผ ๊ณ ๋ คํ•ด์„œ ๋†’์ด ๊ณ ์ •์‹œํ‚ค๋Š”๊ฒŒ ์˜ค๋ฅ˜๊ฐ€ ์ ์€ ํŽธ์ž…๋‹ˆ๋‹ค.

5-4. ์ตœ์†Œ ๋†’์ด ์„ค์ •

  • ๋งŒ์•ฝ ์ตœ์†Œ ๋†’์ด๋Š” ๊ณ ์ •์‹œ์ผœ์•ผ ํ•œ๋‹ค๋ฉด ์˜คํ† ๋ ˆ์ด์•„์›ƒ ๋†’์ด ์„ค์ • ํŽธ์ง‘ํ•˜๋Š” ๋ถ€๋ถ„์—์„œ ๋ถ€๋“ฑํ˜ธ๋กœ >= ์ด์ƒ์œผ๋กœ ์„ค์ •ํ•ด์ค์‹œ๋‹ค.

6. ๋ฐ์ดํ„ฐ ์‚ญ์ œ๊ฐ€ ์•ˆ๋œ๋‹ค?

  • ํ˜น์‹œ ๋ฐ์ดํ„ฐ๋ฅผ ์ง€์šฐ์ง€ ์•Š๊ณ  deleteRows ๋ฉ”์„œ๋“œ๋งŒ ์‚ฌ์šฉํ•˜์…จ๋‚˜์š”? ์ด ๋ฉ”์„œ๋“œ๋Š” ๋‹จ์ˆœํžˆ ๋ทฐ๋ฅผ ๋ณ€๊ฒฝํ•ด์ค„ ๋ฟ, ์‹ค์ œ ๋ฐ์ดํ„ฐ์—๋Š” ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • ์‹ค์ œ ๋ฐ์ดํ„ฐ๋ฅผ removeํ•ด์ฃผ์‹œ๊ณ  deleteRows๋ฅผ ์‚ฌ์šฉํ•ด๋ด…์‹œ๋‹ค.

6-1. ๋ฐ์ดํ„ฐ๋„ ์ง€์šฐ๊ณ  deleteRowsํ–ˆ๋”๋‹ˆ ์—๋Ÿฌ๋‚˜๊ณ  ์ด์ƒํ•ด์š”

  • ์…€ ๋ฐ์ดํ„ฐ๋ฅผ ์ง€์› ์ง€๋งŒ ๋‹ค๋ฅธ ์ •๋ณด(๋ฒ„ํŠผ์˜ tag ๋“ฑ)๋Š” ๊ทธ๋Œ€๋กœ๋ผ์„œ ๊ทธ๋Ÿด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • reloadData, reloadRows, reloadSections์„ ์‚ฌ์šฉํ•ด์„œ ์ •๋ณด๋“ค์„ ์—…๋ฐ์ดํŠธํ•ด์ฃผ์„ธ์š”.

7. ๊ทธ๋ƒฅ ์…€์ด ์ด์ƒํ•˜๊ฒŒ ๋‚˜์™€์š”(?)

์˜๋„ํ•œ ๊ฒƒ์‹ค์ œ๋กœ ๋‚˜์˜จ ๊ฒƒ

์…€์ด 1000๊ฐœ ์žˆ๋‹ค๊ณ  ์ง„์งœ๋กœ ์…€ 1000๊ฐœ๋ฅผ ๋งŒ๋“ค ์ˆ˜๋Š” ์—†์Šต๋‹ˆ๋‹ค.

  • ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๋ณด๋‹ค ํšจ์œจ์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๊ณ , ์ž์—ฐ์Šค๋Ÿฌ์šด ์Šคํฌ๋กค์„ ์œ„ํ•ด์„œ TableView, CollectionView์— ๋„์ž…๋œ ๊ฐœ๋…์ด ์žฌ์‚ฌ์šฉ ๋ฉ”์ปค๋‹ˆ์ฆ˜์ž…๋‹ˆ๋‹ค.
  • ์ปจ๋ฒ ์ด์–ด ๋ฒจํŠธ๋งˆ๋ƒฅ 1000๊ฐœ ์ค‘ 10๊ฐœ ์ •๋„๋งŒ ๋งŒ๋“ค์–ด์„œ ๋Œ๋ ค์“ฐ๋Š” ๊ฒƒ์ธ๋ฐ์š”, ์ด ๊ณผ์ •์—์„œ ์ด์ „์˜ ๋ฐ์ดํ„ฐ๊ฐ€ ๋‚จ์•„์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๊ทธ๋ž˜์„œ ์• ์ดˆ์— ์…€์„ ๋งŒ๋“œ๋Š” cellForRowAt ๋ถ€๋ถ„์—์„œ ์กฐ๊ฑด ์ฒ˜๋ฆฌ๋ฅผ 100% ํ•ด์ฃผ์…”์•ผ ํ•ฉ๋‹ˆ๋‹ค.

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