Dog foot print

[SWIFT] protocol 본문

IOS/Swift

[SWIFT] protocol

개 발자국 2021. 7. 21. 23:03

Protocol

애플의 진영에서는 인터페이스라는 것이 존재하지 않고, 프로토콜이라는 것이 존재한다. 어찌 보면 규약이라는 개념은 비슷하지만 그 규칙의 강제성이나, 제한은 인터페이스가 훨씬 높다. 즉 프로토콜이라는 개념은 최소한의 만족할 만한 규칙 이며, 인터페이스는 부가적인 것이 존재하지 않는 규칙으로 정리 할 수 있다.

프로토콜은 명세라고 불리우기도 하는데, 이는 특정한 것을 만들기 위한 설계서와 같은 역할을 한다. 이 프로토콜이라는 규칙을 준수하며 객체나 구조체, 열거형을 만드는 것을 프로토콜을 구현한다라고 표현 한다.

프로토콜의 구현

protocol [프로토콜 명]{
    프로토콜 명세 ...
}

class A : [protocol] {

}

extension A : [protocol] {

}

enum B : [protocol] {

}

struct C : [protocol] {

}

프토토콜을 구현 할 수 있는 타입은 열거형, 구조체 , 클래스, 익스텐션 입니다.

프로토콜에서 프로퍼티 명세하기

protocol SomeProtocol {
    <변수타입> <변수명> : <변수타입> { get  set}
    <변수타입> <변수명> : <변수타입> { get }
}

protocol SomeProtocol {
    var name : String {get set}
    var age : String {get}
}

class A : SomeProtocol {
    var name : String = "";
    var age : Int = {
        return 19;
    }
}

프로토콜에서 프로퍼티를 명세 할 때, 구현 부분이 아니기 때문에 특정 값을 명시하지 않습니다. 할당연산자가 존재하지 않고, { get , set} 의 형태를 띄고 있는데, 이는 프로퍼티가 읽기와 쓰기 속성이 가능한지를 명세하는 부분 입니다.

Note : 읽기와 쓰기 혹은 읽기 만 가능합니다.

프로토콜에서 메서드 명세하기

protocol SomeProtocol {
    func (매개변수 : 타입) -> 반환 타입 
    func (매개변수 : 타입) // Void 반환;
}

protocol SomeProtocol {
    func foo()
    func add(x : Int, y : Int) -> Int
}

프로토콜에서 메서드를 명세 할 때는 함수의 식별자를 명세해주면 됩니다. 즉 메서드명, 파라메터 , 반환타입 을 명세하면 됩니다.

프로토콜에서 Static과 mutating 사용하기

protocol SomeProtocol {
    var counters : Int {get set}
    static func foo()
    mutating func addCounter(x : Int) -> Int 
}

struct Counter : SomeProtocol {
         var counters : Int = 0;
        static func foo(){
            print("hello world")
        }
        mutating func addCounter(x : Int ) -> Int{
            self.counters += x
            return self.counters
        }
}

구조체에서 메서드를 이용하여, 내부 변수의 재할당이 일어날 때는 함수 키워드 앞에 mutating을 작성해주어야 합니다. 프로토콜을 명세할 때 또한 동일하게 mutating을 작성해주어야 하며, 만약 명세 해주지 않고 구조체 구현에서 mutating을 작성하게 되면 명세를 지키지 않음으로 간주하고 에러를 발생 시킵니다.

Note : 만약 mutating이 명시된 프로토콜을 구조체가 아닌 클래스에서 이를 구현하게 된다면 class에서는 mutating을 따로 구현할 필요가 없으니 안심해도 됩니다.

protocol과 초기화 메서드

import UIKit

protocol CounterProtocol {
    var counts :Int {get set}

    init()
    init(c : Int)
}

class Counter : CounterProtocol{
    internal var counts: Int;

    required init(){
        self.counts = 0;
    }

    required init(c : Int){
        self.counts = c;
    }
}
let c = Counter(c: 10);
c.counts

초기화 구문을 명세 할 때는 init생성자 인자만 명시하면 됩니다. 다만 구현하는 부분에서는 프로토콜에서 명세한 init을 구현한다는 것을 알리기 위해 required 를 init 앞에 명시해주어야 합니다.

만약 자식 클래스에서 특정 프로토콜을 구현하며 이미 부모에서 구현된 init이 존재한다면 override 구문과 required 구문을 함께 명시해야합니다.

import UIKit

protocol SomeProtocol {
    var count : Int {get set}
    init()
    init(c : Int)
}

class A {
    init(){

    }
}

class B : A , SomeProtocol{
    var count: Int = 0;
    override required init(){
        super.init()
    }

    required init(c : Int){
        self.count = c;
    }
}

Note : 만약 init이 명세 되어 있는 프로토콜을 구조체가 구현한다고 하면 멤버와이즈 초기화 구문이 존재해도 명시된 init을 구현 해야합니다.

Type 으로써의 Protocol

import UIKit

protocol SomeProtocol {
    func foo()
    func boo()
}



class A : SomeProtocol {
    func foo(){
        print("foo!");
    }

    func boo(){
        print("boo!")
    }
    func coo(){
        print("coo!")
    }
}

let a : A = A();
a.boo()
a.foo()
a.coo()

let c : SomeProtocol = A();

c.boo()
c.foo()
//c.coo() // 존재하지 않음

만약 프로토콜을 구현한 클래스에서 프로토콜 명세보다 더 많은 멤버를 가지고 있어도 프로토콜의 명세를 구현했기 때문에 에러를 발생 시키지 않습니다. 그러나, 더 많은 기능을 가지고 있는 클래스의 인스턴스를 프로토콜 타입의 변수에 할당 한다면 이 인스턴스는 많은 기능을 실제로 가지고 있더라도, 프로토콜 명세 이외의 멤버에는 접근 할 수가 없습니다.

만약 클래스를 정의할 때 2개 이상의 프로토콜을 구현 하였다면 다음과 같이 &을 사용하여 새로운 타입을 만들어 사용 할 수 있습니다.

import UIKit

protocol SomeProtocol {
    func foo()
    func boo()
}

protocol SomeProtocol2{
    func coo()
}

class A : SomeProtocol, SomeProtocol2 {
    func foo(){
        print("foo!");
    }

    func boo(){
        print("boo!")
    }
    func coo(){
        print("coo!")
    }
}

let a : A = A();
a.boo()
a.foo()
a.coo()

let c : SomeProtocol & SomeProtocol2 = A();

c.boo()
c.foo()
c.coo()

반응형

'IOS > Swift' 카테고리의 다른 글

[IOS] 쓰레드와 동시작업  (0) 2021.09.22
[Swift] 동기적 작업과 비동기적 작업  (0) 2021.09.20
[SWIFT] enumeration  (0) 2021.07.21
[SWIFT] 초기화  (0) 2021.07.20
[SWIFT] Type casting  (0) 2021.07.20
Comments