Swift - Protocol(2_특징, 확장)

이한솔·2023년 9월 19일
0

Swift 문법 🍎

목록 보기
25/32

Protocol의 특징

swift에서 Protocol은 함수, 클로저와 같이 1급 객체다.

일급 객체의 특징

  1. 객체가 런타임에 생성된다.
  2. 변수, 상수의 타입으로 사용할 수 있다.
    해당 프로토콜의 객체를 생성해서 쓰는게 아니라 해당 프로토콜을 채택한 구조체, 클래스, 열거형의 인스턴스를 프로토콜 타입으로 타입캐스팅 해서 사용하는 것이다.
protocol Person {
    var name: String { get }
}

struct StructPerson: Person {
    var name = "hansol"
    var age = 19
}

// 상수 p는 person이라는 프로토콜 타입
let personProtocol: Person

// Person 프로토콜을 채택한 StructPerson의 인스턴스를 person 프로토콜 타입인 상수 p에 대입 가능하다.
personProtocol = StructPerson()

personProtocol.name // 프로토콜에서 정의된 프로퍼티에는 접근 가능
personProtocol.age // Error: Value of type 'any Person' has no member 'age'

if let structPerson = personProtocol as? StructPerson {
    print(structPerson.age) // 출력값: 19
} else {
    print("타입캐스팅 실패")
}
  1. 함수의 파라미터 타입과 반환 타입으로 사용할 수 있다.
protocol Person {
    var name: String { get }
}

struct StructPerson: Person {
    var name = "sol"
}

let p: Person = StructPerson()

func printName(someProtocol: Person) -> String {
    return someProtocol.name
}

printName(someProtocol: p) // 출력값: sol


// 타입 확인 
let test = "s"

p is Person // true
test is Person // false


Protocol의 확장

프로토콜을 채택하는 여러 곳에서 같은 기능을 하는 메소드를 여러번 반복해서 쓸 경우, 프로토콜을 extension해서 기본적으로 제공할 기능을 구현할 수 있다. 프로퍼티는 연산 프로퍼티만 확장해서 사용할 수 있다.

protocol Person {
    var name: String { get }
    func canSpeak()
}

struct StructPerson: Person {
    var name = "sol"
    func canSpeak() {
        print("말할 수 있다.")
    }
}

class APerson: Person {
    var name = "hansol"
    func canSpeak() {
        print("말할 수 있다.")
    }
}


// extension을 통해 기본적으로 제공할 프로퍼티, 기능 구현
// 프로토콜에 선언된 프로퍼티를 extension을 통해 연산 프로퍼티로 기본값을 줄 수 있다.
extension Person {
    var name: String {
        "extension Name"
    }
    func canSpeak(){
        print("말할 수 있다.")
    }
}

class BPerson: Person {
}

let a = APerson()
a.canSpeak() // 출력값: 말할 수 있다.

// BPerson 클래스에 따로 프로퍼티와 메소드를 구현하지 않았지만, extension에 작성해둔것이 호출된다.
let b = BPerson()
print(b.name) // extension Name
b.canSpeak() // 출력값: 말할 수 있다.


// extension에 구현되어있는 기능 외에 다른 기능을 사용하고 싶을 경우, 기존과 동일하게 따로 정의해주면 된다.
class cPerson: Person {
    var name = "Tom"
    
    func canSpeak() {
        print("\(name)은 말할 수 있다.")
    }
}

// extension에 선언된 메소드보다 직접 구현한 메소드의 우선순위가 높기 때문에 직접 구현한 메소드가 호출된다.
let c = cPerson()
c.canSpeak() // 출력값: Tom은 말할 수 있다.

where절 사용

where을 사용해서 기본 메서드를 제공하는 것에 제한을 둘 수도 있다.

protocol Person {
    var name: String { get }
    func canSpeak()
}

// Human 클래스를 채택하는 클래스에만 확장을 제공하겠다.
extension Person where Self: Human {
    func canSpeak(){
        print("말할 수 있다.")
    }
}

class Human {
}

// Human 클래스 채택, extension에 구현되어있는 메소드 사용 가능
class aPerson: Human, Person {
    var name: String = ""
}

// Human 클래스 채택X, extension에 구현되어있는 메소드를 사용 불가능
class bPerson: Person {
    var name: String = ""
    func canSpeak() {
        print("b도 말할 수 있다.")
    } 
}

let a = aPerson()
a.canSpeak() // 출력값: 말할 수 있다.

let b = bPerson()
b.canSpeak() // 출력값: b도 말할 수 있다.

0개의 댓글