Swift 기본 문법 #3
원본 : https://www.notion.so/Week-3-53f19dfd2bab4d17b2d58cde89ac464a
학습목표
1️⃣ 타입과 인스턴스의 관계를 이해하고 코드로 나타낼 수 있다.
2️⃣ 타입을 설계하는 방법을 알고 응용할 수 있다.
3️⃣ 타입의 인스턴스를 초기화하는 방법을 알고 응용할 수 있다.
4️⃣ 옵셔널 체이닝을 이해하고 응용할 수 있다.
01. 타입
: 데이터와 기능을 용도에 맞게 묶어 구조화해놓은 것 → 객체, 어떤 객체의 설꼐도
: 메모리에 생설될 타입의 인스턴스가 수행할 수 있는 기능과 동작을 상세하게 표현한 것
: 데이터와 기능을 용도에 맞게 묶어 구조화해놓은 것 → 객체, 어떤 객체의 설꼐도
: 메모리에 생설될 타입의 인스턴스가 수행할 수 있는 기능과 동작을 상세하게 표현한 것
ex) 컴퓨터라고 정의된 것(명사) → 타입, 내 집에 있는 실체화된 컴퓨터 → 인스턴스
💡 인스턴스 : 클래스, 구조체, 열거형 등의 타입에서 생성된 실체(객체) → 타입은 이 실체를 위한 설계도임 셈타입의 정의
- 열거형(Enumeration)
- 구조체(Struct)
- 클래스(Class)
타입을 정의할 때 타입명은 대문자로 시작 !
- Computer라는 이름의 구조체(Struct)타입을 정의해보자
import Foundation
//Computer라는 이름의 구조체(Struct) 타입 정의
struct Computer {
var battery: Int = 100
let manufacturer: String = "Apple"
func saveData() {
print("데이터를 저장합니다.")
}
func playVideo() {
print("영상을 재생합니다.")
}
}
컴퓨터의 설계도처럼 Computer라는 객체가 가져가야할 값들과 동작을 정의하는 거지롱.
같은 모듈 내에서 타입의 이름은 유일해야 하므로, 만약 같은 기능을 하는 타입을 Class로 구현하고자 한다면 이름을 다르게 해줘야함!
타입은 설계도일 뿐 → 설계도를 통한 실체를 생성해서 사용해야 함 = 인스턴스
타입의 설계 내부를 보면 우리에게 익숙한 변수들과 함수들이 보임.
- 타입 내부
- 타입과 연관된 값 : 속성(Property)
- 타입과 연관된 함수 : 메소드(Method)
병아리인 우리들은 인스턴스 프로퍼티, 인스턴스 메소드만 다룹시당(타입 프로퍼티, 타입 메소드는 나중에)
- 타입은 중첩 타입(Nested Type)으로도 설계할 수 있다
import Foundation
struct SoccerPlayer {
enum Position {
case goalKeeper, wing, back, forward
}
let name: String
var position: SoccerPlayer.Position
}
struct BasketballPlayer {
enum Position {
case center, forward, `gaurd`
}
let name: String
var posrition: BasketballPlayer.Position
}
💡 Structures and Classes : [https://docs.swift.org/swift-book/LanguageGuide/ClassesAndStructures.html](https://docs.swift.org/swift-book/LanguageGuide/ClassesAndStructures.html)
💡 Properties : [https://docs.swift.org/swift-book/LanguageGuide/Properties.html](https://docs.swift.org/swift-book/LanguageGuide/Properties.html)
💡 Methods : [https://docs.swift.org/swift-book/LanguageGuide/Methods.html](https://docs.swift.org/swift-book/LanguageGuide/Methods.html)
02. 인스턴스
인스턴스(Instance)
타입은 설계도일 뿐이라, 설계도를 통한 실체(인스턴스)를 생성해 사용해아함
- Computer 타입으로부터 인스턴스를 생성해 프로퍼티 값을 변경하거나 메소드로 동작을 실행하는 코드 예시
import Foundation
struct Computer {
var battery: Int = 100
let manufacturer: String = "Apple"
func saveData() {
print("데이터를 저장합니다")
}
func playVideo() {
print("영상을 재생합니다")
}
}
//Computer라는 설계도를 통해 실제 컴퓨터를 만들어내는 과정
// 등호 오른쪽은 Computer.init()과 동일한 표현
var myComputer: Computer = Computer()
myComputer.battery = 93
//오류 발생
myComputer.manufacturer = "eelijus LAB" //Error! 상수값 변경 불가
//인스턴스 myComputer의 saveData()메소드를 호출(call)
myComputer.saveData()
//OUTPUT : 테이터를 저장합니다
var sujiComputer: Computer = Computer()
sujiComputer.battery = 92
sujiComputer.playVideo()
//OUTPUT : 영상을 재생합니다
03. 인스턴스의 초기화
이니셜라이저(Initializer)
: 각 타입의 이니셜러이저를 통해 인스턴스의 생성과 초기화 가능
ex) let computer = Computer()
축약표현 : ()
== init()
인스턴스는 메모리에 생성되고, 쓸모를 다하면 메모리에서 소멸됨. 그 소멸 시점에 특별한 처리가 필요하다면 deinit
메소드를 사용할 수 있다.
변수 혹은 상수에 제대로 된 값이 들어있지 않은 상황에서 해당 변/상수에 접근하 → 런타임 에러
스위프트는 이를 미연에 방지하고 옵셔널, 인스턴스의 초기화 과정의 규칙 같은 안전장치를 만듦.
인스턴스 초기화의 규칙
-
대전제 :
인스턴스의 프로퍼티에 값이 있다는 것이 항상 보장되어야 한다
→ 이니셜라이저 내부에서 항상 인스턴스의 프로퍼티 값을 적절한 값으로 초기화해주거나, 인스턴스 프로퍼티가 기본값을 가지고 있어야 함
인스턴스의 생성과 소멸
스위프트의 모든 인스턴스는 초기화와 동시에 모든 프로퍼티에 유효값이 할당돼있어야 함.
프로퍼티에 미리 기본값을 할당해두면, 인스턴스가 생성됨과 동시에 초기값을 지니게 됨.
import Foundation
import Swift
//이니셜라이저와 디이니셜라이저
// init , deinit
class PersonA {
//모든 저장 프로퍼티에 기본값 할당
var name: String = "unknown"
var age: Int = 0
var nickName: String = "nick"
}
//인스턴스 생성 후,
let jason: PersonA = PersonA()
//프로퍼티에 적절한 값 할당
jason.name = "jason"
jason.age = 100
jason.nickName = "j"
//프로퍼티 기본값을 지정하기 어려운 경우에는 이니셜라이절르 통해 인스터가 가져야할 초기값을 전달 가능
class PersonB {
var name: String
var age: Int
var nickName: String
//이니셜라이저
init(name: String, age: Int, nickName: String) {
self.name = name
self.age = age
self.nickName = nickName
}
}
//원하는 프로퍼티값으로 바로 인스턴스 생성 가능
let hana: PersonB = PersonB(name: "hana", age: 20, nickName: "하나")
//에러 -> 인자로 값이 안들어옴
//let hana: PersonB = PersonB(name: "hana", age: 20, nickName: "") Error!
//프로퍼티의 초기값이 꼭 필요없을때는 옵셔널을 사용!
class PersonC {
var name: String
var age: Int
//이 프로퍼티는 꼭 필요한 프로퍼티는 아니야~
var nickName: String? //nickName 프로퍼티에는 nil값이 들어와도 돼~
init(name: String, age: Int, nickName: String) {
self.name = name
self.nickName = nickName
self.age = age
}
init(name: String, age: Int) {
self.name = name
self.age = age
}
}
let jenny: PersonC = PersonC(name: "jenny", age: 10)
let mick: PersonC = PersonC(name: "mick", age: 15, nickName: "nn")
//암시적 추출 옵셔널은 인스턴스 사용에 꼭 필요하지만 초기값을 할당하지 않고자 할 때 사용
class Puppy {
var name: String
//꼭 필요한 프로퍼티지만 이니셜라이징 때는 할당못하고, 나중에 따로 세팅해주겠다?
var owner: PersonC!
init(name: String) {
self.name = name
}
func goOut() {
print("\(name)가 보호자 \(owner.name)와 함께 산책을 하네요")
}
}
let happy: Puppy = Puppy(name: "happy")
//happy.goOut() :Error! 런타임 오류 발생 84번째 줄에 오류 메세지 뜸
//owner가 nil인 상태라 크러쉬 남
happy.owner = jenny //PersonC의 인스턴스인 jenny
happy.goOut()
//실패가능한 이니셜라이저
class PersonD {
var name: String
var age: Int
var nickName: String?
init?(name: String, age: Int) {
if (0...120).contains(age) == false {
return nil
}
if name.count == 0 {
return nil
}
self.name = name
self.age = age
}
}
//에러 발생 -> 옵셔널이 아닌 타입으로 PersonD의 인스턴스 생성하려고 함
//let cock: PersonD = PersonD(name: "cock", age: 23)
let cock: PersonD? = PersonD(name: "cock", age: 23)
let jocker: PersonD? = PersonD(name: "jocker", age: 140)
let jin: PersonD? = PersonD(name: "", age: 30)
print(cock)
print(jocker) //OUTPUT : nil
print(jin) //OUTPUT : nil
// deinitializer
class PersonE {
var name: String
var pet: Puppy?
var child: PersonC
init(name: String, child: PersonC) {
self.name = name
self.child = child
}
deinit {
if let petName = pet?.name {
print("\(name)가 \(child.name)에게 \(petName)을 인도해줍니다.")
self.pet?.owner = child
}
}
}
var donald: PersonE? = PersonE(name: "donald", child: jenny)
donald?.pet = happy
//donald 인스턴스가 더이상 필요없으므로 메모리에서 해제됨
donald = nil
//donal가 jenny에게 happy를 인도함 -> 디이니셜라이저에서 구현돼있음
- 이니셜라이저 중복
//self.name이나 self.age처럼 이니셜라이저 내부에 중복되는 부분이 있을 경우
init(name: String, age: Int, nickName: String) {
self.name = name
self.nickName = nickName
self.age = age
}
init(name: String, age: Int) {
self.name = name
self.age = age
}
//아래처럼 만들어둔 이니셜라이즈로 대체할 수 있다
//자신의 이니셜라이저를 호출해줄때는 convinience를 붙여서!
convinience init(name: String, age: Int, nickName: String) {
self.init(name: String, age: Int)
self.age = age
}
init(name: String, age: Int) {
self.name = name
self.age = age
}
- 실패 가능한 이니셜라이저
이니셜라이저 매개변수로 전달되는 초기값이 잘못된 경우 인스턴스 생성에 실패할 수 있음.
→ 실패 시 nil 반환
따라서 실패가능한 이니셜라이저의 반환타입은 옵셔널 타입.
//실패가능한 이니셜라이저
class PersonD {
var name: String
var age: Int
var nickName: String?
init?(name: String, age: Int) {
if (0...120).contains(age) == false {
return nil
}
if name.count == 0 {
return nil
}
self.name = name
self.age = age
}
}
//에러 발생 -> 옵셔널이 아닌 타입으로 PersonD의 인스턴스 생성하려고 함
//let cock: PersonD = PersonD(name: "cock", age: 23)
let cock: PersonD? = PersonD(name: "cock", age: 23)
let jocker: PersonD? = PersonD(name: "jocker", age: 140)
let jin: PersonD? = PersonD(name: "", age: 30)
print(cock)
print(jocker) //OUTPUT : nil
print(jin) //OUTPUT : nil
- 디이니셜라이저
deinit은 클래스와 인스턴스가 메모리에서 해제되는 시점에 호출됨
인스턴스가 해제되는 시점에 해야할 일은 구현해주는 부분 → class 타입만 가능
// deinitializer
class PersonE {
var name: String
var pet: Puppy?
var child: PersonC
init(name: String, child: PersonC) {
self.name = name
self.child = child
}
deinit {
if let petName = pet?.name {
print("\(name)가 \(child.name)에게 \(petName)을 인도해줍니다.")
self.pet?.owner = child
}
}
}
var donald: PersonE? = PersonE(name: "donald", child: jenny)
donald?.pet = happy
//donald 인스턴스가 더이상 필요없으므로 메모리에서 해제됨
donald = nil
//donal가 jenny에게 happy를 인도함 -> 디이니셜라이저에서 구현돼있음
💡 unwrap하다 → ?를 뒤에 붙여서
- 에어컨을 타입으로 만들어보고 인스턴스를 생성해보자~
import Foundation
import Swift
//에어컨을 타입으로 만들어보고 인스턴스를 생성해보자!
//설계도(타입)
class Aircon {
var brand: String
var size: Int
var color: String?
init(brand: String, size: Int)
{
self.brand = brand
self.size = size
}
func turnOn(temp: Int) {
print("온도를 \(temp)도로 설정합니다")
}
}
let myAirCon: Aircon = Aircon(brand: "samsung", size: 180)
myAirCon.turnOn(temp: 23)
//OUTPUT : 온도를 23도로 설정합니다
💡 Swift Language - Initialization : [https://docs.swift.org/swift-book/LanguageGuide/Initialization.html](https://docs.swift.org/swift-book/LanguageGuide/Initialization.html)
💡 Swift Language - Deinitialization: [https://docs.swift.org/swift-book/LanguageGuide/Deinitialization.html](https://docs.swift.org/swift-book/LanguageGuide/Deinitialization.html)
💡 Swift Languea - Automatic Reference Counting : [https://docs.swift.org/swift-book/LanguageGuide/AutomaticReferenceCounting.html](https://docs.swift.org/swift-book/LanguageGuide/AutomaticReferenceCounting.html)
04. 구조체와 클래스
구조체와 클래스의 차이는 뭘까?
1. 초기화
import Foundation
//Error! 클래스 PersonA에 이니셜라이저 없다고 에러뜸
//인스턴스의 프로퍼티에 값이 있다는 것이 항상 보장되어야하기 때문
class PersonA {
var name: String
var age: Int
}
//구조체는 memberwise라는 기능을 제공해 에러가 발생하지 않는다.
struct PersonB {
var name: String
var age: Int
}
2. deinit
디이셜라이저는 클래스에만 제공되는 메서드
왜 클래스만? 구조체와 클래스는 메모리 위에서 관리되는 방식이 다르기 때문
3. 상속
클래스에서만 가능한 강력한 기능
4. mutating
구조체 : 자신의 프로퍼티값을 변경하는 메서드 앞에 mutating
키워드를 붙여야함.
import Foundation
class PersonA {
var name: String
var age: Int
init(name: String, age: Int) {
self.name = name
self.age = age
}
func addOneToAge() {
self.age += 1
}
}
struct PersonB {
var name: String
var age: Int
//mutating 키워드 없을 시 컴파일 에러!
mutating func addOneToAge() {
self.age += 1
}
}
let sally: PersonA = PersonA(name: "sally", age: 10)
sally.addOneToAge()
print(sally.age)
왜 구조체에는 이런 키워드가 필요할까? 👇
값 타입 vs 참조 타입
상속과 더불어 구조체와 클래스의 아주 중요한 차이점 !
- 구조체 : 값 타입(Value Type) → 인스턴스에 값을 전달 시 값을 복사하여 전달
- 클래스 : 참조 타입(Reference Type) → 인스턴스에게 값 전달 시 값을 참조하여 전달
예시코드의 결과를 예상해봅시당
import Foundation
class CameraA {
var color = "Black"
}
struct CameraB {
var color = "Black"
}
func printCameraColor() {
let str = """
CameraA (my: \(myCameraA.color), yours: \(yourCameraA.color))
CameraB (my: \(myCameraB.color), yours: \(yourCameraB.color))
"""
print(str)
}
var myCameraA = CameraA()
var yourCameraA = myCameraA
var myCameraB = CameraB()
var yourCameraB = myCameraB
printCameraColor()
print("------- myCamera 색을 변경합니다 --------")
myCameraA.color = "White"
myCameraB.color = "White"
printCameraColor()
OUTPUT
CameraA (my: Black, yours: Black)
CameraB (my: Black, yours: Black)
------- myCamera 색을 변경합니다 --------
CameraA (my: White, yours: White)
CameraB (my: White, yours: Black)
블로그에 글을 작성해서 친구에게 공유한다고 생각해보자.
- 블로그의 링크(주소값)을 전달하는 방법
- 블로그의 글을 복사해서 전달하는 방법
이렇게 두 가지가 있을 것임.
1번 방법으로 주소값을 통해 내 글을 참조하고 있는
Class
- 전통적인 OOP 관점에서의 클래스
- 단일상속
- (인스턴스/타입) 메서드
- (인스턴스/타입) 프로퍼티
- 참조 타입
- Apple 프레임워크의 대대분의 뼈대는 모두 클래스로 구성
Struct
- C언어 등의 구조체보다 다양한 기능
- 상속 불가
- (인스턴스/타입) 메서드
- (인스턴스/타입) 프로퍼티
- 값 타입
- Swift의 대부분의 큰 뼈대는 모두 구조체로 구성
Enum
- 다른 언어의 열거형과는 많이 다른 존재
- 상속 불가
- (인스턴스/타입) 메서드
- (인스턴스/타입) 연산 프로퍼티
- 값 타입
- Enumeration
- 유사한 종류의 여러 값을 유의미한 이름으로 한 곳에 모아 정의
- 열거형 자체가 하나의 데이터 타입
- 열거형의 case 하나하나 전부 유의미한 값으로 취급
- 선언 키워드 - enum
Class | Struct | Enum | |
---|---|---|---|
Type | Reference(참조) | Value | Value |
Subclassing(상속) | O | X | X |
Extension | O | O | O |
구조체는 언제 사용하나?
- 연관된 몇몇의 값들을 모아서 하나의 데이터타입으로 표현하고 싶을 때
- 다른 객체 또는 함수 등으로 전달될 때 참조가 아닌 복사를 원할 때
- 자신을 상속할 필요가 없거나, 자신이 다른 타입을 상속받을 필요가 없을때
- Apple 프레임워크에서 프로그래밍을 할 때에는 주로 클래스를 많이 이용
Value vs Reference
-
Value
데이터를 전달할 때 값을 복사하여 전달
-
Reference
데이터를 전달할 때 값의 메모리 위치를 전달
import Foundation
struct ValueType {
var property = 1
}
class ReferenceType {
var property = 1
}
//******** Struct ********\\
//구조체 ValueType의 인스턴스 생성
let firstStructInstance = ValueType()
var secondStrunctInstance = firstStructInstance
secondStrunctInstance.property = 2
print("first struct instance property : \(firstStructInstance.property)")
//OUTPUT : 1
print("secod struct instance property : \(secondStrunctInstance.property)")
//OUTPUT : 2
//******** Class ********\\
let firstClassInstance = ReferenceType()
//첫번째 인스턴스의 참조값을 두번째 인스턴스에 할당해줌
var secondClassInstance = firstClassInstance
secondClassInstance.property = 2
print("first class instance property : \(firstClassInstance.property)")
//OUTPUT : 2
print("second class instance property : \(secondClassInstance.property)")
//OUTPUT : 2
위 코드에선 fistClassInstance가 가리키는 class의 프로퍼티를 secondClassInstance도 가리키게 된다.
아래와 같은 코드는 어떨까?
//******** Class ********\\
let firstClassInstance = ReferenceType()
var secondClassInstance = ReferenceType()
secondClassInstance.property = 2
print("first class instance property : \(firstClassInstance.property)")
//OUTPUT : 1
print("second class instance property : \(secondClassInstance.property)")
//OUTPUT : 2
둘 다 각각의 클래스의 인스턴스가 되기 때문에
fistClassInstance가 가리키는 Class와 secondClassInstance가 가리키는 Class가 다르다.
인자로 전달된 인스턴스의 프로퍼티 값은 어떨까?
- 구조체의 경우
import Foundation
struct SomeStruct {
var someProperty: String = "Property"
}
//디폴트 인스턴스 새성
var someStructInstance: SomeStruct = SomeStruct()
//someFunction이라는 함수 생성 -> structInstance라는 매개변수명으로 구조체 SomeStruct를 받음
func someFunction(structInstance: SomeStruct) {
//내부 변수 생성 -> SomeStruct타입의 localVar에 structInstance 할당
var localVar: SomeStruct = structInstance
localVar.someProperty = "ABC"
}
someFunction(structInstance: someStructInstance)
print(someStructInstance.someProperty)
//OUTPUT : Property
위와 같은 결과가 나오는 이유는 뭘까?
someFunction에 SomeStruct가 인자로 넘어갈때, 그 값이 복사돼서 전달된다.
그러니 함수 스코프안에서 변경해주는 프로퍼티값은 SomeStruct의 원래 프로퍼티값이 아니라,
복사돼서 someFunction에 넘어간 프로퍼티 값이라는 것.
- 클래스의 경우
import Foundation
class SomeClass {
var someProperty: String = "Property"
}
var someClassInstance: SomeClass = SomeClass()
func someFunction(classInstance: SomeClass) {
var localVar: SomeClass = someClassInstance
localVar.someProperty = "ABC"
}
someFunction(classInstance: someClassInstance)
print(someClassInstance.someProperty)
Daty Types In Swift
- 스위프트는 (클래스보다)구조체, 열거형 사용을 선호
- Apple 프레임워크는 대부분 클래스 사용
- Apple 프레임워크 사용시 구조체/클래스 선택은 우리의 몫
05. 프로퍼티
프로퍼티 (Property)
: 타입(구조체, 클래스, 열거형) 내부 에 정의된 상수나 변수. 타입과 연관된 값 표현
프로퍼티의 역할에 따른 종류
우리가 여태까지 사용한 프로퍼티들은 모두 저장 프로퍼티
- 저장 프로퍼티 (stored property)
- 연산 프로퍼티 (computed property) →
var
로만 선언 가능 - 인스턴스 프로퍼티 (instance property)
- 타입 프로퍼티 (type property)
열거형 내부에는 연산 프로퍼티만 구현할 수 있다 !
ㅎㅏ는중.....
-
코드
import Foundation struct Student { //인스턴스 저장 프로퍼티 -> 값을 저장하기 위한 프로퍼티 var name: String = "" var `class`: String = "Swift" var koreanAge: Int = 0 //인스턴스 연산 프로퍼티 -> 특정한 연산을 수행해주기 위한 프로퍼티 var westerAge: Int { get { return koreanAge - 1 } set(inputValue) { koreanAge = inputValue + 1 } } //타입 저장 프로퍼티 -> 타입과 연관돼서 저장되야 할 프로퍼티 static var typeDescription: String = "학생" //인스턴스 메서드 -> 연산 프로퍼티가 대신해줄 수 있음(매개변수, 반환값 없는 경우) // func selfIntroduce() -> String { // print("저는 \(self.class)반 \(name)입니다") // } //위 펑션과 같은 기능을 하는 //읽기전용 인스턴스 연산 프로퍼티 var selfIntroduce: String { get { return "저는 \(self.class)반 \(name)입니다" } } //타입 메서드 // static func selfIntroduce() { // print("학생 타입입니다") // } //읽기전용 타입 연산 프로퍼티 //읽기전용에서는 get을 생략할 수 있음 static var selfIntroduction: String { return "학생타입 입니다" } //타입 연산 프로퍼티 사용 print(Student.selfIntroduction) //OUTPUT : 학생타입 입니다 //인스턴스 저장 프로퍼티 사용 }
06. 상속
상속 : 클래스 / 프로토콜에서 가능
클래스의 상속
: 부모 클래스가 자식 클래스에게 프로퍼티와 메서드를 물려주는 것
import Foundation
class Bus {
var passangerCapacity: Int = 40
var numverOfWheels: Int = 4
func go(to: String) {}
}
class Truck {
var loadageCapacity: Int = 1000
var numberOfWheels: Int = 4
func go(to: String) {}
}
class SportCar {
var maximumSpeed: Int = 360
var numberOfWheels: Int = 4
func go(to: String) {}
}
위의 코드를 보면 class들 간에 중복되는 코드들이 있다. 저걸 하나로 빼줄 수는 없을까?
아래와 같이 Vehicle
클래스를 만들어 상속받게 해보자.
class Vehicle {
var numverOfWheels: Int = 4
func go(to: String) {}
}
import Foundation
class Vehicle {
var numberOfWheels: Int = 4
func go(to: String) {}
}
class Bus: Vehicle {
var passangerCapacity: Int = 40
// var numberOfWheels: Int = 4
// func go(to: String) {}
}
class Truck: Vehicle {
var loadageCapacity: Int = 1000
// var numberOfWheels: Int = 4
// func go(to: String) {}
}
class SportCar: Vehicle {
var maximumSpeed: Int = 360
// var numberOfWheels: Int = 4
// func go(to: String) {}
}
var myCar: SportCar = SportCar()
print(myCar.numberOfWheels)
//OUTPUT : 4
서브클래싱 - 상속의 상속
- 예시 코드 1
import Foundation
class Vehicle {
var numberOfWheels: Int = 4
func go(to: String) {}
}
class Truck: Vehicle {
var loadageCapacity: Int = 1000
}
class DumpTruck: Truck {
func spillContents() {}
}
DumpTruck
은 Trcuk
의 모든 기능을 상속받는다. 물론 Vehicle
의 기능도 상속받음.
- 예시 코드 2
import Foundation
//Person - Studenct - Kchoi 의 클래스 상속 구조를 만들어보자
class Person {
var weight: Int = 60
func eat() {
weight += 1
}
}
class Student: Person {
var skillStack: String = "programming language"
func study() {
skillStack += " better"
}
}
var kchoi: Student = Student()
//var kchoi = Student()
print(kchoi.weight)
//OUTPUT : 60
kchoi.eat()
print(kchoi.weight)
//OUTPUT : 61
kchoi.skillStack = "flutter"
print(kchoi.skillStack)
//OUTPUT : flutter
kchoi.study()
print(kchoi.skillStack)
//OUTPUT : flutter better
override
override
: 재정의 구문
상속받은 클래스의 기능을 꼭 그대로 받지 않고 자식 클래스가 부모 클래스의 기능을 변경해줄 수 있다.
파라미터 재정의는 노노. 코드 블록 부분만 재정의 가능.
프로퍼티 재정의도 가능
프로퍼티 오버라이딩 시에는 상위 클래스에서 저장 프로퍼티였건 연산 프로퍼티였건 무조건 get, set을 모두 제공하는 연산 프로퍼티로 override해야함
그러다가 다시 부모 클래스의 기능을 그대로 사용하고 싶으면?
super
키워드로 호출해주면 된다.
import Foundation
//Person - Studenct - Kchoi 의 클래스 상속 구조를 만들어보자
class Person {
var weight: Int = 60
func eat() {
weight += 1
}
}
class Student: Person {
var skillStack: String = "programming language"
func study() {
skillStack += " better"
}
//override 키워드로 메서드 재정의
override func eat() {
weight += 5
}
//super 키워드로 부모 클래스의 메서드 그대로 사용
func eatAsPerson() {
super.eat()
}
}
final class
: 재정의 불가 타입 메서드 - static과 동일한 기능
영상 봐야함.. https://www.youtube.com/watch?v=T60mxyxxdys
💡 Inheritance : [https://docs.swift.org/swift-book/LanguageGuide/Inheritance.html](https://docs.swift.org/swift-book/LanguageGuide/Inheritance.html) 07. 옵셔널 체이닝과 nil 병합 연산자
옵셔널 체이닝
nil 병합 연산자
💡 Swift Language - Optional Chaining : [https://docs.swift.org/swift-book/LanguageGuide/OptionalChaining.html](https://docs.swift.org/swift-book/LanguageGuide/OptionalChaining.html)
💡 Swift Language - Basic Operators(Nil Coalescing Operator) : [https://docs.swift.org/swift-book/LanguageGuide/BasicOperators.html](https://docs.swift.org/swift-book/LanguageGuide/BasicOperators.html)
08. 객체지향 프로그래밍
객체지향 프로그래밍 패러다임
OOP : Object Oriented Programming
패러다임 : 관점, 시각
프로그램을 만드는 것을 어떻게 바라볼까 - 프로그래밍 패러다임
그 중에 하나가 객체지향 프로그래밍 패러다임
ㅎ ㅏ는중....
09. 타입의 설계
타입은 실제로 언제 사용하고, 어떤 과정을 거쳐서 설계할까?
프로그래밍에서 타입은 왜 필요할까?
Author And Source
이 문제에 관하여(Swift 기본 문법 #3), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@eelijus/Swift-기본-문법-3저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)