[Swift] 문법8 - Protocol

LeeEunJae·2023년 3월 19일
0

iOS

목록 보기
9/14
post-custom-banner

📌 프로토콜

프로토콜은 인터페이스 입니다. 최소한으로 가져야할 속성이나 메서드를 정의합니다. 구현은 하지 않습니다.

protocol Sendable {
    var from: String? { get }
    var to: String { get }
    
    func send()
}

클래스와 구조체에 프로토콜을 적용(Confirm)할 수 있습니다. 프로토콜을 적용하면 프로토콜에서 정의한 속성과 메서드를 모두 구현해야합니다.

protocol Sendable {
    var from: String? { get }
    var to: String { get }
    
    func send()
}

struct Mail: Sendable {
    var from: String?
    var to: String
    
    func send() {
        print("Send a mail from \(self.from) to \(self.to)")
    }
}

struct Feedback: Sendable {
    var from: String? {
        return nil
    }
    var to: String
    
    func send() {
        print("Send a feedback to \(self.to)")
    }
}

프로토콜은 추상클래스처럼 사용할 수 있습니다.

func sendAnything(_ sendable: Sendable) {
  sendable.send()
}

let mail = Mail(from: "dldmswo1209@gmail.com", to: "ylee886@naver.com")
sendAnything(mail)

let feedback = Feedback(to: "ylee886@naver.com")
sendAnything(feedback)

sendAnything은 Sendable 타입 파라미터를 받습니다. mail과 feedback 은 엄연히 다른 타입이지만, 모두 Sendable 프로토콜을 적용했으므로 sendAnything() 의 파라미터로 전달할 수 있습니다.
그리고 Sendable 에서는 send() 를 정의했으므로 호출 가능합니다.

프로토콜은 또 다른 프로토콜을 적용할 수 있습니다.

protocol Messagable {
    var message: String? { get }
}

protocol Sendable: Messagable {
    var from: String? { get }
    var to: String { get }
    
    func send()
}

Sendable은 Messagable 프로토콜을 따르는 프로토콜입니다. 따라서 Sendable 을 적용받는 구조체나 클래스에서는 message 속성을 구현해야 합니다.

📌 Any 와 AnyObject

Any 는 모든 타입에 대응, AnyObject 는 모든 객체에 대응합니다.

let anyNumber: Any = 10
let anyString: Any = "Hi"

let anyInstance: AnyObject = Dog()

Any 와 AnyObject 는 프로토콜입니다. Swift 에서 사용가능한 모든 타입은 Any 를 따르도록 설계되었고, 모든 클래스는 AnyObject 프로토콜이 적용되어있습니다.

📌 타입 캐스팅

anyNumber 에 10을 넣었다고 해서 Int가 아닙니다. Any 프로토콜을 따르는 어떤 값이기 때문에 Int 타입의 1과 연산을 하면, 컴파일 에러가 발생합니다.

print(anyNumber + 1) // 컴파일 에러

이럴 때에는 as 를 이용해서 다운 캐스팅 (Down Casting)을 해야합니다. Int는 Any를 따르는 타입이기 때문에 Int보다 Any의 범주가 더 크겠죠. 따라서 다운 캐스팅 입니다.
Any 는 Int뿐 아니라 다른 타입들도 포함하고 있으므로 무조건 Int 로 변환된다는 보장이 없습니다.
따라서 as? 를 사용해서 옵셔널을 취해야 합니다.

let number: Int? = anyNumber as? Int

옵셔널이기 때문에 옵셔널 바인딩을 바로 적용할 수 있겠죠.

if let number = anyNumber as? Int {
  print(number + 1)
}

📌 타입 검사

타입 캐스팅까지는 필요없고, 타입 검사만 하면 될 때 is 를 사용하면 됩니다.

print(anyNumber is Int) // true
print(anyNumber is String) // false
print(anyNumber is Bool) // false
print(anyNumber is Float) // false
print(anyNumber is Double) // false
profile
매일 조금씩이라도 성장하자
post-custom-banner

0개의 댓글