Search

Generic / Protocol - 이경헌

목차

1.
Generic(제네릭) 1-1 Generic은 왜 쓸까 1-2 Generic type
2.
Protocol 2-1 Protocol 정의 2-2 요구사항

1. Generic

Generic은 타입에 대한 추상화를 제공

1-1 Generic은 왜 쓸까

func add(_ a: Int, _ b : Int) -> Int { return a + b } func add(_ a: Double, _ b : Double) -> Double { return a + b } func add(_ a: String, _ b : String) -> String { return a + b }
Swift
복사
이렇게 파리미터와 타입별 로 전부 하나씩 노가다 구현할 수 없으니 이럴 때 쓰는 것

1-2 Generic Type

중복을 피하고 명확하고 추상적인 방식으로 의도를 표현하는 코드’
타입 안정성(Type Safety)
코드 재사용성
효율적인 코딩
Swift 표준 라이브러리의 대부분은 제네릭 코드로 구축되었습니다. Swift의 Array 및 Dictionary 유형은 모두 일반 컬렉션입니다.
공식문서의 영향으로? 대부분 Generic Type을 설명할 때 Swap(두 원소의 위치를 변경)으로 주로 설명
func swapTwoInts(_ a: inout Int, _ b: inout Int) { let tmp = a a = b b = tmp } // cf. inout // 해당 파라미터의 값을 함수 로컬 밖에도 변경한게 유지되도록 하고 싶을 때 씀 var integerArr = [5, 3, 2, 0] swapTwoInts(&integerArr[0], &integerArr[1]) // 가능 var doubleArr = [5.0, 4.3, 3.2, 1,2] // ???
Swift
복사
Double형 말고도 String, Character 등 여러 타입용 함수를 정성껏 만들기가 위에 작성해 놓은 ‘코드 재사용’, ‘효율적인 코딩’에 위배
// 제네릭 버전 // 제네릭을 적용할 함수 이름<타입 매개변수> // or 제네릭을 적용할 타입 이름<타입 매개변수> func swap<T>(_ a: inout T, _ b: inout T) { let temp = a a = b b = temp } // double도 가능
Swift
복사
또한 swift로 코딩을 하다가 Array<Element>, Dictionary<Key, Value> 본 이것들이 ‘Generic’이 였던 것

2. Protocol

프로토콜은 특정 작업이나 기능에 적합한 함수, 프로퍼티 및 기타 요구 사항의 청사진을 정의

2-1 Protocol 정의

공식 문서의 설명 문구와 코드에 따르면, 함수, 프로퍼티 및 기타 요구 사항의 선언을 포함하며 정의
// 클래스, 구조 및 열거형과 비슷하게 프로토콜을 정의 protocol SomeProtocol { // 요구 사항을 정의 let somethingg: Int = 0 func doSomething() } // 이름 뒤에 콜론(:)으로 프로토콜들을 채택 struct SomeStructure: FirstProtocol, AnotherProtocol { // 요구 사항을 정의 let somethingg: Int = 0 func doSomething() } // 슈퍼클래스(상속해올 클래스)가 있고 클래스가 프로토콜을 채택할 때, // 해당 슈퍼클래스 이름을 프로토콜 앞에 나열하고 쉼표로 구분 class SomeClass: SomeSuperclass, FirstProtocol, AnotherProtocol { // 요구 사항을 정의 let somethingg: Int = 0 func doSomething() }
Swift
복사

2-2 요구사항

공식 문서의 설명 문구와 코드에 따르면, 요구 사항을 채택하는 형태(클래스, 구조체, 열거형)에게 어떤 동작이나 기능을 작성하여 사용할 ‘프로토콜’ 요구사항을 맞춘다 함
// MARK: - 프로퍼티 요구사항 protocol FullyNamed { // 그냥 'FullName'이라는 전체 이름을 제공할 수 있어야 한다 점만 // (gettable 인스턴스 프로퍼티가 있어야함) 지정 var fullName: String { get } } struct Person: FullyNamed { // 'Person'이라는 구조체는 // 'FullyNamed' 프로토콜의 요구사항인 전체 이름을 제공할 수 있는 변수가 존재 var fullName: String } let john = Person(fullName: "John Appleseed") //john.fullName is "John Appleseed" 라 잘 출력 // MARK: - 함수 요구사항 /// 프로퍼티와 동일하게 프로토콜 정의의 일부로 작성됨 /// 중괄호나 메소드 내부의 정의가 존재 X. /// 프로토콜 정의 내의 함수 매개변수에는 디폴트를 지정 X protocol RandomNumberGenerator { func random() -> Double } class LinearCongruentialGenerator: RandomNumberGenerator { var lastRandom = 42.0 let m = 139968.0 let a = 3877.0 let c = 29573.0 // RandomNumberGenerator 프로토콜의 요구사항인 'random'이라는 메소드가 존재 // 위 프로토콜 선언 부에 비어놓았던 random 메소드를 세부 기능은 // 사용할 class나 구조체에서 요구사항에 맞춰 코딩 func random() -> Double { lastRandom = ((lastRandom * a + c) .truncatingRemainder(dividingBy:m)) return lastRandom / m } } // MARK: - Mutating // struct와 enum 내에서 메서드를 정의하여 내부 프로퍼티를 변경할 때 사용하는 키워드 // 프로토콜에서 사용할 때는 일반 struct와 enum에서 사용하는 방식과 매우 비슷 // 공식문서에선 토클 스위치로 이를 설명함 protocol Togglable { mutating func toggle() } enum OnOffSwitch: Togglable { case off, on // Togglable 프로토콜에 맟춰 세부 기능 코딩 mutating func toggle() { switch self { case .off: self = .on case .on: self = .off } } } var lightSwitch = OnOffSwitch.off lightSwitch.toggle()
Swift
복사

그 외

Delegation Delegation 말 그대로 ‘위임자’ 프로토콜를 공부해보면 틀만 설계해 놓고 사용자가 사용할 때 세부사항을 코딩함 즉 ‘너가 알아서 해라’ 라는 느낌이 강했음. Delegation 패턴은 주로 프로토콜(또는 인터페이스)을 사용하여 다른 객체에 어떤 기능을 위임하거나 대리 수행하도록 하는 디자인 패턴.(ex. UITableView, UICollectionView)

참고