[Swift] 타입 캐스팅

임승섭·2023년 6월 23일
0

Swift

목록 보기
10/35

타입 캐스팅 (Type Casting)

is 연산자 (type check operator)

  • 타입에 대한 검사 수행
  • true or false 리턴
  • 이항연산자 형태
class Person {
    var id = 0
    var name = "이름"
    var email = "abc@gmail.com"
}


class Student: Person {
    // id
    // name
    // email
    var studentId = 1
}



class Undergraduate: Student {
    // id
    // name
    // email
    // studentId
    var major = "전공"
}

let person1 = Person()
let student1 = Student()
let undergraduate1 = Undergraduate()


/*type check*/
person1 is Person                // true
person1 is Student               // false
person1 is Undergraduate         // false

student1 is Person               // true
student1 is Student              // true
student1 is Undergraduate        // false

undergraduate1 is Person         // true
undergraduate1 is Student        // true
undergraduate1 is Undergraduate  // true

as 연산자 (type cast operator)

다운캐스팅

  • as? : Optional 타입으로 리턴
    • 실패 시 nil 리턴
  • as! : Optional 타입을 강제 언래핑한 타입 리턴
    • 실패 시 런타임 오류

업캐스팅

  • 타입캐스팅 항상 성공
/*다운캐스팅*/

// 선언은 Undergraduate -> 메모리에 5개의 저장 속성은 가지고 있다
// 타입은 Person -> 저장 속성이 3개만 보이게 한다 (3개 항목만 접근 가능하게 한다)
let person: Person = Undergraduate()
person.id
person.name
person.email
//person.studentId	// 에러


// Undergraduate 타입으로 변환해서 새로운 변수에 담는다
// ppp의 타입은 Optional Undergraduate
let ppp = person as? Undergraduate		


// 아예 처음부터 if let 바인딩 해서 옵셔널 벗긴 걸 ppp에 저장
if let ppp = person as? Undergraduate {
	ppp.id
    ppp.name
    ppp.email
    ppp.studentId
    ppp.major
}

// 강제 다운캐스팅 (타입 변환이 되지 않으면 에러)
let ppp = person as! Undergraduate



// 만약, 처음에 선언할 때 Person으로 선언해놓고 그걸 캐스팅하려고 하면 nil 리턴!!




/*업캐스팅*/

let undergraduate2: Undergraduate = Undergraduate()


let person4 = undergraduate2 as Person       // 항상 성공
person4.id
person4.name
//person4.studentId
//person4.major

상속과 다형성(Polymorphism)

  • 다형성 : 하나의 인스턴스(객체)가 여러가지 타입의 형태로 표현될 수 있다.
  • 다형성의 구현은 클래스의 상속과 밀접한 관련이 있다.
// 3개의 클래스
class Person {
	var id = 0
    var name = "이름"
    var email = "abc@gmail.com"
    
    func walk() {
    	print("사람이 걷는다.")
    }
}

class Student: Person {
	var studentId = 1
    
    override func walk() {
    	print("학생이 걷는다.")
    }
    
    func study() {
    	print("학생이 공부한다.")
    }
}

class Undergraduate: Student {
	var major = "전공"
   
   	override func walk() {
    	print("대학생이 걷는다.")
    }
    
    override func study() {
    	print("대학생이 공부한다.")
    }
    
    func party() {
    	print("대학생이 파티를 한다.")
    }
}

let person1 = Person()
person1.walk()						// 사람이 걷는다
let student1 = Student()
studetn1.walk()						// 학생이 걷는다
student1.study()					// 학생이 공부한다
let undergraduate1 = Undergraduate()
undergraduate1.walk()				// 대학생이 걷는다
undergraduate1.study()				// 대학생이 공부한다
undergraduate1.party()				// 대학생이 파티를 한다



// 타입 캐스팅 (다형성)
// 교재 그림 확인 - 어떤 붕어빵 틀을 가리키고 있는지 확인하자
let student2: Person = Student()
student2.walk()						// 학생이 걷는다
// student2.study()					// 에러
let undergraduate2: Person = Undergraduate()
undergraduate2.walk()				// 대학생이 걷는다
// undergraduate2.study()			// 에러


let people: [Person] = [Person(), Student(), Undergraduate()]	// Person 타입의 array이기 때문에 세 개를 다 담을 수 있다.

person[0].walk	// Person 타입으로 인식 (Person 인스턴스)
person[1].walk	// Person 타입으로 인식 (Student 인스턴스)
person[2].walk	// Person 타입으로 인식 (Undergraduate 인스턴스)
  • 업캐스팅된 타입(Person) 형태의 메서드를 호출하더라도,
    실제 메모리에서 구현된 "재정의된" 메서드가 호출되어 실행된다.
  • 타입의 저장 형태는 속성/메서드에 대한 접근 가능 범위를 나타내는 것이고,
    다형성은 인스턴스에서 메모리의 실제 구현 내용에 대한 것.
  • 메서드는 재정의 가능하고 메서드 테이블을 통해 동작

Any와 AnyObject를 위한 타입 캐스팅

  • Any 타입
    • 기본 타입(Int, String, ...) 등 포함, 커스텀 클래스, 구조체, 열거형, 함수 타입까지 포함해서
      어떤 타입의 인스턴스도 표현할 수 있는 타입.
    • 옵셔널 타입도 가능
    • 항상 타입캐스팅 해서 사용해야 한다
  • AnyObject 타입
    • 어떤 클래스 타입의 인스턴스도 표현할 수 있는 타입
/*Any 타입*/

var some: Any = "Swift"
some = 1.0		// 정상적으로 동작
some = 3.2

// (주의) 저장된 타입의 메모리 구조를 알 수 없기 때문에 항상 타입캐스팅해서 사용해야 한다
var some2: Any = "Hello"
(some2 as! String).count	// 이렇게 해야 문자열 함수 count 사용 가능


class Person {
    var name = "이름"
    var age = 10
}

class Superman {
    var name = "이름"
    var weight = 100
}

// Any타입의 장점: 모든 타입을 담을 수 있는 배열을 생성 가능  
let array: [Any] = [5, "안녕", 3.5, Person(), Superman(), {(name: String) in return name}]



/*AnyObject 타입*/

// 클래스의 인스턴스만 담을 수 있다.
let objArray: [AnyObject] = [Person(), Superman(), NSString()]
(objArray[0] as! Person).name



/*타입캐스팅 + 분기처리*/
for (index, item) in array.enumrated() {	// array : Any 타입의 배열
	switch item {
    case is Int:							// is 연산자 (item is Int)
    	print("정수입니다")			
    case let num as Double:					// as 연산자를 사용할 때는 바인딩 이용 (let num = item as Double)
    	print("소수입니다")
    case let String:						
    	print("문자열입니다")
    case let person as Person:				// let person = item as Person
    	print("사람입니다.")
        print("이름은 \(person.name) 입니다")
        print("나이는 \(person.age) 입니다")
    case is (String) -> String:				// item is (String) -> String
    	print("클로저 타입입니다")
    default:
    	print("그 외의 타입입니다.")
    }
}

0개의 댓글