CGSize(width: Double, height: Double)
XIB(XML Interface Builder)
let nib = UINib(nibName: SampleTableViewCell.IDF, bundle: nil)
tableView.register(nib, forCellReuseIdentifier: SampleTableViewCell.IDF)
동적인 높이를 구성하기 위한 조건
automaticDimension
tableView.rowHeight = UITableView.automaticDimension
layout(절대적인 값을 주는 것이 아니라, 상대적인 위치로 잡아줄 것)
numOfLines(label이 있을 경우에만)
사용자가 편집가능한 cell 제작
//1. 시스템 편집, 주어진 cell에 대해서 편집가능하게 user가 사용하겠다.
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
//2. editing style 지정, default로 삭제UI 탑제
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
list.remove(at: indexPath.row)
tableView.reloadData()
}
//1. 스토리보드 파일찾기
let storyboard = UIStoryboard(name: "Main", bundle: nil)
//2. 스토리보드 파일 내 뷰컨트롤러 찾기
guard let viewController = storyboard.instantiateViewController(withIdentifier: "AddViewController") as? AddViewController else { return }
//2-1(옵션). 네비게이션 컨트롤러가 있는 형태로 present하고 싶은 경우, view에 네비게이션 컨트롤러 추가
let nav = UINavigationController(rootViewController: viewController )
//3. 화면 전환 방식 설정
nav.modalTransitionStyle = .coverVertical
nav.modalPresentationStyle = .fullScreen
//4. 화면 띄우기
present(nav, animated: true)
UILabel.appearance().textColor = .white // 일괄적으로 기본 텍스트 색상 결정하는 것.
in addition to stored properties, classes, structures, and enumerations can define computed properties, which don’t actually store a value. Instead, they provide a getter and an optional setter to retrieve and set other properties and values indirectly. [애플 공식 문서]
→ 실제로 값을 저장하지는 않지만, getter와 setter를 제공해서 다른 프로퍼티와 값을 간접적으로 검색하고 설정할 수 있다.
struct Point {
var x = 0.0, y = 0.0
}
struct Size {
var width = 0.0, height = 0.0
}
struct Rect {
var origin = Point()
var size = Size()
var center: Point {
get { //get 키워드 입력 후 함수처럼 블럭을 생성하고 블럭 내부에 원하는 로직을 작성한다.
//이후 반드시 리턴(계산 속성의 타입으로)
let centerX = origin.x + (size.width / 2)
let centerY = origin.y + (size.height / 2)
return Point(x: centerX, y: centerY)
}
set(newCenter) {
origin.x = newCenter.x - (size.width / 2)
origin.y = newCenter.y - (size.height / 2)
}
}
}
var square = Rect(origin: Point(x: 0.0, y: 0.0),
size: Size(width: 10.0, height: 10.0))
let initialSquareCenter = square.center
// initialSquareCenter is at (5.0, 5.0)
square.center = Point(x: 15.0, y: 15.0)
print("square.origin is now at (\(square.origin.x), \(square.origin.y))")
// Prints "square.origin is now at (10.0, 10.0)"
앱에서 user가 데이터를 추가하거나 삭제하는 시점에 매번 데이터를 reload 하는 것은 번거로울 수 있다. 이를 해결하기 위해서 사용하는 개념이 옵저버이다. 데이터 자체의 변화를 감지하고, 그에 따라 대응하는 코드를 작성할 수 있다.
observer var todo = TodoInfomation() {
didSet { //변수가 달라짐을 감지! -> 프로퍼티 옵저버
tableView.reloadData()
print("didset 실행")
}
}

구조체 타입으로 선언해 전체 데이터를 한번에 넘겨주자.
아울렛으로 다이렉트하게 데이터를 이동시킬 수 없다.(중간 다리가 필요)
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
guard let vc = self.storyboard?.instantiateViewController(identifier: DetailViewController.IDF) as? DetailViewController else {return}
vc.data = todo.list[indexPath.row]
present(vc, animated: true)
print("전환")
}
타입 속성은 lazy한 성격을 가지고 있다. 즉, 지연 저장 속성 처럼 속성에 접근하는 순간 초기화가 진행되며 1회만 진행된다. 이는 다수의 스레드에서 해당 속성에 접근하려고 하더라도 보장된다.
<문제상황> : 클래스나 구조체에서 인스턴스를 초기화할 때, 내부의 메서드를 활용해 초기화 하고 싶다. 하지만, 인스턴스 내부 요소들은 동시에 초기화가 진행되기 때문에 이는 불가능하다.
(즉, 메서드를 사용하고 싶으면 메서드 사용 시점에 메서드가 초기화되어 있어야한다.)
→ 이를 해결할 수 있는 것이 메서드를 타입메서드로 선언하면 된다.
struct TodoInfomation {
//인스턴스 프로퍼티
var list = [
toDo(main: "장보기", sub: "셀렉", like: true, done: false, color: randomColor()),
toDo(main: "고", sub: "0122", like: true, done: false, color: randomColor()),
toDo(main: "청소", sub: "111", like: true, done: false, color: randomColor()),
]
//인스턴스 메서드 -> 타입 메서드
static func randomColor()-> UIColor {
let red = CGFloat.random(in: 0...1)
let green = CGFloat.random(in: 0...1)
let blue = CGFloat.random(in: 0...1)
return UIColor(red: red, green: green, blue: blue, alpha: 1)
}
}
데이터
모델에 들어가는 코드는 파운데이션을 임포트했을 때 오류가 나는 코드는 사용하면 관점으로 접근
→ UI요소를 배제해야하기 때문.
nib 파일에 기반한 객체들이 초기화된 다음에 실행되는 메서드. awakeFromNib()은 초기화 과정 이후 view에 속한 아울렛 객체들이 모두 초기화되고 접근 가능한 상태에 호출된다.
스위프트에서 cell은 재사용큐 구조를 활용해, 끊임없이 초기화된다. 이때, 고정된 속성의 경우 매번 초기화할 필요가 없기 때문에 이를 방지할 수 있는 코드가 필요하다. 
따라서, awakeFromNib()을 사용해, cell 객체의 공통 설정 등을 한번에 초기화할 수 있다.
전체 데이터 리로드, 특정 item(컬렉션 뷰) 이나 row에 대해서만 초기하기 등 다양한 reload 옵션이 존재한다.
enum TransitionType {
case add
case edit
}
override func viewDidLoad() {
super.viewDidLoad()
switch tpye {
case .add:
title = "추가"
let xmark = UIImage(systemName: "xmark")
let leftButton = UIBarButtonItem(image: xmark, style: .plain, target: self, action: #selector(closedButtonTapped))
navigationItem.leftBarButtonItem = leftButton
navigationItem.leftBarButtonItem?.tintColor = .cyan
case .edit:
title = "수정화면"
}
}
//계산 속성
//get, set -> 기존 데이터의 검증 및 간단한 관리를 위해 사용
//willSet, didSet -> 데이터의 변화를 감지 후 추가적인 액션이 필요한 경우, 옵저버로 활용
//newValue, oldValue 기본적으로 사용할 수 있다.
class Chicken {
let name = "치킨"
var totalOrder = 10
var newOrder {
get {
return totalOrder * 100000
}
set {
totalOrder += newValue
}
}
}
// 고정값을 줄 프로퍼티 선언
// will/did set 선언
// 해당 값을 set(변화)할 프로퍼티 선언
class ChickenPrice {
var price: Int = 20000 {
willSet { // 데이터 변화 전에 로직 처리
print("\(price)에서 \(newValue)로 변화")
}
didSet { // 데이터 변화 후에 로직 처리
print("\(oldValue)에서 \(price)로 변화")
}
}
var priceChange: Int = 0 {
didSet {
price += priceChange
}
}
}
//프로토콜은 명세만 한다. 블럭 내부의 기능, 로직은 프로토콜을 채택한 객체 내부에서 구현한다.
protocol VeiwPresentableProtocol {
초기화할 수 없음.
// var naviagtionTitle = "네비게이션 이름"
// var backgroundColor = .red
// var identifier = "identifier"
//최소 요구사항 이후에 추가하는 것은 본인 마음. 즉 set하는 것은 개발자가 선택적으로 할 수 있는 것이다.
var naviagtionTitle:String { get }
var backgroundColor:UIColor { get }
var identifier:String { get }
func configureView()
func configureLabel()
func configureTextLabel()
}