일반적으로 행위가 어떻게 진행되는지 규정한 규약을 뜻한다.
특정 기능을 위한 property, method와 같은 요구사항의 청사진
실제 기능을 수행하는 type은 요구사항을 완수하여 해당 protocol을 적용
Swift 기본 라이브러리는 app을 빌드할 때 사용할 수 있는 많은 protocol을 정의한다.
CustomStringConvertible
Equatable
Comparable
Codable
- 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가 같은지 비교하기 위한==
메서드를 반드시 정의해야 함
object가print()
함수를 통해 console에 출력되는 방식을 정의
요구사항
description
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
custom type의 두 인스턴스가 동일한지 비교하는 방법을 제시한다.
요구사항
==
methodlhs
(left-hand side), rhs
(right-hand side) parameter가 동일한 값을 갖는지 여부를 결정하는 로직을 가지는 methodstruct 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가 동일하면 실행할 로직 작성
}
struct
, enum
Equatable
을 적용할 때, ==
method를 작성하지 않아도 모든 property들이 같다면 true
를 반환하는 ==
method가 자동으로 생성된다.class
==
메서드를 완성해주어야 한다.// 위의 코드와 같은 로직이라고 할 수 있다.
struct Employee: Equatable {
var firstName: String
var lastName: String
var jobTitle: String
var phoneNumber: String
}
<
, <=
, >
, >=
연산자를 사용하여 object를 정렬하는 방법을 정의한다.
요구사항
Equatable
protocol<
methodstruct 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")
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
}
}
Codable
적용을 통해서 JSONEncoder
를 사용하여 웹에서 주로 쓰이는 JSON 형식으로 object를 변환할 수 있다.
데이터 형식
Data
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 함수 타입
JSONEncoder
의encode(_:)
method가 여기에 속한다.try?
구문을 통해 optional 값을 반환할 수 있다.
- 정상값 반환: optional 값 반환
- 에러 반환:
nil
반환
protocol
키워드와 요구사항 정의를 통해 나만의 protocol을 생성할 수 있다.
요구사항 정의
property: read-only / read/write 중 어느 것인지 정의한다.
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)
}
}
protocol은 공유할 property와 function의 집합을 제공한다는 관점에서 subclass를 선언하는 것과 유사하다.
superclass가 subclass에게 상속을 진행하는 것처럼, protocol 역시 default 기능을 제공하는데 사용될 수 있다.
class 또는 structure가 다른 타입의 instance에게 자신의 책임을 위임하는 일반적인 design pattern
일을 수행해야하는 object가 존재하지만, 실제로 code를 통해 해당 일을 수행하지 않을 수 있다.
delegate pattern은 app에 구체적인 행동을 제공하도록 요구하는 object를 가진 framework를 사용할 때 특히 중요하다.
UIKit
UIApplicationDelegate
: app이 remote notifications에 반응하는 방법을 정의UITextFieldDelegate
: 텍스트 입력을 유효화UITableViewDelegate
: 행이 선택됐을 때 action을 수행