Swift문법 - (17)프로토콜 - 1

Youth·2022년 10월 4일
0

swift문법공부

목록 보기
17/27
post-thumbnail

프로토콜(Protocols) - 1

  • 프로토콜의 필요성
    • 클래스 상속의 단점
      1. 하나의 클래스만 상속가능
      2. 필요하지 않은 속성이나 메서드도 상속이됨
      3. 클래스에서만 가능함

필요하지 않은 속성이나 메서드가 상속이 되는 경우

class Bird {
    var isFemale = true
    func layEgg() {
        if isFemale {
            print("새가 알을 낳는다.")
        }
    }
    func fly() {
        print("새가 하늘로 날아간다.")
    }
}

Eagle은 자동으로 isFemale과 layEgg() Fly()를 상속받음
class Eagle: Bird {
    func soar() {
        print("공중으로 치솟아 난다.")
    }
}

Penguin은 날수없는데 Bird를 상속받아 어쩔수없이 fly()를 상속받게됨
class Penguin: Bird {
    // fly()
    func swim() {
        print("헤엄친다.")
    }
}

프로토콜

  • 프로토콜을 채택하면 내가 꼭 정의하라고한 함수는 “무조건”정의해야함
  • 상속할클래스를 먼저 적어주고 프로토콜을 적음
// 요구사항을 정의 (자격증의 필수 능력만 정의)
protocol SomeProtocol {
    func playPiano()
}

→ SomeProtocol을 채택한 구조체,클래스는 무조건 playPiano()라는 함수를 구현


  1. 구조체에서 채택
  • SomeProtocol을 채택했기 때문에 func playPiano()를 무조건 구현
  • 구현안하면 오류, 어떤 내용으로 구현할지는 자유
struct MyStruct: SomeProtocol {
    func playPiano() {
        print("피아노를 칩니다")
    }
}
  1. 클래스에서 채택
class MyClass: SomeProtocol {
    func playPiano() {
        print("나는 피아노를 칩니다")
    }
}

✅프로토콜을 타입으로 사용할 수 있다

  • 타입을 적어야하는 곳에 프로토콜을 넣을 수 있다
struct FlyingMuseum1 {
    func flyingDemo(flyingObject: CanFly) {
        flyingObject.fly()
    }
}

→ flyingDemo라는 함수에 파라미터로 “CanFly”라는 프로토콜을 채택하는 클래스나 구조체를 넣을 수 있다

프로토콜(Protocols) 문법

  • 프로토콜 기본문법
💡 클래스에서 상속이 있는 경우 1) 상위 클래스를 먼저 선언 후 2) 프로토콜 채택 선언

프로토콜의 요구사항의 종류

  1. 속성의 요구사항 정의하는 방법
    • 속성의 뜻에서 var로 선언 (let으로 선언할 수 없음)
    • get, set 키워드를 통해서 읽기/쓰기 여부를 설정 (✅최소한의 요구사항일뿐)
    • 저장 속성/계산 속성으로 모두 구현 가능
protocol RemoteMouse {
		// id를 읽을수만 있으면됨(let저장속성도 가능함 -> 쓰기 불가능함)
		// -> 읽기 저장속성, 읽기만 가능한 계산속성, 읽기 쓰기 모두 가능한 계산속성
    var id: String { get }                
    
		// name을 읽기도하고 쓰기도 해야함
		// var 저장속성(let은 쓰기는불가능함❌), var 계산속성
    var name: String { get set }  

		// 타입 저장 속성 (static), 타입 계산 속성 (class)
		// 타입계산속성으로 하고 재정의를 하게하고 싶으면 아래 클래스에서 class로 구현해도됨
    static var type: String { get set }  
}

메서드의 요구사항 정의하는 방법

  • 메서드의 헤드부분(인풋/아웃풋)의 형태만 요구사항으로 정의
  • mutating 키워드: (구조체로 제한하는 것은 아님) 구조체에서 저장 속성 변경하는 경우,
    구조체도 채택 가능하도록 허락하는 키워드
  • 타입 메서드로 제한 하려면, static키워드만 붙이면 됨
    (채택해서 구현하는 쪽에서 static / class 키워드 모두 사용 가능)

클래스에서의 메서드 요구사항 정의

  1. 정의
protocol RandomNumber {
		// 최소한 타입 메서드가 되야함
		// class로 구현해서 재정의를 허용하는 것도 가능
    static func reset()         
    func random() -> Int
    mutating func doSomething()
}
  1. 채택 및 구현
class Number: RandomNumber {
    // 재정의 허락
    class func reset() {
        print("다시 셋팅")
    }
		// 재정의를 허락하지 않음
    // static func reset() {
    //     print("다시 셋팅")
    // }
    
    func random() -> Int {
        return Int.random(in: 1...100)
    }
    
    // 클래스이기때문에 mutating키워드가 필요가 없음
    func doSomething() {
        print("gg ")
    }
}

열거형에서의 메서드 요구사항 정의

  1. 정의
protocol Togglable {
    mutating func toggle() 
}
  1. 채택 및 구현
enum OnOffSwitch: Togglable {
    case on
    case off
		// 열거형(valueType)이기때문에 mutating키워드 붙여줘야함
    mutating func toggle() {
        switch self {
        case .off:
            self = .on
        case .on:
            self = .off
        }
    }
}

클래스라면????
class BigSwitch: Togglable {
    var isOn = false
	  // mutating 키워드 필요없음 (클래스 이기 때문)
    func toggle() {      
        isOn = isOn ? false : true 
}

메서드 요구사항 - 생성자 요구사항

  • (1) 클래스는 (상속 고려해야함) 생성자 앞에 required를 붙여야함 (하위에서 구현을 강제) - 구조체의 경우 상속이 없기 때문에, required키워드 필요 없음
  • (2) 아니면 final을 붙여서 상속을 막으면 required 생략가능
  • (3) 클래스에서는 반드시 지정생성자로 구현할 필요없음(편의생성자로 구현도 가능)

예제1

class SomeClass: SomeProtocol {
    required init(num: Int) {
        // 실제 구현
    }
}

class SomeSubClass: SomeClass {
    // 하위 클래스에서 생성자 구현 안하면 필수 생성자는 자동 상속
    // required init(num: Int)
    
}

예제2

protocol AProtocol {
    init()
}

class ASuperClass {
    init() {
        // 생성자의 내용 구현
    }
}

class ASubClass: ASuperClass, AProtocol {
    // AProtocol을 채택함으로 "required" 키워드 필요
		// 상속으로 인한 "override(재정의)" 재정의 키워드도 필요
    required override init() {
        // 생성자의 내용 구현
    }
}

프로토콜 채택과 구현 - 확장(Extension)에서

protocol Certificate {
    func doSomething()
}

class Person { }

// 관습적으로 본체보다는 확장에서, 채택하고 구현 (코드를 깔끔하게 정리 가능)
extension Person: Certificate {
    func doSomething() {
        print("Do something")
    }
}
profile
AppleDeveloperAcademy@POSTECH 1기 수료, SOPT 32기 iOS파트 수료

0개의 댓글