티스토리 뷰

Swift

Swift [Any, AnyObject]

이도형 2023. 2. 25. 18:20

INDEX

1.  Any

2.  AnyObject

3. 옵셔널 값의 Any

4.  다형성(polymorphism)을 통한 타입캐스팅 복습

5.  마무리

 

이번 포스팅은 쉬어가는 느낌? 

짧고 간단하다. 

Any는 원래 익숙하며, AnyObject는 class에만 한정된 타입으로 타입캐스팅만 알고있다면 금방 이해할 수 있다.

1.  Any

Any타입은 기본타입(Int, string, Double...), 클래스, 구조체, 열거형, 함수, 옵셔널타입까지 포함하여

어떤 타입의 인스턴스도 표현 가능한 타입을 뜻한다.

 

var some: Any = "Swift"
some = 10
some = 3.2
some = "String!!"

단점은 저장된 타입의 메모리구조를 알 수 없기에, 항상 타입캐스팅을 해서 사용해야한다.

 

Any타입의 as!로 타입캐스팅

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

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


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


//array[1].count
(array[1] as! String).count

 

 

2.  AnyObject

AnyObject타입은 어떤 클래스타입의 인스턴스만 표현할 수 있는 타입으로

Any에 비해 타입이 클래스로 한정적이다.

(아래 예제에서 switch문에서는 let에 바인딩 성공시 실패하지 않는다는 확신이 있기에 as로 타입캐스팅 한 것)

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

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

let objArray: [AnyObject] = [Person(), Superman(), NSString()]

//objArray[0].name
(objArray[0] as! Person).name //이름

// 타입캐스팅 + 분기처리

for (index, item) in array.enumerated() {
    // (0,  5)
    // (1, "안녕")
    // (2, 3.5)
    // ...
    
    switch item {
    case is Int:                                  // item is Int
        print("Index - \(index): 정수입니다.")
    case let num as Double:                       // let num = item as Double
        print("Index - \(index): 소수 \(num)입니다.")
    case is String:                               // item is String
        print("Index - \(index): 문자열입니다.")
    case let person as Person:                    // let person = item as Person
        print("Index - \(index): 사람입니다.")
        print("이름은 \(person.name)입니다.")
        print("나이는 \(person.age)입니다.")
    default:
        print("Index - \(index): 그 이외의 타입입니다.")
    }
}

//Index - 0: 정수입니다.
//Index - 1: 문자열입니다.
//Index - 2: 소수 3.5입니다.
//Index - 3: 사람입니다.
//이름은 이름입니다.
//나이는 10입니다.
//Index - 4: 그 이외의 타입입니다.

 

Any, AnyObject의 🍎공식문서 예제(switch문으로 일대일 매칭시키면된다) ⭐️인스턴스 as 타입⭐️

 

var things: [Any] = []

things.append(0)
things.append(0.0)
things.append(42)
things.append(3.14159)
things.append("hello")
things.append((3.0, 5.0))
things.append(Movie(name: "Ghostbusters", director: "Ivan Reitman"))
things.append({ (name: String) -> String in "Hello, \(name)" }) //클로저

for thing in things {
    switch thing {
    case 0 as Int:
        print("zero as an Int")
    case 0 as Double:
        print("zero as a Double")
    case let someInt as Int:
        print("an integer value of \(someInt)")
        //where절을 통한 조건 추가
    case let someDouble as Double where someDouble > 0:
        print("a positive double value of \(someDouble)")
    case is Double:
        print("some other double value that I don't want to print")
    case let someString as String:
        print("a string value of \"\(someString)\"")
    case let (x, y) as (Double, Double):
        print("an (x, y) point at \(x), \(y)")
    case let movie as Movie:
        print("a movie called \(movie.name), dir. \(movie.director)")
    case let stringConverter as (String) -> String: //클로저 타입이야?
        print(stringConverter("Michael"))
    default:
        print("something else")
    }
}

// zero as an Int
// zero as a Double
// an integer value of 42
// a positive double value of 3.14159
// a string value of "hello"
// an (x, y) point at 3.0, 5.0
// a movie called Ghostbusters, dir. Ivan Reitman
// Hello, Michael

 

3. 옵셔널 값의 Any

의도적인 옵셔널값의 사용

Any는 모든 타입을 포함하므로, 의도적인 옵셔널값을 사용하려면

Any타입으로 변환하면 컴파일러가 알려주는 경고를 없앨 수 있음

 

WHY?

- 옵셔널값은 임시적인 값일 뿐이므로, 일반적으로 개발자들은 옵셔널 바인딩을 해서

  언래핑해서 안의 값을 사용해야함 ===> 그래서 경고를 통해 알려줌

  (Any로 변환하겠다는 것은 그 자체를 사용하겠다는 의미임 ===> 경고 사라짐)

 

let optionalNumber: Int? = 3
print(optionalNumber)          // 경고
print(optionalNumber as Any)   // 경고 없음

 

4.  다형성(polymorphism)을 통한 타입캐스팅 복습

다형성이란?

하나의 객체(instance of class)가 여러타입으로 저장되고, 다양한 방식으로 동작하는 것

=> 차후 포스팅할 주요 단원 프로토콜(protocol)에서도 중요

업캐스팅된 타입(Person) 형태의 메서드를 호출하더라도

실제 메모리에서 구현된 재정의된(overriding)된 메서드가

호출되어 실행⭐️

타입의 저장 형태는 속성/메서드에 대한 접근가능 범위를 나타내는 것이고,

다형성은 인스턴스에서 메모리의 실제 구현 내용에 대한 것이다.(메서드는 재정의 가능하고, 메서드 테이블을 통해 동작)

 

class Person {
    var id = 0
    var name = "이름"
    var email = "abc@gmail.com"
    
    func walk() {
        print("사람이 걷는다.")
    }
}


class Student: Person {
    // id
    // name
    // email
    var studentId = 1
    
    override func walk() {         // 재정의 메서드. walk() - 1
        print("학생이 걷는다.")
    }
    
    func study() {
        print("학생이 공부한다.")
    }
}



class Undergraduate: Student {
    // id
    // name
    // email
    // studentId
    var major = "전공"
    
    override func walk() {       // 재정의 메서드. walk() - 2
        print("대학생이 걷는다.")
    }
    
    override func study() {      // 재정의 메서드. study() - 1
        print("대학생이 공부한다.")
    }
    
    func party() {
        print("대학생이 파티를 한다.")
    }
}

let person1 = Person()
person1.walk()

//let student1 = Student()
let student1: Person = Student()
student1.walk()
//student1.study() //Person타입이므로 접근불가

//let undergraduate1 = Undergraduate()
let undergraduate1: Person = Undergraduate()
undergraduate1.walk()
//undergraduate1.study() //Person타입이므로 접근불가
//undergraduate1.party() //Person타입이므로 접근불가

let people: [Person] = [Person(), Student(), Undergraduate()]

// 반복문
for person in people {
    person.walk()
}

//사람이 걷는다.
//학생이 걷는다.
//대학생이 걷는다.

// 한개씩
people[0].walk()     // Person 타입으로 인식 (Person 인스턴스)
people[1].walk()     // Person 타입으로 인식 (Student 인스턴스)
people[2].walk()     // Person 타입으로 인식 (Undergraduate 인스턴스)
//사람이 걷는다.
//학생이 걷는다.
//대학생이 걷는다.

 

5.  마무리

Any와 Anyobject의 차이가 무엇인지,

옵셔널과 Any타입의 관계,

다형성으로 정의된 메서드 예제를 통해

타입캐스팅이 더 쉬워졌다면 PASS

 

 

출처

Inflearn Allen님의 강의 노트

Swift 공식문서

야곰님의 스위프트 프로그래밍 3판

 

반응형
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
글 보관함