swift에는 프로토콜이라는 것이 있다.
프로토콜은 코드의 청사진이라고 생각하면 된다.
자바를 안다면 인터페이스와 비슷한 존재라고 생각하면 된다.
프로토콜의 경우 무엇을 만들어야 하는지 정의 할 수 있다 하지만 정의 해야 되는 내용을 미리 구현해 놓을 수는 없다.
- 클래스
1.1 클래스 전용 프로토콜- 구조체
- 열거형
- 프로토콜
- extension
다음 요소들에 프로토콜의 적용이 가능하다.
protocol SomeProtocol {
}
다음과 같은 형태로 프로토콜의 생성이 가능하다
struct SomeStructure: FirstProtocol, AnotherProtocol {
}
class SomeClass: FirstProtocol, AnotherProtocol {
}
다음과 같이 클래스 이름 뒤에 :콜론을 붙이고 채택할 프로토콜의 이름을 명시 해 주면 된다.
그리고 클래스의 상속또한 프로토콜 채택과 같이 :콜론을 이용해서 명시하는데 클래스상속과 프로토콜의 채택이 동시에 이루어 지는 경우 반드시 상속받는 클래스 이름을 제일 앞에 작성해줘야 한다.
프로토콜의 경우 채택하게 되면 프로토콜에서 명시해 놓은 내용들을 반드시 구현해야 한다
struct SomeProtocol{
var mustBeSettable: Int { get set }
var doesNotNeedToBeSettable: Int { get }
}
//타입 프로퍼티 요구사항
protocol AnotherProtocol {
static var someTypeProperty: Int { get set }
}
타입 프로퍼티의 경우 static 키워드를 붙여 주면 된다.
protocol RandomNumberGenerator {
func random() -> Double
}
메서드의 경우 동일하게 형태만 작성하고 {}중괄호를 이용한 상세 내용구현은 없이 작성해준다.
protocol Togglable {
mutating func toggle()
}
구조체와 열거형의 경우 내부 프로퍼티의 수정이 기본적으로는 불가능하기때문에 내부 프로퍼티를 수정하는 메소드를 사용할때 mutating키워드를 사용한다.
프로토콜의 요구사항 명시의 순간에서 동일하게 mutating키워드를 붙여서 사용한다.
protocol SomeProtocol {
init(someParameter: Int)
}
생성자 또한 프로토콜에서 미리 요구사항으로 선언이 가능하다.
하지만 생성자의 경우 기존의 생성자와 충돌할 수 있기 때문에 구현시 별도의 키워드를 사용해서 구현해야한다.
class SomeClass: SomeProtocol {
required init(someParameter: Int) {
// initializer implementation goes here
}
}
다음과 같이 요구사항 생성자의 구현의 경우 앞에 required키워드를 붙여줘야 한다.
extension SomeClass: SomeProtocol {
//(대충 SomeProtocol구현하는 코드)
}
다음과 같이 확장구문에서도 프로토콜의 채택이 가능하다.
타입이 이미 프로토콜의 모든 요구사항을 준수하지만 해당 프로토콜을 채택한다고 아직 명시하지 않은 경우 빈 확장을 사용하여 프로토콜을 채택하도록 만들 수 있다.
struct Hamster {
var name: String
var textualDescription: String {
return "A hamster named \(name)"
}
}
extension Hamster: TextRepresentable {}
프로토콜에서 타입에 구애 받지 않는 제네릭을 이용하고자 할때 associatedtype 키워드를 이용해야만 제네릭을 사용 가능하다.
protocol Container {
associatedtype Item
mutating func append(_ item: Item)
var count: Int { get }
subscript(i: Int) -> Item { get }
}
자바에서처럼 <>각괄호를 이용한 제네릭을 프로토콜에 사용하는것은 불가능하다. 그래서 associatedtype키워드를 사용해서 제네릭을 사용해야 한다.
자세한 내용은 제네릭에서...
extension Array: TextRepresentable where Element: TextRepresentable {
var textualDescription: String {
let itemsAsText = self.map { $0.textualDescription }
return "[" + itemsAsText.joined(separator: ", ") + "]"
}
}
let myDice = [d6, d12]
print(myDice.textualDescription)
// Prints "[A 6-sided dice, A 12-sided dice]"
where키워드를 사용하여 특정 프로토콜을 준수하는 경우와 같은 특정 조건에서만 프로토콜의 요구사항을 충족시키는 형태를 말한다.
마찬가지로 자세한 내용은 제네릭에서...
코드의 일관성과 가독성을 높이기 위해서 프로토콜을 사용할 수 있다.