swift에서 Protocol은 함수, 클로저와 같이 1급 객체다.
프로토콜 타입
으로 타입캐스팅
해서 사용하는 것이다.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("타입캐스팅 실패")
}
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
프로토콜을 채택하는 여러 곳에서 같은 기능을 하는 메소드를 여러번 반복해서 쓸 경우, 프로토콜을 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을 사용해서 기본 메서드를 제공하는 것에 제한을 둘 수도 있다.
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도 말할 수 있다.