19. Protocol

Kang.__.Mingu·2021년 7월 31일
0

1. Study Swift

목록 보기
19/25

프로토콜을 통해 형식이 구현해야 하는 요구사항을 선언하고 이 요구사항을 충족하도록 형식을 구현하는 방법에 대해 공부

Protocol Syntax

프로토콜 선언 문법과 프로토콜 채용 문법에 대해 공부

Defining Protocols

protocol ProtocolName {
	propertyRequirements
    methodRequirements
    initializerRequirements
    subscriptRequirements
}

protocol ProtocolName: Protocol, ... {
}
protocol Something {
    func doSomething()
}

Adopting Protocols

enum TypeName: ProtocolName, ... {
}

struct TypeName: ProtocolName, ... {
}

class TypeName: SuperClass, ProtocolName, ... {
}

프로토콜 채용

struct Size: Something {        // 상위 프로토콜 이름 선언
    func doSomething() {
        
    }
}

class-Only Protocols

protocol ProtocolName: AnyObject {
}
protocol SomethingObject: AnyObject, Something {
    
}
// 클래스 전용
class object: SomethingObject {
    func doSomething() {
        
    }
}

Property Requirements

프로토콜에서 속성을 선언하고 형식에서 요구사항을 구현

protocol ProtocolName {
	var name: Type { get set }
    static var name: Type { get set }
}

프로토콜 형식 선언
항상 var 키워드로 선언

protocol Figure {
    static var name: String { get set }
}

struct Rectangle: Figure {      // 상수 저장 속성 X
    static var name = "Rect"
}

struct Tringle: Figure {
    static var name = "Triangle"
}

class Circle: Figure {      // class의 하위도 똑같이 class로 선언해야한다	
    class var name: String {
        get {
            return "Circle"
        }
        set {
            
        }
    }
}

Method Requirements

프로토콜에서 메소드를 선언하고 형식에서 요구사항을 구현

protocol ProtocolName {
	func name(param) -> ReturnType
    static func name(param) -> ReturnType
    mutating func name(param) -> ReturnType
}
  • 프로토콜에서 메소드를 선언할 때 헤드만 작성
  • 타입 메서드를 선언할 때는 func 키워드 앞에 static 키워드를 추가한다.
  • 만약 프로트콜을 가평식에 추가할 수도 있고, 메소드 내부에서 속성값을 변경해야한다면 func 키워드 앞에 mutating 키워드를 추가해야한다.
  • mutating 키워드로 선언되어 있다면 가평식 전용이라고 생각할 수 있다.
    하지만 프로토콜에서 사용한 mutating 키워드는 메소드에서 속성을 변경할 수 있어야 한다는 요구사항을 표현
protocol Resettable {
    static func reset()
}

class Size: Resettable {       // struct에서만 입력을 받는 상위에 mutating를 추가해야 함수에서 오류 발생 x
    var width = 0.0
    var height = 0.0
    
    func reset() {
        width = 0.0
        height = 0.0
    }
    
    class func reset() {
        // static 대신 class를 선언하면 오버라이딩을 선언하는 동시에 프로토콜의 요구사항을 충족한다.
    }
}

Initializer Requirements

프로토콜에서 생성자를 선언하고 형식에서 요구사항을 구현

protocol ProtocolName {
	init(param)
    init?(param)
    init!(param)
}
protocol Figure {
    var name: String { get }
    init(n: String)
}

// 구조체 선언 및 프로토콜 선언
struct Rectangle: Figure {
    var name: String
    
    // 프로토콜의 생성자를 바꾸면 밑에 생성자도 추가해야된다.
    init(n: String) {
        name = n
    }
}


class Circle: Figure {
    var name: String
    required init(n: String) {
        name = n
    }
}

final class Triangle: Figure {      // final = 더 이상 상속되지 않는 클래스
    var name: String
    // final은 더 이상 상속이 되지 않기 때문에 상속을 고려하지 않아도 된다.
    // 그래서 required 키워드 없이 요구 사항을 충족시킴
    
    // 프로토콜의 생성자를 바꾸면 밑에 생성자도 추가해야된다.
    init(n: String) {
        name = n
    }
}


class Oval: Circle {
    var prop: Int
    
    init() {
        prop = 0
        super.init(n: "Oval")
    }
    
    required convenience init(n: String) {
        self.init()
    }
}


protocol Grayscale {
    init?(white: Double)
}

struct Color: Grayscale {
    init(white: Double) {
         
    }
}

// 어렵다..
// 포기 금지

Subscript Requirements

프로토콜에서 서브스크립트를 선언하고 형식에서 요구사항을 구현합니다.

protocol ProtocolName {
	subscript(param) -> ReturnType { get set }
}
  • Subscript에서 get으로 선언 했다고 해서 실제 구현에서 get 블럭만 구현해야 하는 것은 아니다.
  • 값을 읽을 수 있어야 한다는 요구사항만 충족시키면 나머지 구현에는 제약이 없다
  • get 키워드는 필수
protocol List {
    subscript(idx: Int) -> Int { get }
}

struct DataStore: List {
    subscript(idx: Int) -> Int {
        get {
            return 0
        }
        set {
            
        }
    }   
}
profile
최선을 다해 꾸준히 노력하는 개발자 망고입니당 :D

0개의 댓글