기어가더라도 제대로

[Swift-기초] Extension, protocol Extension - 100 days of SwiftUI 본문

Swift - 기초

[Swift-기초] Extension, protocol Extension - 100 days of SwiftUI

Damagucci-juice 2022. 10. 2. 09:56

Extension 

  • 일종의 확장판을 만든는 개념
  • 커스텀한 타입뿐 아니라 String, Int 등 기존에 있는 타입에서도 사용 가능
  • extension 키워드 사용 
  • 다음 확장하려는 타입을 명시
  • { } 사이에 있는 코드는 그 타입에 기능적으로 추가됨

예시

var quote = "   The truth is rarely pure and never simple   "
let trimmed = quote.trimmingCharacters(in: .whitespacesAndNewlines)

 

  • String 에 존재하는 trimmingCharacters(in:) 이라는 메서드는 반환값을 내보낸다. 
  • 메서드를 실행한 결과를 따로 담아놀 trimmed 라는 변수가 필요한데 extension 으로 이를 줄이면 다음과 같다.

혹은 더 짧게 구현도 가능하다. 

let trimmed = quote.trimmed()
let trimmed2 = trim(quote)

Extension 의 장점

  • 전역 함수로서 기능한다, 쉽게 찾을 수 있다.
  • 전역 함수 작성보다 코드가 깔끔해진다. 관련 타입들의 extension 끼리 모아 놓을 수 있기 때문
  • 타입 그 자체의 메서드라서 private 속성이나 메서드도 사용할 수 있다. 

동사원형() 메서드와 과거형 메서드() -ed() 의 차이

  • Swift 가이드라인에서 제안
  • -ed 형 메서드, -ing 형 메서드
    • 원본 자료형의 값을 변경하지 않고 변화를 적용시킨 복사본을 리턴
    • trimmed(), reversed(), sorted() ...
  • 동사원형 메서드
    • 원본 자료형의 값을 변경함
    • trim(), sort()...

Extension 의 특징

  • 타입에 변수를 추가할 수 있는데, 반드시 연산 프로퍼티여야 한다. 
  • 저장 프로퍼티 X
  • 새로운 저장 프로퍼티는 원본 타입의 실제 데이터 크기에 영향을 줄 수 있기 때문

Extension Example - String 

extension String {
    var lines: [String] {
        self.components(separatedBy: .newlines)
    }
}

let lyrics = """
But I keep cruising
Can't stop, won't stop moving
It's like I got this music in my mind
Saying it's gonna be alright
"""

print(lyrics.lines.count)

 

Extension Trick - initializer

  • 커스텀 타입에서 멤버 와이즈 이니셜라이저 와 커스텀 이니셜 라이저 를 같이 사용하고 싶은 경우
    • 커스텀 이니셜라이저를 사용하면 멤버 와이즈 이니셜라이저는 더 이상 자동 제공되지 않는다. 
struct Book {
    let title: String
    let pageCount: Int
    let readingHours: Int
}

extension Book {
    init(title: String, pageCount: Int) {
        self.title = title
        self.pageCount = pageCount
        self.readingHours = pageCount / 50
    }
}
// 기본 멤버와이즈 이니셜라이저
let lotr = Book(title: "Lord of the Rings", pageCount: 1178, readingHours: 24)

// 커스텀 이니셜라이저
let pig3brother = Book(title: "돼지 3형제", pageCount: 39)

 


protocol extension 의 생성과 사용

  • 프로토콜에 extension 을 추가하면 어떻게 될까?
    • 프로토콜은 타입이 지켜야하는 계약서
    • extension 은 존재하는 타입에 기능적인 추가
  •  프로토콜을 채택한 타입들에서 구체적인 선언을 하지 않고 프로토콜만 채택하면 사용가능한 기능을 추가할 수 있다. 

예시 - 1

let guests = ["Mario", "Luigi", "Peach"]

if guests.isEmpty == false {
    print("Guest count: \(guests.count)")
}

if !guests.isEmpty {
    print("Guest count: \(guests.count)")
}
  • "만약 게스트가 비어있지 않다면" 이라는 조건문은 가독성 측면에서 좋지 않음

  • Array, Set, Dictionary 가 채택하는 Collection 이라는 프로토콜에 extension 으로 저런 속성을 달아주면
// 변경 후
if guests.isNotEmpty {
    print("Guest count: \(guests.count)")
}

// 변경 전
if !guests.isEmpty {
    print("Guest count: \(guests.count)")
}
  • extension 으로 간단한 추가만 했을 뿐인데 훨씬 가독성이 좋은 코드가 나왔다. 

예시 - 2

  • 처음 접하면 그냥 Employee 에서 extension 달면 된다고 생각할 수 있는데
  • 이는 Swift 에서 추구하는 방향인 Protocol Oriented Programming 을 수월하게 구현해준다.
    • 아직은 "그런게 있나보네" 하는 수준까지만 인지해도 좋다.
Comments