3주차 정리
✅ First App
- label : 글자를 표현하는 모든 것, 눌러도 아무런 동작하지 않음
- 오토 레이아웃 : 위치를 잡아주는 것
- 화면 하나 당 화면을 관리하는 코드가 있음
- button : 대부분의 버튼은 touch up inside. 기본 설정은 sender(파라미터, 보내는 이)
- touch up inside : 버튼 안에서 눌러서 버튼 안에서 손을 떼었을 때
- UILabel.text : 레이블의 문자를 바꾸는 속성
- IB : Interface Builder
- Outlet : 배출구
- Action : 행동이 전달
- viewDidLoad : 앱의 화면에 들어오면 처음 실행시키는 함수
✅ iOS Architecture/Framework
- 프레임워크(rule) -> 개발자 -> 라이브러리
- import를 아무것도 안 하면 그냥 swift언어만 사용하는 것
- UIKit 안에 Foundation이 포함되어 있음
✅ Dice Game
- stack view : 두 객체를 묶어줌
- spacing : 가운데 공간
- distribution : 나머지 공간을 어떻게 채울거냐
- fill equally : 1:1로 나눠가짐
✅ RPS Game
- enum raw value : random value를 쉽게 생성
🌟 button style Default VS Plain
- 왜 plain은 currentTitle을 찾아가지 못할까?
- plain : titleLabel!.text는 찾아감.
- UIButton은 UIControl을 상속함.
- UIButton.currentTitle must be used from main thread only
✅ RandomBingo Game
✅ UpDown Game
✅ 클래스와 구조체
- 클래스는 붕어빵틀 같다
- 클래스(강아지) -> 객체(보리, 초코)
- 근본적으로 구조체와 클래스는 크게 다른 개념이 아님
- 둘다 붕어빵을 만듦 ㅎㅎ
- 인스턴스 : 카톡 친구 한명 한명. 메모리에 찍어낸 실제 데이터.
- 약속으로 클래스의 인스턴스만 객체라고 부르기로 함
- 클래스(붕어빵틀)는 데이터 영역에 존재.
1️⃣ 차이점
- 메모리 저장방식
- 구조체 : 값형식. 스택에 저장. 값을 전달할 때 복사본 생성.
- 클래스 : 참조형식. 힙에 저장. 메모리 주소값이 힙을 가르킴.
- 스택은 차례차례 쌓지만 힙은 군데군데 비어있는 영역을 찾아서 따로따로 저장
🌟 메모리 구조가 다르다!!!
- 구조체는 그 함수가 실행되고 나서 인스턴스가 사라진다.
2️⃣ 복사하면 어떻게 될까
class Person {
var name = "사람"
}
struct Animal {
var name = "동물"
}
var p = Person()
p.name
var a = Animal()
a.name
var p2 = p
p.name
p2.name
var a2 = a
a.name = "강아지"
a.name
a2.name
- 클래스는 주소를 복사. 동일한 메모리주소를 가리킴. 동일한 데이터를 가리킨다는 의미.
- 구조체는 ? 값을 복사. 서로 각각 다른 데이터로 나눠짐.
- 구조체가 조금 더 가벼움. 많은 경우 구조체를 사용.
3️⃣ let 선언
- 클래스는 속성을 바꿀 수 있고, 구조체는 바꿀 수 없다??
- 왜 ?? 클래스를 let으로 선언하면 메모리 주소를 바꿀 수 없다는 뜻이지만 구조체를 let으로 선언하면 속성이 let으로 바뀌는 것.
🌟 상당히 중요한 내용!
class PersonClass {
var name = "사람"
var age = 0
}
struct AnimalStruct {
var name = "동물"
var age = 0
}
let pclass = PersonClass()
let astruct = AnimalStruct()
pclass.name = "사람1"
pclass.name
astruct.name
4️⃣ 점문법
- 명시적 멤버 표현식?
- 문자열도 구조체로 만들어져 있음...?
- 문자열도 메모리에 인스턴스로 찍어낸 것. 그래서 "안녕하세요".count가 가능한 것.
5️⃣ 관습
- 속성과 메서드 순서.
- 속성 먼저. 메서드 나중.
🌟 클래스 안에서 메서드 실행문이 올 수 없음
6️⃣ 초기화
class Dog {
var name: String
var weight: Double
init(name: String, weight: Double) {
self.name = name
self.weight = weight
}
func sit() {
print("앉았습니다")
}
}
var bori = Dog(name: "보리", weight: 15.0)
bori.name
bori.weight
- self는 실제 데이터를 의미
🌟 모든 저장 속성을 초기화 해야 함. 모든 속성에 값을 넣어줘야 한다는 의미.
- 초기화의 의미 : 데이터를 메모리에 저장
- 오버로딩 가능 -> 다양한 생성자
🌟 속성이 옵셔널 타입인 경우
===, !==
🌟 클래스와 클로저만 참조 형식.
7️⃣ 객체 지향 프로그래밍 (OOP)
- oop는 왜 필요할까?
- 클래스, 구조체는 (의미있는)데이터를 묶음으로 만들려는 것. 상태정보를 담는 바구니
- 클래스/구조체 사용 이유 : 모델링(DTO, DAO, Helper Object), 미리 만들어놓은 것 사용하기 위함.
- 변수/상수 -> 구조체(속성, 메서드. 상속X) -> 클래스(속성, 메서드. 상속O)
- 실제로 애플은 구조체를 많이 사용하라고 권장
oop의 4대 특징(캡상추다)
-
객체지향 : 클래스를 사용한다는 의미와 유사
-
추상화, 캡슐화, 상속성, 다형성
-
추상화 = 모델링 : 실생활에서 필요한 것만 쏙쏙 뽑아서 조합한 것
-
캡슐화 = 모델링, 정보 은닉, 데이터 캡슐화 : 연관 있는 속성, 메서드
-
상속성 = 재사용, 확장
-
다형성 = 사용편의, 동적 바인딩 : ?? 상속과 관련. 프로토콜과 관련. 오버로딩. 오버라이딩.
✅ 속성과 메서드
-
구조체와 클래스의 속성에서는 차이가 거의 없지만 메서드에서 생성자와 소멸자 부분에서 차이가 생김
1️⃣ 지연 저장 속성
struct Bird1 {
var name: String
lazy var weight: Double = 0.2
init(name: String) {
self.name = name
}
}
var aBird1 = Bird1(name:"새")
aBird1.weight
- 나중에 메모리 공간을 찍어내는 것
- 해당 저장 속성의 초기화를 지연시키는 것
- 변수로만 선언 가능. 상수로는 선언 불가.
- 초기화 값을 선언해줘야 함.
- 표현식으로도 초기화 가능
- 접근하는 순간에 초기값을 가질 수 있도록.
- 왜 쓸까? 메모리 공간을 많이 차지할 때. 다른 저장 속성을 이용해야 할 때(다른 저장 속성에 의존)
class AView {
var a: Int
lazy var view = UIImageView()
lazy var b: Int = {
return a * 10
}()
init(num: Int) {
self.a = num
}
}
var view1 = Aview(num: 10)
- 실제로 프로젝트에서 지연 저장 속성을 많이 사용함.
🌟 함수는 일을 할 수 있는 명령어의 묶음
2️⃣ 메서드의 메모리 동작
- 그림에서 저장속성만 나타남. 메서드는 어디갔지 ? 함수 주소를 보리와 초코에 저장할 필요 없음. 가리키면 됨. 공통된 속성은 데이터 영역에서 관리하면 됨.
- 데이터 영역 안에 메서드 영역이 따로 존재하는 것. 함수의 주소를 다 가지고 있음. 메서드를 찾아가서 실행하는 것. ->
메서드 디스패치
3️⃣ 계산 속성
class Person {
var birth:Int = 0
var age: Int {
get {
return 2022 - birth
}
set(age) {
self.birth = 2022 - age
}
}
func getAge() -> Int {
return 2022 - birth
}
func setAge(_ age: Int) {
self.birth = 2022 - age
}
}
var p1 = Person()
p1.birth = 2000
p1.getAge()
p1.setAge(20)
p1.birth
p1.age
p1.age = 21
문법적 약속
: set에서 age라는 파라미터를 지우고 newValue를 사용해도 됨.
- get은 반드시 구현해야 함
- set은 생략 가능
- 속성과 메서드는 그렇게 큰 차이가 있지 않음
- age는 birth에 의존. birth를 이용해서 계산하는 것. 그래서 계산 속성
- get만 있다면 get-only property / read-only property
- getter/setter
- java에도 동일한 내용이 있음
- 왜 쓸까 ? 두 가지를 한 번에 구현. 명확해 보임. 읽기 쉬움. 메모리 구조도 메서드.
4️⃣ 타입 속성
- static : 고정적인, 고정된
- 저장 타입 속성 : 항상 기본값이 필요. 타입이기 때문에. 지연 속성의 성격.
- 계산 타입 속성
- 모든 인스턴스와 공유할 수 있는. 계속 가지고 있는 메모리 공간.
- 인스턴스로 접근하는 것이 아닌 타입으로 접근해야 함.
- 게임 캐릭터라고 하면, 유저가 기사를 한 명씩 만들어 낼 때마다 몇 명의 기사를 만들어냈는지 카운트할 수 있는 것
Int.max
Int.min
Double.pi
- 언제 쓸까? 모든 인스턴스가 동일하게 가져야하는 속성일 때. 공유해야하는 성격에 가까운 속성일 때.
5️⃣ 속성 감시자
- 저장 속성 감시자
- willSet, didSet
- 저장 속성의 값이 어떻게 바뀌는지 감시하는 것.
- willSet -> didSet
- newValue, oldValue
- 일반적으로 didSet을 많이 사용.
- 계산 속성에는 왜 속성 감시자를 사용할 수 없나 ? set에서 값 변경을 관찰할 수 있기 때문
- 프로필 사진, 상태메세지의 옛날 데이터를 기억할 때.