프로젝트C. Weather
- UIKit
- UITableView
- UITableViewCell
- View Reuse
- Table View Cell Customize
- Swift
- Codable
- JSONDecoder
키워드: 테이블뷰, JSON, Delegation 패턴, 내비게이션 인터페이스
테이블뷰
테이블뷰 만들기
메인스토리보드에 테이블뷰컨트롤러 아니고 테이블뷰 추가하기
테이블뷰셀 추가하고, reuse identifier: cell 설정하기
dataSource와 delegate를 View Controller로 설정하기
- 인터페이스 빌더로
메인스토리보드 View Controller Scene에서 테이블뷰 오른쪽마우스, 노란색네모 뷰컨트롤러로 연결해주기
- 코드로
self.tableView.delegate = self
self.tableView.dataSource = self
style: grouped로 변경
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
@IBOutlet weak var tableView: UITableView!
let cellIdentifier: String = "cell"
let korean: [String] = ["가", "나", "다", "라", "마", "바", "사", "아", "자", "차", "카", "타", "파", "하"]
let english: [String] = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
//한글과 영어 두개의 섹션
func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
//섹션에 있는 행의 개수
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
switch section {
case 0:
return korean.count
case 1:
return english.count
default:
return 0
}
}
//행에 해당하는 셀 리턴
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: self.cellIdentifier, for: indexPath)
// 셀 생성
let text: String = indexPath.section == 0 ? korean[indexPath.row] : english[indexPath.row]
cell.textLabel?.text = text
return cell
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return section == 0 ? "한글" : "영어"
}
}
동적으로 데이터 추가하기
셀 아래 버튼을 추가하고 섹션을 추가한 뒤
버튼을 누를 때마다 날짜를 그 섹션에 추가하기
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
@IBOutlet weak var tableView: UITableView!
let cellIdentifier: String = "cell"
let korean: [String] = ["가", "나", "다", "라", "마", "바", "사", "아", "자", "차", "카", "타", "파", "하"]
let english: [String] = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]
var dates: [Date] = []
let dateFormatter: DateFormatter = {
let formatter: DateFormatter = DateFormatter()
formatter.dateStyle = .medium
formatter.timeStyle = .medium
return formatter
}()
@IBOutlet weak var touchUpAddButton: UIButton!
@IBAction func touchUpAddButton(_ sender: UIButton) {
dates.append(Date())
//전체를 불러옴
//self.tableView.reloadData()
self.tableView.reloadSections(IndexSet(2...2), with: UITableView.RowAnimation.automatic)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
//한글과 영어 두개의 섹션
func numberOfSections(in tableView: UITableView) -> Int {
return 3
}
//섹션에 있는 행의 개수
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
switch section {
case 0:
return korean.count
case 1:
return english.count
case 2:
return dates.count
default:
return 0
}
}
//행에 해당하는 셀 리턴
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: self.cellIdentifier, for: indexPath)
// 셀 생성
if indexPath.section < 2 {
let text: String = indexPath.section == 0 ? korean[indexPath.row] : english[indexPath.row]
cell.textLabel?.text = text
} else {
cell.textLabel?.text = self.dateFormatter.string(from: self.dates[indexPath.row])
}
return cell
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
if section < 2 {
return section == 0 ? "한글" : "영어"
}
return nil
}
}
테이블 뷰 커스터마이징
tableView Cell추가
그 안에 label 두 개 추가
Style: custom
reuse identifier: customCell
코코아터치클래스 UITableViewCell생성: customCell의 인스턴스를 만들기 위해서
customCell의 클래스를 방금 생성한 Class와 연결: CustomTableViewCell
//CustomTableViewCell.swift
@IBOutlet var leftLabel: UILabel!
@IBOutlet var rightLabel: UILabel!
//ViewController.swift
var dates: [Date] = []
let dateFormatter: DateFormatter = {
let formatter: DateFormatter = DateFormatter()
formatter.dateStyle = .medium
return formatter
}()
let timeFormatter: DateFormatter = {
let formatter: DateFormatter = DateFormatter()
formatter.timeStyle = .medium
return formatter
}()
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// 셀 생성
if indexPath.section < 2 {
let cell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: self.cellIdentifier, for: indexPath)
let text: String = indexPath.section == 0 ? korean[indexPath.row] : english[indexPath.row]
cell.textLabel?.text = text
return cell
} else {
// 커스텀테이블뷰셀이라고 지정하고 일반테이블뷰의 메서드를 사용했기 때문에 as! 필요
// 강제 타입캐스팅 말고 좋은 방법 찾아보기
let cell: CustomTableViewCell = tableView.dequeueReusableCell(withIdentifier: self.customcellIdentifier, for: indexPath) as! CustomTableViewCell
cell.leftLabel?.text = self.dateFormatter.string(from: self.dates[indexPath.row])
cell.rightLabel?.text = self.timeFormatter.string(from: self.dates[indexPath.row])
return cell
}
}
뷰의 재사용
UITableViewCell, UICollectionViewCell
모바일에서는 PC보다 자원이 한정되어 있어 메모리를 절약하기 위해
화면에서 안보이면 재사용큐에 들어간 후 재사용되어 나온다.
let cell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: self.cellIdentifier, for: indexPath)
register(:forCellReuseIdentifer:)이나 register(:forCellReuseIdentifier:)으로 Identifier를 반드시 설정해줘야 한다. (코드로 설정하는 방법)
segue
show, show detail
show detail은 split view에서 사용한다
https://developer.apple.com/library/archive/featuredarticles/ViewControllerPGforiPhoneOS/UsingSegues.html
다음 화면으로 데이터 전달하기
embed in > Navigation Controller
뷰 컨트롤러 추가
그 안에 레이블 추가
셀에서 뷰 컨트롤러 드래그하고 Selection Segue > show 선택
코코아터치클래스 생성 UIViewController
//ViewController.swift
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
//segue.identifier =
guard let nextViewController: SecondViewController = segue.destination as? SecondViewController else {
return
}
guard let cell: UITableViewCell = sender as? UITableViewCell else {
return
}
// 세컨드뷰컨트롤러에서 텍스트레이블이 아직 생성되어 있지 않기 때문에 textToSet에 값을 저장해서 넘겨준다
nextViewController.textToSet = cell.textLabel?.text
}
//SecondViewController.swift
import UIKit
class SecondViewController: UIViewController {
var textToSet: String?
@IBOutlet weak var textLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.textLabel.text = self.textToSet
}
}
JSON
Codable = Decodable & Encodable
메인스토리보드에서 테이블뷰컨트롤러와 셀을 생성하고
셀의 Style: Subtitle, identifier: cell 설정한다
dataSource와 tableView를 각각 아웃렛과 뷰컨트롤러를 연결해준다
//ViewController.swift
import UIKit
class ViewController: UIViewController, UITableViewDataSource {
@IBOutlet weak var tableView: UITableView!
let cellIdentifier: String = "cell"
var friends: [Friends] = []
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.friends.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: self.cellIdentifier, for: indexPath)
let friend: Friends = self.friends[indexPath.row]
cell.textLabel?.text = friend.nameAndAge
cell.detailTextLabel?.text = friend.fullAddress
return cell
}
override func viewDidLoad() {
super.viewDidLoad()
let jsonDecoder: JSONDecoder = JSONDecoder()
guard let dataAsset: NSDataAsset = NSDataAsset(name: "friends") else {
return
}
do {
//디코드타입은 프렌즈배열
self.friends = try jsonDecoder.decode([Friends].self, from: dataAsset.data)
} catch {
print(error.localizedDescription)
}
self.tableView.reloadData()
}
}
//Friends.swift
//{
// "name":"하나",
// "age":22,
// "address_info": {
// "country":"대한민국",
// "city":"울산"
// }
//}
import Foundation
struct Friends: Codable {
struct Address: Codable {
let country: String
let city: String
}
let name: String
let age: Int
let addressInfo: Address
var nameAndAge: String {
return self.name + "(\(self.age))"
}
var fullAddress: String {
return self.addressInfo.city + ", " + self.addressInfo.country
}
//JSON의 파라미터의 이름(키값)과 매칭되지 않을 때 CodingKey 프로토콜을 따르게 해 바꿔서 사용
enum CodingKeys: String, CodingKey {
case name, age
case addressInfo = "address_info"
}
}
Xcode 단축키
프로토콜 누르고 control^, command 누르면 UIKit를 보여준다.
command n: 새 파일 생성
화면 전환...
왜이렇게 나뉘어서 되는거지?
미치겠다...
Author And Source
이 문제에 관하여(프로젝트C. Weather), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@msi753/프로젝트C.-Weather저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)