Bibi's DevLog πŸ€“πŸŽ

[Swift] ν”„λ‘œν† μ½œ Protocol λ³Έλ¬Έ

πŸ“±πŸŽ iOS/πŸ•Š Swift

[Swift] ν”„λ‘œν† μ½œ Protocol

λΉ„λΉ„ bibi 2022. 8. 2. 16:13

[Swift] ν”„λ‘œν† μ½œ Protocol

Swift ν”„λ‘œκ·Έλž˜λ° - 377μͺ½ ~

ν”„λ‘œν† μ½œ : νŠΉμ • μ—­ν• (κΈ°λŠ₯)을 ν•˜κΈ° μœ„ν•œ λ©”μ„œλ“œ, ν”„λ‘œνΌν‹°, 기타 μš”κ΅¬μ‚¬ν•­μ˜ 청사진을 μ •μ˜ν•œ 것

ν”„λ‘œν† μ½œμ€ κΈ°λŠ₯을 μ •μ˜ν•˜κ³  μ œμ‹œν•  뿐, 슀슀둜 κΈ°λŠ₯을 κ΅¬ν˜„ν•˜λŠ” 것이 μ•„λ‹ˆλ‹€.

  • ꡬ쑰체/클래슀/μ—΄κ±°ν˜•μ€ νŠΉμ • ν”„λ‘œν† μ½œμ„ 채택(adopted)ν•΄μ„œ κ·Έ 역할을 μœ„ν•œ μš”κ΅¬μ‚¬ν•­μ„ κ΅¬ν˜„ν•œλ‹€.
  • μ–΄λ–€ νƒ€μž…μ΄ μ–΄λ–€ ν”„λ‘œν† μ½œμ˜ μš”κ΅¬μ‚¬ν•­μ„ λ”°λ₯΄λ©΄, 'ν•΄λ‹Ή ν”„λ‘œν† μ½œμ„ μ€€μˆ˜ν•œλ‹€(conform)'라고 ν‘œν˜„ν•œλ‹€.

μŠ€μœ„ν”„νŠΈμ—μ„œ ν”„λ‘œν† μ½œμ€ μ™„μ „ν•œ ν•˜λ‚˜μ˜ νƒ€μž…μœΌλ‘œ μ‚¬μš©λœλ‹€.

  • νŒŒλΌλ―Έν„°λ‚˜ λ¦¬ν„΄νƒ€μž…μœΌλ‘œ μ‚¬μš© κ°€λŠ₯
  • ν”„λ‘œνΌν‹°, λ³€μˆ˜, μƒμˆ˜μ˜ νƒ€μž…μœΌλ‘œ μ‚¬μš© κ°€λŠ₯
  • λ°°μ—΄ λ“± μ»¨ν…Œμ΄λ„ˆ μš”μ†Œμ˜ νƒ€μž…μœΌλ‘œ μ‚¬μš© κ°€λŠ₯

ν”„λ‘œν† μ½œ λ§Œλ“€κΈ°

: protocol ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•΄ μ„ μ–Έν•œλ‹€.

protocol ν”„λ‘œν† μ½œμ΄λ¦„ {
    ν”„λ‘œν† μ½œ μ •μ˜
}

ν”„λ‘œνΌν‹° μš”κ΅¬μ‚¬ν•­

  • ν”„λ‘œνΌν‹°μ™€ νƒ€μž… ν”„λ‘œνΌν‹° μš”κ΅¬ κ°€λŠ₯
  • ν”„λ‘œνΌν‹° μš”κ΅¬μ‚¬ν•­μ€ 항상 var둜 μ„ μ–Έ
  • ν”„λ‘œνΌν‹°λ₯Ό 읽기 μ „μš©({ get }) 으둜 할지, 읽고 μ“°κΈ°({ get, set })둜 할지 μ •ν•΄μ€˜μ•Ό 함
  • κ΅¬ν˜„ν•  λ•ŒλŠ” ν”„λ‘œνΌν‹°μ˜ 이름과 νƒ€μž…λ§Œ 맞으면 됨
  • νƒ€μž… ν”„λ‘œνΌν‹°λŠ” static ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•΄ μ„ μ–Έ
protocol SomeProtocol {
    var settableProperty: String { get set }
    var notNeedToBeSettableProperty: String { get }
    static var typeProperty: Int { get }
}

λ©”μ„œλ“œ μš”κ΅¬μ‚¬ν•­

  • μΈμŠ€ν„΄μŠ€ λ©”μ„œλ“œ λ˜λŠ” νƒ€μž… λ©”μ„œλ“œ μš”κ΅¬ κ°€λŠ₯
  • λ©”μ„œλ“œμ—μ„œ ν•¨μˆ˜ bodyλ₯Ό μ œμ™Έν•˜κ³  μ‹œκ·Έλ‹ˆμ²˜λ§Œ μž‘μ„±
  • νƒ€μž… λ©”μ„œλ“œλŠ” static ν‚€μ›Œλ“œ μ‚¬μš©
protocol Sendable {
    var from: Sendable { get }

    func send(data: Any)

    static func isSendableInstance(_ instance: Any) -> Bool
}

κ°€λ³€ λ©”μ„œλ“œ μš”κ΅¬ mutating method requirements

  • κ°’ νƒ€μž…(ꡬ쑰체, μ—΄κ±°ν˜•)의 μΈμŠ€ν„΄μŠ€ λ©”μ„œλ“œμ—μ„œ μžμ‹  λ‚΄λΆ€μ˜ 값을 λ³€κ²½ν•  λ•Œ func μ•žμ— mutating으둜 μ„ μ–Έν•΄ μ€€λ‹€.
  • κ°€λ³€ λ©”μ„œλ“œλ₯Ό μš”κ΅¬ν•œ ν”„λ‘œν† μ½œμ„ ν΄λž˜μŠ€κ°€ κ΅¬ν˜„ν•  λ•ŒλŠ” mutating ν‚€μ›Œλ“œλ₯Ό μƒλž΅ν•œλ‹€.
  • ν”„λ‘œν† μ½œμ—μ„œ κ°€λ³€ λ©”μ„œλ“œλ₯Ό μš”κ΅¬ν•˜μ§€ μ•ŠλŠ”λ‹€λ©΄, mutating λ©”μ„œλ“œλŠ” κ΅¬ν˜„μ΄ λΆˆκ°€λŠ₯ν•˜λ‹€
protocol Resettable {
  mutating func reset()
}

struct Point: Resettable {
    var x: Int = 0
    var y: Int = 0

    mutating func reset() {
        self.x = 0
        self.y = 0
    }
}

μ΄λ‹ˆμ…œλΌμ΄μ € μš”κ΅¬

  • λ©”μ„œλ“œμ™€ λ§ˆμ°¬κ°€μ§€λ‘œ μ΄λ‹ˆμ…œλΌμ΄μ €μ˜ λ§€κ°œλ³€μˆ˜λ§Œ μ§€μ •ν•˜κ³ , bodyλŠ” κ΅¬ν˜„ν•˜μ§€ μ•ŠλŠ”λ‹€.
  • 클래슀 νƒ€μž…μ—μ„œ ν”„λ‘œν† μ½œμ΄ μš”κ΅¬ν•œ μ΄λ‹ˆμ…œλΌμ΄μ €λ₯Ό κ΅¬ν˜„ν•  λ•ŒλŠ” required ν‚€μ›Œλ“œλ₯Ό 뢙인 μš”κ΅¬ μ΄λ‹ˆμ…œλΌμ΄μ €λ‘œ κ΅¬ν˜„ν•œλ‹€.
    • ν•΄λ‹Ή 클래슀λ₯Ό μƒμ†λ°›λŠ” λͺ¨λ“  ν΄λž˜μŠ€λŠ” 같은 ν”„λ‘œν† μ½œκ³Ό μš”κ΅¬ μ΄λ‹ˆμ…œλΌμ΄μ €λ₯Ό κ΅¬ν˜„ν•΄μ•Ό ν•˜κΈ° λ•Œλ¬Έ.
    • 상속할 수 μ—†λŠ” final 클래슀라면 requiredλ₯Ό μƒλž΅ κ°€λŠ₯함
  • ν”„λ‘œν† μ½œμ΄ μš”κ΅¬ν•œ μ΄λ‹ˆμ…œλΌμ΄μ €κ°€ κ΅¬ν˜„λœ 클래슀λ₯Ό 상속받은 ν΄λž˜μŠ€μ—μ„œλŠ” required overrideλ₯Ό λͺ¨λ‘ λͺ…μ‹œν•΄μ•Ό 함
  • μ‹€νŒ¨ κ°€λŠ₯ν•œ μ΄λ‹ˆμ…œλΌμ΄μ €λ„ μš”κ΅¬ κ°€λŠ₯
protocol Name {
  var name: String { get }

  init(name: String)
}

class Person: Named {
  var name: String

  required init(name: String) {
    self.name = name
  }
}

ν”„λ‘œν† μ½œ μ±„νƒν•˜κΈ°

  • ꡬ쑰체, 클래슀, μ—΄κ±°ν˜• λ“±μ—μ„œ νƒ€μž… 이름 뒀에 μ½œλ‘ μ„ 뢙인 ν›„, 채택할 ν”„λ‘œν† μ½œμ„ μ‰Όν‘œλ‘œ λ‚˜μ—΄ν•¨
  • 클래슀 상속도 ν•¨κ»˜ λ°›λŠ” 경우, μƒμ†λ°›λŠ” 클래슀 이름 λ‹€μŒμ— ν”„λ‘œν† μ½œ λ‚˜μ—΄
struct SomeStruct: AProtocol, AnotherProtocol {

}

ν”„λ‘œν† μ½œμ˜ 상속

  • ν”„λ‘œν† μ½œλΌλ¦¬λ„ 상속이 κ°€λŠ₯ν•˜λ‹€.
  • 문법은 클래슀 상속 문법과 μœ μ‚¬ν•˜λ‹€.
  • κ΅¬ν˜„ν•  λ•ŒλŠ” 상속받은 ν”„λ‘œν† μ½œμ˜ μš”κ΅¬μ‚¬ν•­κΉŒμ§€ λͺ¨λ‘ κ΅¬ν˜„ν•΄μ•Ό ν•œλ‹€.
protocol Readable {
    func read()
}

protocol Writeable {
    func write()
}

protocol ReadWriteSpeakable: Readable, Writeable {
    func speak()
}

클래슀 μ „μš© ν”„λ‘œν† μ½œ

  • ν”„λ‘œν† μ½œμ˜ 상속 λ¦¬μŠ€νŠΈμ— class ν‚€μ›Œλ“œλ₯Ό μΆ”κ°€ν•˜λ©΄, ν”„λ‘œν† μ½œμ΄ 클래슀 νƒ€μž…μ—λ§Œ 채택될 수 μžˆλ„λ‘ μ œν•œν•  수 μžˆλ‹€.
  • 맨 μ²˜μŒμ— class ν‚€μ›Œλ“œλ₯Ό λ„£μ–΄μ•Ό ν•œλ‹€.
protocol ClassOnlyProtocol: class, Readable, Writeable {
  // 이 ν”„λ‘œν† μ½œμ€ ν΄λž˜μŠ€μ—μ„œλ§Œ 채택 κ°€λŠ₯
}

ν”„λ‘œν† μ½œ μ‘°ν•©(composition)

  • λ§€κ°œλ³€μˆ˜ νƒ€μž…μ— μ—¬λŸ¬ ν”„λ‘œν† μ½œμ„ ν•œ λ²ˆμ— μ‘°ν•©ν•˜μ—¬ μš”κ΅¬ν•  수 있음
    • 주어진 ν”„λ‘œν† μ½œμ„ λͺ¨λ‘ μ€€μˆ˜ν•΄μ•Ό 함
  • λ§€κ°œλ³€μˆ˜ ν•˜λ‚˜κ°€ ν”„λ‘œν† μ½œμ„ λ‘˜ 이상 μš”κ΅¬ν•  수 있음
  • νŠΉμ • 클래슀의 μΈμŠ€ν„΄μŠ€ 역할을 ν•  수 μžˆλŠ”μ§€λ„ ν•¨κ»˜ 확인할 수 있음
    • 단, ν΄λž˜μŠ€λŠ” ν•œ νƒ€μž…λ§Œ μ‘°ν•©ν•  수 있음
protocol Named {
    var name: String { get }
}

protocol Aged {
    var age: Int { get }
}

func celebrateBirthday(to celebrator: Named & Aged) {
    print("Happy Birthday \(celebrator.name)! Now you ard \(celebrator.age)")
}

class Car: Named {
  var name: String

  init(name: String) {
    self.name = name
  }
}

var someVariable: Car & Named

ν”„λ‘œν† μ½œ μ€€μˆ˜ 확인

νƒ€μž…μΊμŠ€νŒ…μ˜ is, as μ—°μ‚°μžλ‘œ λŒ€μƒμ΄ ν”„λ‘œν† μ½œμ„ μ€€μˆ˜ν•˜λŠ”μ§€ ν™•μΈν•˜κ±°λ‚˜, νŠΉμ • ν”„λ‘œν† μ½œλ‘œ μΊμŠ€νŒ…ν•  수 μžˆλ‹€.

  • is : ν•΄λ‹Ή μΈμŠ€ν„΄μŠ€κ°€ ν”„λ‘œν† μ½œμ„ μ€€μˆ˜ν•˜λŠ”μ§€ 확인
  • as? : λ‹€λ₯Έ ν”„λ‘œν† μ½œλ‘œ λ‹€μš΄μΊμŠ€νŒ… μ‹œλ„
  • as! : λ‹€λ₯Έ ν”„λ‘œν† μ½œλ‘œ κ°•μ œ λ‹€μš΄μΊμŠ€νŒ…
struct Person: Named, Aged {
  var name: String
  var age: Int
}

let bibi: Person = Person(name: "bibi", age: 99)
print(bibi is Named) // true
print(bibi is Aged) // true

if let castedInstance: Name = bibi as Named {
  print("\(castedInstance) is Named")
} // Person is Named

ν”„λ‘œν† μ½œ λ³€μˆ˜μ™€ μƒμˆ˜

  • ν”„λ‘œν† μ½œμ„ νƒ€μž…μœΌλ‘œ κ°–λŠ” λ³€μˆ˜/μƒμˆ˜μ—λŠ”, κ·Έ ν”„λ‘œν† μ½œμ„ μ€€μˆ˜ν•˜λŠ” νƒ€μž…μ˜ μ–΄λ–€ μΈμŠ€ν„΄μŠ€λ“  ν• λ‹Ήν•  수 μžˆλ‹€.
  • ν”„λ‘œν† μ½œλ§ŒμœΌλ‘œ 슀슀둜 μΈμŠ€ν„΄μŠ€ 생성 및 μ΄ˆκΈ°ν™”λ₯Ό ν•  μˆ˜λŠ” μ—†λ‹€.

μœ„μž„μ„ μœ„ν•œ ν”„λ‘œν† μ½œ (Delegation)

  • μœ„μž„(Delegation λΈλ¦¬κ²Œμ΄μ…˜) : ν΄λž˜μŠ€λ‚˜ ꡬ쑰체가 μžμ‹ μ˜ μ±…μž„μ„ λ‹€λ₯Έ μΈμŠ€ν„΄μŠ€μ—κ²Œ μœ„μž„ν•˜λŠ” λ””μžμΈ νŒ¨ν„΄.
    • μ±…μž„μ„ μˆ˜ν–‰ν•˜λ„λ‘ μ •μ˜ν•œ ν”„λ‘œν† μ½œμ„ μ€€μˆ˜ν•˜λŠ” νƒ€μž…μ€ κ·Έ μ±…μž„μ„ μˆ˜ν–‰ν•¨μ΄ 보μž₯λ˜λ―€λ‘œ, ν”„λ‘œν† μ½œμ„ μ€€μˆ˜ν•  λ•Œ μ±…μž„μ„ μœ„μž„ν•  수 μžˆλ‹€.
  • μœ„μž„ νŒ¨ν„΄μ€ μ• ν”Œ ν”„λ ˆμž„μ›Œν¬μ—μ„œ μ‚¬μš©ν•˜λŠ” μ£Όμš” νŒ¨ν„΄μ΄λ‹€.
    • λ‹€μ–‘ν•œ ν”„λ‘œν† μ½œμ΄ "...Delegate"와같은 μ΄λ¦„μœΌλ‘œ μ •μ˜λ˜μ–΄ μžˆλ‹€.
    • 예) UITableView νƒ€μž…μ˜ μΈμŠ€ν„΄μŠ€κ°€ ν•  일을 μœ„μž„λ°›μ•„ μ²˜λ¦¬ν•˜λŠ” μΈμŠ€ν„΄μŠ€λŠ” UITableViewDelegate ν”„λ‘œν† μ½œμ„ μ€€μˆ˜ν•΄μ•Ό 함