Extension과 Protocol은 Swift에서 자주 사용되는 기능이다. 값에 접근이 불가함에도 Extension으로 추가 기능을 구현할 수 있고, Protocol의 경우 POP라는 개념으로 Apple에서 밀어주는? 개념이다. Generic의 경우 코드 중복을 줄일 수 있는 좋은 기능이다. 잘 다뤄둔다면 중급(?) 이상의 개발자가 되는데 큰 도움을 줄 것이다.(~그렇게 믿고 있다 ㅜㅜ~) 그럼 시작해보자!

Extension

  • class, struct, enum 확장 가능
  • 원본 소스에 접근할 수 없어도 사용가능
  • Objective-C의 category와 유사한 기능
  • 접근제어 가능
  • 가능한 것들
    • computed property 추가
    • method 추가
    • initializer 추가
      • designated intializer, deinitializer 추가 불가
      • 새로운 initializer, convenience initializer 추가 가능
      • 추가된 initializer에서 default initializer, memberwise initializer 호출 가능
    • subscript 추가
    • nested type 추가
    • 특정 protocol의 confirm
    • protocol 확장

Protocol

  • 어떤 작업/기능을 위한 method, property의 interface 정의시 사용

  • class, struct, enum에 채택되며 그때 해당 type은 요구 사항을 구현 해야 함

  • 이를 구현한 경우, type이 protocol을 준수한다고 함

  • Objective-C에 비해 나아진 점

    • type처럼 사용 가능
    • protocol extension을 이용하여 default implementation 가능
      • 준수하는 모든 type이 추가작업 없이 확장 기능을 가짐
    • protocol 기반 프로그래밍을 POP라 부름
  • 예시

    protocol SomeProtocol {
      var mustBeSettable: Int { get, set }
      var doesNotNeedToBeSettable: Int { get }
    }
  • Protocol Type

    • 모든 type과 동일한 동작 가능
      • return type 가능
      • property로 사용 가능
      • container(array, dictionary etc)의 element로 사용 가능
  • Inheritance

    • 기존 존재하는 다른 protocol을 상속받아 확장 가능
    • class와 달리 multiple inheritance 가능
  • Class-only Protocol

    • class에서만 사용가능하도록 제약 가능
      protocol SomeClassOnlyProtocol: AnyObject, SomeInheritedProtocol {
          // statement
      }
  • Protocol Composition

    • 두개 이상 protocol을 만족하는 type을 정의할 수 있음

      protocol Named {
          var name: String { get }
      }
      
      protocol Aged {
          var age: Int { get }
      }
      
      struct Person: Named, Aged {
          var name: String
          var age: Int
      }
      
      func withHappyBirthday(to celebrator: Named & Aged) {
          // statement
      }
  • is, as 연산자의 의미

    • is
      • protocol conform시 True
    • as
      • as?
        • protocol conform하지 않으면 nil
      • as!
        • protocol conform하지 않으면 runtime error
  • Optinal Protocol Requirement

    • Objective-C에서 처럼 Optional 정의 가능
    • 단, Objective-C class 상속 받은 class만 채택가능
    • @objc attribute 사용하여 선언
    • @objc optional var ...
    • @objc optional func ...
  • Protocol Constraint

    • protocol을 conform할 수 있는 타입에 대한 제약을 걸 수 이씅ㅁ
    • where 사용
      protocol RandomBAckgroundColorView where Self: UIView {
          // statement
      }
  • Protocol Extension

    • Default function
      extension RandomNumberGenerator {
          func randomBool() -> Bool {
            return random() > 0.5
          }
      }
    • Default Value
      extension CounterDataSource {
          var fixedIncrement: Int {
            return 0
          }
      }
      • extension으로 default value를 구현해두면, 필요시에만 추가 구현하도록 처리가 가능
      • 경우에 따라서 optional을 대체할 수 있음
        • @objc attribute 지울 수 있음
    • Constraint 추가
      • 확장시 제약을 걸 수 있음
      • where 사용
      • protocol 자체 기능 (내부에 구현되어 있는)만 이용해서 기능 확장 해야함
      • 기존에 그 protocol을 준수하는 모든 type이 확장된 기능을 가지게 됨
        extension Collection where Element: Equatable {
            func allEqual() -> Bool {
                for element in self {
                    if element != self.first {
                        return False
                    }
                }
            }
        }

Generic

  • <> 안에 들어간 것을 placeholder라 함

  • function내부에서 parameter type이나 return type으로 사용가능

    func swap<T>(_ a: inout T, _ b: inout T) {
        let temp = a
        a = b
        b = a
    }
    
    struct Stack<Element> {
        var items = [Element]()
        mutating func push(_ item: Element) {
            self.items.append(item)
        }
        mutating func pop() -> Element {
            return self.items.removeLast()
        }
    }
  • Type Constraint

    func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) {
      
    }
  • Associated Type

    • protocol 정의 시 그 protocol이 사용할 임의의 type을 선언해 둘 수 있음

    • associatedtype

      protocol Container {
          associatedtype Item // Item이라는 type이 있을 거야~
          mutating func append(_ item: Item)
          var count: Int { get }
          subscript(i: Int) -> Item { get }
      }
      
      struct Stack<Element>: Container {
          var items = [Element]()
          mutating func push(_ item: Element) {
              self.items.append(item)
          }
          mutating func pop() -> Element {
              return self.items.removeLast()
          }
      
          typealias Item = Element // associated type인 Item을 Element라 할거야: type inference로 생략가능
          mutating func append(_ item: Element) {
              self.push(item)
          }
      
          var count: Int {
              return items.count
          }
      
          subscript(i: Int) -> Element {
              return items[i]
          }
      }
  • where

    • type parameter에 where절을 이용해서 제약 가능
      func allItemsMatch<C1: Container, C2: Container>(_ c1: C1, c2: C2) -> Bool where C1.item == C2.Item, C1.Item: Equatable {
        
      }
      • C1.item == C2.Item은 두 container의 item이 동일한 type이라는 제약
      • C1.Item: Equatable item이 비교 가능한 type이어야 한다는 제약
profile
목표와 계획, 그리고 실천의 힘을 믿습니다.

0개의 댓글