[Swift] 타입 캐스팅, assert, guard, 프로토콜

최승원·2022년 5월 31일
0

TIL (Today I Learned)

목록 보기
17/21
class Person {
    var name: String = ""
    func breath() {
        print("숨을 쉽니다")
    }
}

class Student: Person {
    var school: String = ""
    func goToSchool() {
        print("등교를 합니다")
    }
}

class UniversityStudent: Student {
    var major: String = ""
    func goToMT() {
        print("멤버십 트레이닝을 갑니다 신남!")
    }
}

var yagom: Person = Person()
var hana: Student = Student()
var jason: UniversityStudent = UniversityStudent()

is를 사용하여 타입 확인

// is를 사용하여 타입 확인
var result: Bool

result = yagom is Person // true
result = yagom is Student // false
result = yagom is UniversityStudent // false

result = hana is Person // true
result = hana is Student // true
result = hana is UniversityStudent // false

result = jason is Person // true
result = jason is Student // true
result = jason is UniversityStudent // true

업 캐스팅

// 업 캐스팅
// as를 사용하여 부모클래스의 인스턴스로 사용할 수 있도록 함
var mike: Person = UniversityStudent() as Person
var jenny: Student = Student()
var jina: Any = Person() // as Any 생략 가능

다운 캐스팅

다운 캐스팅은 as?와 as!를 사용하여 자식 클래스의 인스턴스로 사용할 수 있도록 하는 것이다.

// 조건부 다운 캐스팅 - as?를 사용
var optionalCasted: Student?

optionalCasted = mike as? UniversityStudent // mike는 할당된 인스턴스가 UniversityStudent이기 때문에 캐스팅 가능
optionalCasted = jenny as? UniversityStudent // nil
optionalCasted = jina as? UniversityStudent // nil
optionalCasted = jina as? Student // nil

// 강제 다운 캐스팅 - as!를 사용
optionalCasted = mike as! UniversityStudent
optionalCasted = jenny as! UniversityStudent // 런타임 에러
optionalCasted = jina as! UniversityStudent // 런타임 에러
optionalCasted = jina as! Student // 런타임 에러

assert

// assert 함수는 조건에 잘 맞는지 확인할 때 사용할 수 있음
// 디버깅 모드에서만 작동
var someInt: Int = 0

someInt = 1

// 앞의 조건에 맞으면 assert 함수를 넘어가고
// 맞지 않으면 뒤의 문자열을 출력
assert(someInt == 0, "someInt != 0") // 동작 중지, 검증 실패

// 문자열 출력은 생략 가능
assert(someInt == 0) // 동작 중지, 검증 실패

guard

// guard 구문은 Early Exit(빠른 종료)를 위해 사용
func functionWithGuard(age: Int?) {
    // optional binding(안전한 unwrapping)과 연결
    guard let unwrappedAge = age,
          unwrappedAge < 130,
          unwrappedAge >= 0 else {
        print("나이값 입력이 잘못되었습니다")
        // 반드시 return이 있어야 함
        return
    }
    print("당신의 나이는 \(unwrappedAge)세입니다")
}

프로토콜

// protocol은 어떤 기능을 구현하라고 강요하는 것
// 채택: protocol의 기능을 구현한다고 하는 것
// protocol을 준수한다: 실제로 protocol의 기능을 구현했을 때
protocol Talkable {
    // 프로퍼티 요구
    // 항상 var 키워드 사용
    var topic: String { get set } // 읽기, 쓰기 모두 가능
    var language: String { get } // 읽기 가능
    var language2: String { get }
    
    // 메서드 요구
    func talk()
    
    // 이니셜라이저 요구
    init(topic: String, language: String)
}

// Person 구조체는 Talkable 프로토콜을 채택
struct Person: Talkable {
    var topic: String
    let language: String // let은 읽기만 가능, 그러나 var 사용해도 됨
    
    // 읽기 전용 프로퍼티 요구는 읽기 전용 연산 프로퍼티로 대체 가능
    var language2: String { return "한국어" }
    
    func talk() {
        print("\(topic)에 대해 \(language)로 말합니다")
    }
    
    init(topic: String, language: String) {
        self.topic = topic
        self.language = language
    }
}

프로토콜의 상속

// 프토토콜은 다중 상속 가능
protocol Readable {
    func read()
}

protocol Writeable {
    func write()
}

protocol ReadWriteSpeakable: Readable, Writeable {
    // func read()
    // func write()
    func speak()
}

// "클래스의 상속"과 "프로토콜의 채택"을 동시에 하려면
// "클래스의 상속"을 먼저 명시해야 함
class SuperClass: Readable {
    func read() { print("read") }
}

class SubClass: SuperClass, Writeable, ReadWriteSpeakable {
    func write() { print("write") }
    func speak() { print("speak") }
}

프로토콜 준수 확인

// is, as 연산자를 사용하여 프로토콜을 준수하는지 확인할 수 있음
let sup: SuperClass = SuperClass()
let sub: SubClass = SubClass()

var someAny: Any = sup
someAny is Readable // true
someAny is ReadWriteSpeakable // false

if let someReadalbe: Readable = someAny as? Readable {
    someReadalbe.read()
} // read

if let someReadWriteSpeakable: ReadWriteSpeakable = someAny as? ReadWriteSpeakable {
    someReadWriteSpeakable.speak()
} // 동작하지 않음
profile
문의 사항은 메일로 부탁드립니다🙇‍♀️

0개의 댓글