클래스
클래스는 붕어빵 틀. 객체는 붕어빵. -> 클래스가 있어야 객체지향언어
클래스로 부터 만들어진 객체를 인스턴스라고 한다.(swift에서는 객체 = 인스턴스)
청사진이나 설계사의 그림이 건물이 완성된 후의 모습을 나타내고 있는 것 처럼 클래스는 객체가 생성되었을 때 어떠한 모습을 보일 것인지를 정의
클래스 = 자동차
프로퍼티(특성,데이터,속성) = 문, 핸들, 바퀴, 의자
메소드(행위, 조작) = 움직인다, 정차한다, 감속한다 -> 어떠한 일을 하고 어떠한 속성이 있는지 정의
코딩 : class 클래스이름: 부모 클래스 { 프로퍼티 / 인스턴스 메소드 / 타입 메소드 }
클래스에 프로퍼티 추가하기
반드시 초기값이 있어야 한다.
init을 이용하여 초기화 하면 초기값은 없어도 가능하다.
옵셔널 변수 or 상수로 선언하여 초기값이나 nil 할당.
저장(stored) 프로퍼티와 계산(computed) 프로퍼티가 있다.
class Woman {
var age : Int = 0 // age와 weight는 저장 프로퍼티라서 반드시 초기값이 있어야 한다.
var weight : Double! // 옵셔널로 프로퍼티 선언
var name : String? // 옵셔널로 선언하면 언래핑 해줘야 함
}
클래스에 메소드 추가하기
인스턴스 메소드는 인스턴스가 호출하며, 함수처럼 작성하면 된다.
타입(클래스) 메소드는 클래스 레벨에서 동작하는 것으로, 클래스의 새로운 인스턴스를 생성하는 것과 같은 동작
타입 메소드는 인스턴스 메소드와 동일한 방법으로 선언하지만 앞에 class 또는 static을 붙인다.
class 키워드로 만든 클래스 메소드는 자식 클래스에서 override 가능 하다.
class Woman {
var age : Int = 2 // stored 프로퍼티
var weight : Double! = 3.5 // stored 프로퍼티
func display() { // 인스턴스 메소드 -> 인스턴스에서 동작
print("나이 = \(age), 몸무게 = \(weight)")
}
class func cM() { // 타입 메소드 -> 클래스에서 동작 / 자식 클래스에서 override 가능
print("cM은 클래스 메소드 입니다.")
}
static func scM() { // 타입 메소드 -> 클래스에서 동작
print("scM은 클래스 메소드(static)")
}
}
인스턴스 만들기
class Woman {
var age : Int = 2
var weight : Double! = 3.5
func display() { // 인스턴스 메소드
print("나이 = \(age), 몸무게 = \(weight)")
}
class func cM() { // 타입 메소드
print("cM은 클래스 메소드 입니다.")
}
static func scM() { // 타입 메소드
print("scM은 클래스 메소드(static)")
}
var x : Int = 0 // Int x 변수를 선언 하듯이
var kim : Woman = Woman() // 클래스 Woman 인 객체 kim을 선언
// 일반 변수 선언과는 다르게 ' = Woman() ' 써줘야 함
// ' : Woman ' 은 생략 가능 -> var kim = Woman()
// 눈에 보이지 않는 default initializer 를 호출하는것
print(kim.age)
kim.display() // 인스턴스 메소드는 인스턴스가 호출
Woman.cM() // 클래스 메소드는 클래스가 호출
Woman.scM() // 클래스 메소드는 클래스가 호출
인스턴스 초기화하기 : init()
클래스, 구조체, 열거형(enum)에서 인스턴스가 생성되는 시점에서 해야할 초기화 작업
인스턴스가 만들어지면서 자동 호출됨
designated initailizer : 모든 프로퍼티를 다 초기화 시키는 생성자
소멸자 : 인스턴스가 사라질 때 자동 호출 -> deinit{}
코딩 : init() { }
class Woman {
var age : Int = 2 // stored 프로퍼티
var weight : Double! = 3.5 // stored 프로퍼티
func display() {
print("나이 = \(age), 몸무게 = \(weight)")
}
init(yourAge: Int, yourWeight: Double) {
age = yourAge
weight = yourweight
} // designated initializer
class func cM() { // 타입 메소드 -> 클래스에서 동작 / 자식 클래스에서 override 가능
print("cM은 클래스 메소드 입니다.")
}
static func scM() { // 타입 메소드 -> 클래스에서 동작
print("scM은 클래스 메소드(static)")
}
}
var kim : Woman = Woman(yourAge: 10, yourWeight: 20.5)
// init을 하나라도 만들면 default init은 사라진다
// 따라서 var kim : Woman = Woman() 은 오류가 뜨게 됨
// init을 만들면 stored 프로퍼티인 age 와 weight는 초기값이 없어도 가능
kim.display()
self
현재 클래스 내의 메소드나 프로퍼티를 가리킬 때 사용
self.메소드 / self.프로퍼티
같은 이름의 매개변수와 구분하기 위해 반드시 사용
class Man {
var age : Int
var weight : Double
func display() {
print("나이 = \(age), 몸무게 = \(weight)")
}
init(age: Int, weight: Double) {
self.age = age // self.age 는 클래스의 프로퍼티
self.weight = weight // age 는 init의 매개변수
}
}
var kim = Man(age:10, weight: 20.4)
// 1. age 와 weight의 값은 클래스 Man의 init의 매개변수로 할당
// 2. init의 매개변수 값을 클래스의 프로퍼티로 할당
// 3. 할당된 프로퍼티로 메소드 display 실행
kim.display()
computed 프로퍼티
var 로 선언해야한다
계산 프로퍼티는 프로퍼티가 설정되거나 검색되는 시점에서 계산 또는 파생된 값
setter가 없으면 get{ } 는 생략 가능
set(newValue) { } 매개변수명은 newValue가 default. (생략가능)
코딩 : var 이름 : 타입 { get { return 내용 } set(newValue) { 대입 내용 } }
class Man {
var age : Int
var weight : Double
var manAge : Int { // computed 프로퍼티
get { // setter가 없으면 생략 가능
return age-1 //manAge프로퍼티 호출시 age의 값
}
set(USAAge) { // newValue 대신 USAAge를 매개변수로 사용
age = USAAge + 1 // manAge에 값 할당시 age의 값
}
}
func display() {
print("나이 = \(age), 몸무게 = \(weight)")
}
init(age: Int, weight: Double) {
self.age = age
self.weight = weight
}
}
var kim = Man(age:10, weight: 20.4)
kim.display()
print(kim.manAge) // 9 -> 클래스 Man의 manAge로 get의 리턴값
print(kim.age) // 10
kim.manAge = 3 // 클래스 Man의 manAge로 set(USAAge)에 값을 할당
print(kim.age) // 4-> set(USAAge)로 연산된 값이 age 프로퍼티에 할당
method overloading : 생성자 중첩
매개변수의 개수와 자료형이 다르고 이름만 같은 함수를 여러개 정의
class Man {
var age : Int
var weight : Double = 3.5 // 두번째 init 때문에 초기값을 넣어줘야한다.
var manAge : Int {
get {
return age-1
}
set(USAAge) {
age = USAAge + 1
}
}
func display() {
print("나이 = \(age), 몸무게 = \(weight)")
}
init(age: Int, weight: Double) { // 첫번째 init
self.age = age
self.weight = weight
}
init(age: Int) { // 두번째 init
self.age = age // weight 는 클래스 Man의 default 값을 사용
}
}
var kim = Man(age:10, weight: 20.4)
kim.display() // 나이 = 10, 몸무게 = 20.4
var kim2 = Man(age:20)
kim2.display() // 나이 = 20, 몸무게 = 3.5
UIImage 클래스의 init()함수 overloading
앱에서 이미지 데이터를 관리하는 클래스인 UIImage는 15개의 init()가 overloading되어 있다.
init?(named: String)
의 init을 사용하여
let myImage: UIImage = UIImage(named: "apple.png")!
myImage 라는 인스턴스(객체)를 생성
init? : 실패 가능한 생성자
init? or init! 사용 하지만 일반적으로 '?' 를 많이 사용한다
오류 상황에 nil을 리턴하는 조건문이 있음
class Man {
var age : Int
var weight : Double
func display() {
print("나이 = \(age), 몸무게 = \(weight)")
}
init?(age: Int, weight: Double) {
if age <= 0 {
return nil
} else {
self.age = age
}
self.weight = weight
}
}
var kim : Man? = Man(age:1, weight: 20.4) // 옵셔널 인스턴스 선언
if let kim1 = kim { // 옵셔널 바인딩
kim1.display()
}
if let kim2 = Man(age:2, weight: 5.5) {
kim2.display() // 인스턴스 생성과 동시에 옵셔널 바인딩
}
var kim3 : Man = Man(age: 2, weight: 4.4)!
kim3.display() // 인스턴스 생성과 동시에 강제 언래핑
var kim4 : Man? = Man(age: 8, weight: 0)
kim4!.display() // 옵셔널 인스턴스를 사용시 강제 언래핑
// 나이가 nil 값일 때
var kim : Man? = Man(age: -1, weight: 3.5)
if let kim1 = kim {
kim1.display() // nil이 리턴되어 아무런 값도 나오지 않는다
}
if let kim2 = Man(age: 0, weight: 5.5) {
kim2.display() // nil이 리턴되어 아무런 값도 나오지 않는다
}
var kim3 : Man = Man(age: 0, weight: 1.1)!
kim3.display() // nil을 강제로 풀어버려 crash가 생긴다
// 강제 언래핑은 위험함
출처 : https://www.youtube.com/channel/UCM8wseo6DkA-D7yGlCrcrwA