제네릭 문법
- 형식에 관계없이, 한 번의 구현으로 모든 타입을 처리하여 타입에 유연한 함수를 작성하는 문법이다.
- 유지보수 및 재사용성이 증가하는 장점이 있다.
- 함수뿐만 아니라 구조체, 클래스, 열거형도 제네릭으로 일반화가 가능하다.
제네릭 문법이 필요한 이유
- 타입만 다르고 구현 내용이 동일한 경우, 제네릭이 없다면 타입마다 모든 경우를 다 정의해줘야 한다. 개발자의 일이 늘고, 유지보수 및 재사용성이 어렵게 만들기 때문이다.
제네릭 함수의 정의
func genericsFunc<T>(array: [T]){
// code
}
- <T>는 타입 파라미터라고 한다. 함수 내부에서 파라미터의 타입이나 리턴형으로 사용된다.
- 관습적으로 Type의 의미인 T를 사용하기도 하지만, 다른 문자를 사용해도 된다. (형식 이름이기 때문에 UpperCamelCase로 선언)
- <T, U>처럼 타입 파라미터를 2개 이상 선언하는 것도 가능하다.
구조체 제네릭으로 정의하기
struct GenericMember<T> {
var members: [T] = []
}
let numMember = GenericMember(members: [1, 2, 3])
let strMember = GenericMember(members: ["안녕", "하이"])
클래스 제네릭으로 정의하기
class GridPoint<A> {
var x: A
var y: A
init(x: A, y: A){
self.x = x
self.y = y
}
}
let aPoint = GridPoint(x: 10, y: 20)
let aPoint = GridPoint(x: 3.2, y: 5.3)
열거형 제네릭으로 정의하기
enum Pet<T> {
case dog
case cat
case bird
case etc(T)
}
let myPet = Pet.cat
- 열거형은 연관값을 가질 때 제네릭으로 정의할 수 있다.
제네릭 확장
struct Coordinates<T> {
var x: T
var y: T
}
extension Coordinates {
func getPlace() -> (T, T) {
return (x, y)
}
}
extension Coordinates where T == Int {
func getPlace() -> (T, T) {
return (x, y)
}
}
- 확장 시에도 기존에 구현되어 있던 타입 파라미터를 활용해 위와 같이 정의할 수 있다.
- where 절을 활용해 특정 타입일 때만 확장되도록 설정할 수 있다.
타입 제약(Type Constraint)
func findIndex<T: Equatable>(item: T, array: [T]) -> Int? {
for (index, value) in array.enumerated() {
if item == value {
return index
}
}
return nil
}
- 제네릭에서 타입을 제약할 수 있다.
- 타입 매개 변수 이름 뒤 콜론으로 프로토콜 제약 조건 또는 단일 클래스를 배치할 수 있다.
구체 / 특정화(specialization) 함수 구현 가능
func findIndex(item: String, array: [String]) -> Int? {
for (index, value) in array.enumerated() {
if item.caseInsensitiveCompare(value) == .orderedSame {
return index
}
}
return nil
}
- 위와 같이 동일한 함수 이름에 구체적인 타입을 명시하면, 해당 구체적인 타입의 함수가 실행된다.
프로토콜에서 제네릭의 사용 (Associated Types)
protocol RemoteControl {
associatedtype Element
func changeChannel(to: Element)
func alert() -> Element?
}
struct TV: RemoteControl {
typealias Element = Int // 생략 가능
func changeChannel(to: Int) {
print("TV 채널바꿈")
}
func alert() -> Int? {
return 1
}
}
- <T>처럼 기존의 타입 파라미터 형식이 아닌 associatedtype T 형태로 정의한다.
- 프로토콜에서는 T 대신 Element을 관습적으로 많이 사용하고 있다
- 프로토콜은 타입들이 채택할 수 있는 요구사항만을 선언하는 개념이기 때문에 제네릭 타입과 조금 다른 개념이 도입된 것으로 추정된다.
- 프로토콜을 채택하는 쪽에서는 구현해야하는 함수에 타입을 정확히 명시하면 된다. 또는 typealias로 실제 형식을 표시해야한다.
728x90
'FRONT-END > iOS' 카테고리의 다른 글
Swift 고급연산자 (1) | 2023.08.29 |
---|---|
Swift 문자열과 문자(String and Character) (2) | 2023.08.28 |
iOS 화면 시스템 (프레임 vs 오토레이아웃) (0) | 2023.08.10 |
Xcode MARK, 코드 스니펫 설정하는 법 (0) | 2023.08.10 |
Swift 에러 처리(Error Handling) (0) | 2023.08.07 |
댓글