본문 바로가기
아이폰 개발/Swift

swift 기초 - 옵셔널 체이닝, 타입캐스팅

by 인생여희 2021. 3. 5.

swift 기초 - 옵셔널 체이닝, 타입캐스팅

 

 [1] 옵셔널 체이닝  

 

 [1-1] 옵셔널 체이닝

 옵셔널 체이닝은 옵셔널 요소 내부의 프로퍼티로

 또다시 옵셔널이 연속적으로 연결되는 경우 유용하게 사용할 수 있다.

 

 

[1-2] 예제 클래스 및 인스턴스 생성

//사람 클래스
class Person {
    var name : String
    var job:String?         // 직업 - 옵셔널
    var home: Apartment?      //집 - 옵셔널
    
    //이름 초기화 메소드
    init(name:String) {
        self.name = name
    }
}

//아파트 클래스
class Apartment {

    var buildingNumber : String     //동
    var roomNumber: String        //호수
    var guardMan : Person?       //경비원 - 옵셔널
    var owner : Person?         //주인 - 옵셔널

    //초기화 메소드 : 동, 호수
    init(dong:String , ho:String) {
        buildingNumber = dong
        roomNumber = ho
    }
}

let kim :Person? = Person(name: "kimdongsu")
let apartment : Apartment? = Apartment(dong: "18", ho: "610")
let superman : Person? = Person(name: "superman")

 

 

 옵셔널 체이닝이 실행 후 결과 값이 nil 일 수 있으므로

 결과 타입도 옵셔널이다.

 

 

우리집 경비원의 직업은?

[1-3] 옵셔널 사용하지 않는 예제

func guardJob(owner:Person?) {
    
    if let owner = owner{
        
        if let home = owner.home {
            
            if let guardman = home.guardMan {
             
                if let guardmanJob = guardman.job{
                    print("우리집 경비원의 직업은 \(guardmanJob) 입니다.")
                }else{
                    print("우리집 경비원은 직업이 없어요")
                }
            }
        }
    }
}
//호출
guardJob(owner: kim)

 

 

[1-4] 옵셔널 사용하는 예제

func guardJobWithOptionalChaining(owner:Person?) {
 
    if let guardJob = owner?.home?.guardMan?.job{
        print("우리집 경비원의 직업은 \(guardJob) 입니다.")
    }else{
        print("우리집 경비원은 직업이 없어요")
    }
    
}
//호출
guardJobWithOptionalChaining(owner: kim)

 

 

출력

print(kim?.home?.guardMan?.job) //nil

//집 할당
kim?.home = apartment

print(kim?.home) //Optional(test2.Apartment)

print(kim?.home?.guardMan) //nil

//경비원 할당
kim?.home?.guardMan = superman


print(kim?.home?.guardMan) //Optional(test2.Person)

print(kim?.home?.guardMan?.name) //Optional("superman")

print(kim?.home?.guardMan?.job) //nil

//경비원 직업 할당.
kim?.home?.guardMan?.job = "슈퍼경비원!"

 

 

[2] 타입 캐스팅

 

 스위프트의 타입캐스팅은 인스턴스의 타입을 확인하는 용도

 또는 클래스의 인스턴스를 부모 혹은 자식 클래스 타입으로 사용할 수 있는지 확인하는 용도로 사용한다.

 is, as 를 사용한다.

 

 

[2-1] 타입 캐스팅을 위한 클래스 정의

//슈퍼 클래스
class PersonA {
    var name: String = ""
    func breath() {
        print("숨을쉬어요")
    }
}

//서브 클래스 - 1
class Student: PersonA {
    var school : String = ""
    func gotoSchool() {
        print("등교를 합니다..")
    }
}

//서브 클래스 - 2
class UniversityStudent: Student {
    var major : String = ""
    func gotoMT(){
        print("엠티를 갑니다~")
    }
}

//인스턴스 객체 생성
var dongsoo : PersonA = PersonA()
var minwoo : Student = Student()
var jassy : UniversityStudent = UniversityStudent()

 

 

[2-2] 타입 확인 - is 를 사용해서 타입을 확인

var result : Bool

result = dongsoo is PersonA             //true
result = dongsoo is Student             //false : dongsoo 객체는 Student 클래스의 슈퍼 클래스이다.
result = dongsoo is UniversityStudent       //false dongsoo 객체는 Student 클래스의 슈퍼 슈퍼 클래스이다.

result = minwoo is PersonA              //true
result = minwoo is Student              //true
result = minwoo is UniversityStudent        //false : minwoo 객체는 UniversityStudent 클래스의 슈퍼 클래스이다.

result = jassy is PersonA               //ture
result = jassy is Student               //true
result = jassy is UniversityStudent         //true


//dongsoo 객체의 타입 구하기
//dongsoo 는 PersonA 타입이다.

if dongsoo is UniversityStudent {
    print("동수는 대학생입니다.")
}else if dongsoo is Student{
    print("동수는 학생입니다.")
}else if dongsoo is PersonA{
    print("동수는 사람입니다.") //동수는 사람입니다.
}

//jassy 객체의 타입 구하기
switch jassy{
case is PersonA :
    print("jassy는 사람입니다.")
case is Student :
    print("jassy는 학생입니다.")
case is UniversityStudent :
    print("jassy는 대학원 생입니다.") //jassy는 사람입니다.
}

switch jassy {
case is UniversityStudent:
    print("jassy은 대학생입니다")
case is Student:
    print("jassy은 학생입니다")
case is PersonA:
    print("jassy은 사람입니다")
default:
    print("jassy은 사람도, 학생도, 대학생도 아닙니다")
} // jassy은 대학생입니다

 

 

 [2-3] 업캐스팅

 as 를 사용하여 부모 클래스의 인스턴스로 사용할 수 있도록

 컴파일러에게 타입정보를 전환해준다.

 Any 혹은 AnyObject로도 타입정보를 변환할 수 있다

 암시적으로 처리되므로 생략해도 무방하다.

 

 

var mike : PersonA = UniversityStudent() as PersonA
var jenny : Student = Student()
var jina : Any = PersonA() // as Any 생략가능

print(mike)     //test2.UniversityStudent
print(jenny)    //test2.Student
print(jina)     //test2.PersonA

 

 

 [2-4] 다운캐스팅

 as? 또는 as! 를 사용하여 자식 클래스의 인스턴스로 사용할 수 있도록

 컴파일러에게 인스턴스의 타입정보를 전환해준다.

 

// as? 조건부 다운 캐스팅
var optionCasted:Student?

optionCasted = mike as? UniversityStudent       //메모리 주소
optionCasted = jenny as? UniversityStudent      //nil
optionCasted = jina as? UniversityStudent       //nil
optionCasted = jina as? Student             //nil



//as! 강제 다운캐스팅
var forcedCasted: Student

forcedCasted = mike as! UniversityStudent
//forcedCasted = jenny as! UniversityStudent      //런타임 오류
//forcedCasted = jina as! UniversityStudent       //런타임오류
//forcedCasted = jina as! Student             //런타임오류

 

 

[2-5] 강제 다운 캐스팅 활용

func doSomethingWithSwitch(someone:PersonA) {
    
    switch someone {
    case is UniversityStudent:
        //강제 다운캐스팅
        (someone as! UniversityStudent).gotoMT()
        
    case is Student:
        (someone as! Student).gotoSchool()
        
    case is PersonA:
        (someone as! PersonA).breath()
    }
}

doSomethingWithSwitch(someone: mike as PersonA)  //엠티를 갑니다~
doSomethingWithSwitch(someone: mike)          //엠티를 갑니다~
doSomethingWithSwitch(someone: jenny)         //등교를 합니다..
doSomethingWithSwitch(someone: dongsoo)        //숨을쉬어요

 

 

[2-6] 조건부 다운캐스팅 예제 함수

func doSomething(someone:PersonA) {
    
    if let universityStudent = someone as? UniversityStudent {
        
        universityStudent.gotoMT()
        
    }else if let student = someone as? Student {
        
        student.gotoSchool()
        
    }else if let person = someone as? PersonA{
     
        person.breath()
    }
    
}

doSomething(someone: mike as PersonA)   // 엠티를 갑니다~
doSomething(someone: mike)          // 엠티를 갑니다~
doSomething(someone: jenny)         // 등교를 합니다..
doSomething(someone: dongsoo)        // 숨을쉬어요

 

 

 

test2.zip
0.02MB

 

 

 

참고

blog.yagom.net/