1.1 Protocols

Joohyun·2022년 5월 2일
0

Protocol

  • 일반적으로 행위가 어떻게 진행되는지 규정한 규약을 뜻한다.

  • 특정 기능을 위한 property, method와 같은 요구사항의 청사진

  • 실제 기능을 수행하는 type은 요구사항을 완수하여 해당 protocol을 적용

  • Swift 기본 라이브러리는 app을 빌드할 때 사용할 수 있는 많은 protocol을 정의한다.

    • CustomStringConvertible
      • custom object를 console에 출력하는 방법 정의
    • Equatable
      • 같은 type의 instance가 서로 같은지 판별하는 방법 정의
    • Comparable
      • 같은 type의 instace들을 정렬하는 방법 정의
    • Codable
      • app 시작 시 저장될 수 있도록 type의 property를 key/value 형식으로 인코딩 가능
  • Computer communication에서의 Protocol
    • HTTP(Hyper Text Transfer Protocol)
      • 두 컴퓨터가 웹사이트에서 데이터를 통신하는 방법의 표준
    • TCP/IP(Transmission Control Protocol/Internet Protocol)
      • 컴퓨터끼리 데이터를 찾고 전송하는 방법의 표준
  • Swift Programming에서의 Protocol
    • object가 반드시 완수해야하는 property 또는 method를 정의
      ex) Equatable: type이 두 instance가 같은지 비교하기 위한 == 메서드를 반드시 정의해야 함

자주 쓰이는 기본 라이브러리 protocol

1. CustomStringConvertible

  • object가print()함수를 통해 console에 출력되는 방식을 정의

  • 요구사항

    • description
      • instance를 표현하는 String을 반환하는 computer property
  • 해당 protocol 적용 시, custom type의 출력 string을 적절하게 제어할 수 있다.

  • protocol이 요구하는 함수 또는 변수를 추가하지 않으면, error가 발생한다.

// : 뒤에 차용할 protocol 이름 추가
class Shoe: CustomStringConvertible {
  let color: String
  let size: Int
  let hasLaces: Bool
 
  init(color: String, size: Int, hasLaces: Bool) {
    self.color = color
    self.size = size
    self.hasLaces = hasLaces
  }
  
  // protocol이 요구하는 computed property 추가
  var description: String {
        return "Shoe(color: \(color), size: \(size), hasLaces: \
        (hasLaces))"
    }
}

let myShoe = Shoe(color: "Black", size: 12, hasLaces: true)
print(myShoe)
// console
Shoe(color: Black, size: 12, hasLaces: true)
  • CustomStringConvertible을 적용하기 전
class Shoe {
  let color: String
  let size: Int
  let hasLaces: Bool
 
  init(color: String, size: Int, hasLaces: Bool) {
    self.color = color
    self.size = size
    self.hasLaces = hasLaces
  }
}
 
let myShoe = Shoe(color: "Black", size: 12, hasLaces: true)
print(myShoe)
  • console
// 출력된 것이 그닥 도움이 되지 않는다.
Shoe

2. Equatable

  • custom type의 두 인스턴스가 동일한지 비교하는 방법을 제시한다.

  • 요구사항

    • == method
      • lhs(left-hand side), rhs(right-hand side) parameter가 동일한 값을 갖는지 여부를 결정하는 로직을 가지는 method
struct Employee: Equatable {
  var firstName: String
  var lastName: String
  var jobTitle: String
  var phoneNumber: String
 
  // first name, last name, job title, phone number가 모두 같은 경우 같다고 간주
  static func ==(lhs: Employee, rhs: Employee) -> Bool {
    return lhs.firstName == rhs.firstName && lhs.lastName == rhs.lastName && lhs.jobTitle == rhs.jobTitle && lhs.phoneNumber == rhs.phoneNumber
  }
}
let currentEmployee = Employee(firstName: "James", lastName: "Kittel", jobTitle: "Industrial Designer", phoneNumber: "415-555-7766")
let selectedEmployee = Employee(firstName: "James", lastName: "Kittel", jobTitle: "Marketing Director", phoneNumber: "415-555-9293")
 
if currentEmployee == selectedEmployee {
  // 두 instance가 동일하면 실행할 로직 작성
}

Autogeneration

  • struct, enum

    • Equatable을 적용할 때, == method를 작성하지 않아도 모든 property들이 같다면 true를 반환하는 == method가 자동으로 생성된다.
  • class

    • 자동생성을 지원하지 않으므로 반드시 == 메서드를 완성해주어야 한다.
    // 위의 코드와 같은 로직이라고 할 수 있다.
    struct Employee: Equatable {
      var firstName: String
      var lastName: String
      var jobTitle: String
      var phoneNumber: String
    }

3. Comparable

  • <, <=, >, >= 연산자를 사용하여 object를 정렬하는 방법을 정의한다.

  • 요구사항

    • Equatable protocol
      • 해당 protocol을 적용해야 한다.
    • < method
      • left-hand value와 right-hand value를 비교하는 method를 요구한다.
struct Employee: Equatable, Comparable {
  var firstName: String
  var lastName: String
  var jobTitle: String
  var phoneNumber: String
  
  // `==` method는 swift compiler가 자동으로 생성
  
  // last name의 알파벳 순으로 정렬
  static func < (lhs: Employee, rhs: Employee) -> Bool {
      return lhs.lastName < rhs.lastName
  }
}
let employee1 = Employee(firstName: "Ben", lastName: "Stott", jobTitle: "Front Desk", phoneNumber: "415-555-7767")
let employee2 = Employee(firstName: "Vera", lastName: "Carr", jobTitle: "CEO", phoneNumber: "415-555-7768")
let employee3 = Employee(firstName: "Glenn", lastName: "Parker", jobTitle: "Senior Manager", phoneNumber: "415-555-7770")

let employees = [employee1, employee2, employee3]
let sortedEmployees = employees.sorted(by: <) // 오름차순

for employee in sortedEmployees {
  print(employee)
}
// console
let employee2 = Employee(firstName: "Vera", lastName: "Carr", jobTitle: "CEO", phoneNumber: "415-555-7768")
let employee3 = Employee(firstName: "Glenn", lastName: "Parker", jobTitle: "Senior Manager", phoneNumber: "415-555-7770")
let employee1 = Employee(firstName: "Ben", lastName: "Stott", jobTitle: "Front Desk", phoneNumber: "415-555-7767")
  • Equatable, Comparable protocol이 요구하는 ==, < method를 정의하면 자동으로 !=, <=, >, >= 연산자를 제공한다.
let employees = [employee1, employee2, employee3]
let sortedEmployees = employees.sorted(by: >) // 내림차순

for employee in sortedEmployees {
  print(employee)
}
// console
let employee1 = Employee(firstName: "Ben", lastName: "Stott", jobTitle: "Front Desk", phoneNumber: "415-555-7767")
let employee3 = Employee(firstName: "Glenn", lastName: "Parker", jobTitle: "Senior Manager", phoneNumber: "415-555-7770")
let employee2 = Employee(firstName: "Vera", lastName: "Carr", jobTitle: "CEO", phoneNumber: "415-555-7768")

4. Codable

  • object의 property 이름과 값을 key/value 쌍으로 생성하여 Encoder, Decoder object를 통해 사용자의 데이터를 저장하고 읽을 수 있도록 한다.

  • app의 정보를 다양한 형태로 변경할 수 있다.

  • Swift 기본 라이브러리의 대부분 type은 Codable을 적용하고 있다.

  • Codable을 type 선언 뒤에 붙여주면 Swift compiler가 자동으로 Encoder, Decoder object가 특정 데이터 형식으로 encode, decode 할 수 있도록 정보를 제공한다.

struct Employee: Equatable, Comparable, Codable {
    var firstName: String
    var lastName: String
    var jobTitle: String
    var phoneNumber: String
 
     static func < (lhs: Employee, rhs: Employee) -> Bool {
        return lhs.lastName < rhs.lastName
    }
}

예시) JSONEncoder

  • Codable 적용을 통해서 JSONEncoder를 사용하여 웹에서 주로 쓰이는 JSON 형식으로 object를 변환할 수 있다.

  • 데이터 형식

    • Encode : Data
    • Decode : key/value 쌍의 배열을 보여주는 String
    import Foundation
    
    let ben = Employee(firstName: "Ben", lastName: "Stott", jobTitle: "Front Desk", phoneNumber: "415-555-7767")
    
    let jsonEncoder = JSONEncoder()
    
    // 정상적으로 encode된다면, encoding된 값을 String 형식으로 저장
    if let jsonData = try? jsonEncoder.encode(ben),
        let jsonString = String(data: jsonData, encoding: .utf8) {
        print(jsonString)
    }
    // console
    {"firstName":"Ben","lastName":"Stott","jobTitle":"Front
    Desk","phoneNumber":"415-555-7767"}

Throwing Function

  • 구체적인 error type을 반환하는 특별한 Swift 함수 타입
  • JSONEncoderencode(_:) method가 여기에 속한다.
  • try? 구문을 통해 optional 값을 반환할 수 있다.
    • 정상값 반환: optional 값 반환
    • 에러 반환: nil 반환

Protocol 생성

  • protocol 키워드와 요구사항 정의를 통해 나만의 protocol을 생성할 수 있다.

  • 요구사항 정의

    • property: read-only / read/write 중 어느 것인지 정의한다.

      • Read-only : computed property (get만 가능)
      • Read/write : 일반적인 property (get, set 모두 가능)
    • method: 구체적인 이름, 파라미터, 반환 타입을 정의한다.

// fullName property, sayFullName() method를 요구하는 FullyNamed protocol 정의
protocol FullyNamed {
  var fullName: String { get }
 
  func sayFullName()
}
// protocol 적용
struct Person: FullyNamed {
  var firstName: String
  var lastName: String
 
  var fullName: String {
    return "\(firstName) \(lastName)"
  }
 
  func sayFullName() {
    print(fullName)
  }
}

subclass와의 유사성

  • protocol은 공유할 property와 function의 집합을 제공한다는 관점에서 subclass를 선언하는 것과 유사하다.

  • superclass가 subclass에게 상속을 진행하는 것처럼, protocol 역시 default 기능을 제공하는데 사용될 수 있다.

Delegation

  • class 또는 structure가 다른 타입의 instance에게 자신의 책임을 위임하는 일반적인 design pattern

    • protocol
      • 위임할 것들을 정의하여 다른 타입에게 일을 위임
        ex) 직원에게 자신의 업무를 위임하는 매니저
    • type
      • 위임을 받아 실제 일을 수행하는 위임자
        ex) 매니저에게 일을 받아 업무를 진행하는 직원
  • 일을 수행해야하는 object가 존재하지만, 실제로 code를 통해 해당 일을 수행하지 않을 수 있다.

  • delegate pattern은 app에 구체적인 행동을 제공하도록 요구하는 object를 가진 framework를 사용할 때 특히 중요하다.

    • UIKit
      • UIApplicationDelegate: app이 remote notifications에 반응하는 방법을 정의
      • UITextFieldDelegate: 텍스트 입력을 유효화
      • UITableViewDelegate: 행이 선택됐을 때 action을 수행
profile
Developer

0개의 댓글