메서드, 속성 및 기타 요구사항의 청사진을 정의하여 클래스, 구조체 또는 열거형에서 구현할 수 있는 일종의 인터페이스인 프로토콜에 대해 공부해 봅니다.
#1. protocal
#2. associatedtype
#1. protocal
☑️ protocol
-
- 프로토콜에서는 이름과 타입 그리고 gettable, settable을 명시한다.
- 프로토콜은 설계된 조건만 정의를 하고 제시를 할 뿐 스스로 기능을 구현하지 않는다.
- class, structure, enum이 프로토콜을 ‘채택’하고 요구사항을 충족하면 프로토콜을 ‘준수’했다고 한다.
- 프로퍼티는 항상 var로 선언해야 한다.
- 메서드를 정의할 때 메서드 이름과 리턴값을 지정할 수 있고, ****{}(구현 코드)는 적지 않는다.
- 상속과 유사하다고 볼 수도 있겠지만 class 이외에 struct나 enum도 프로토콜을 채택할 수 있다는 특징이 있습니다
- 상속은 다중 상속이 불가능하지만 프로토콜은 다중 상속이 가능합 (확장성이 높음)
protocol 프로토콜이름 { // 프로토콜 정의 } // 상속받는 클래스의 프로토콜 채택 class 클래스이름: 슈퍼클래스, 프로토콜1, 프로토콜2 { // 클래스 정의 } protocol Vehicle { var speed: Double { get set } // get과 set을 모두 요구하는 가변 속성 var manufacturer: String { get } // 읽기 전용 속성 } class Car: Vehicle { var speed: Double = 0.0 // get과 set이 요구되는 속성을 구현 var manufacturer: String = "Toyota" // 읽기 전용 속성을 구현 } class Bicycle: Vehicle { var speed: Double = 0.0 // get과 set이 요구되는 속성을 구현 var manufacturer: String { return "Giant" } // 읽기 전용 속성을 연산 프로퍼티로 구현 } let car = Car() car.speed = 60.0 // set 가능 print(car.speed) // get 가능 print(car.manufacturer) // get 가능 let bike = Bicycle() bike.speed = 20.0 // set 가능 print(bike.speed) // get 가능 print(bike.manufacturer) // get 가능
// 예시 protocol Student { var studentId: Int { get set } var name: String { get } func printInfo() -> String } struct UnderGraduateStudent: Student { var studentId: Int var name: String var major: String func printInfo() -> String { return "\\(name), whose student id is \\(studentId), is major in \\(major)" } } struct GraduateStudent: Student { var studentId: Int var name: String var degree: String var labNumber: Int func printInfo() -> String { return "\\(name), member of lab no.\\(labNumber), has a \\(degree) degree" } } // 프로토콜은 타입으로서도 사용가능 let underGraduate: Student = UnderGraduateStudent(studentId: 1, name: "홍길동", major: "computer") let graduate: Student = GraduateStudent(studentId: 2, name: "김철수", degree: "master", labNumber: 104) let studentArray: [Student] = [underGraduate, graduate]
// 프로토콜의 다중상속 protocol Coordination { var top: String { get set } var pants: String { get set } init(top: String, pants: String) func checkCoordination() } protocol Hair { var hair: String { get } func checkHairStyle() } struct Person: Coordination, Hair { var top: String var pants: String let hair: String = "포마드" func checkHairStyle() { print("오늘의 헤어스타일은 \\(hair)스타일") } func checkCoordination() { print("상의: \\(top)\\n하의: \\(pants)") } init(top: String, pants: String) { self.top = top self.pants = pants } } let safari: Person = Person(top: "긴팔", pants: "반바지") safari.checkHairStyle() safari.checkCoordination() //오늘의 헤어스타일은 포마드스타일 //상의: 긴팔 //하의: 반바지
#2. associatedtype, typealias
☑️ associatedtype
- 프로토콜 내에서 실제 타입을 명시하지 않고, 해당 프로토콜을 채택하는 타입에서 실제 타입을 결정하도록 하는데 사용
- 프로토콜에서 특정 메서드, 속성 또는 서브스크립트의 반환 타입이나 매개변수 타입으로 구체적인 타입을 명시하지 않고 대신 associatedtype으로 선언하여 프로토콜을 채택하는 타입에서 실제 타입을 정의할 수 있다.
☑️ typealias
- typealias는 기존 타입에 대해 새로운 이름을 지정하거나 복잡한 타입에 대한 간결한 별칭을 생성할 때 사용됩니다.
- 코드를 읽기 쉽게 만들거나 여러 번 사용되는 긴 타입 이름을 간략하게 대체할 때 유용합니다.
protocol Container {
associatedtype Item // 연관 타입
var count: Int { get }
mutating func append(_ item: Item)
func item(at index: Int) -> Item
}
struct IntContainer: Container {
typealias Item = Int // 연관 타입을 Int로 typealias하여 구현
var items = [Item]()
var count: Int {
return items.count
}
mutating func append(_ item: Item) {
items.append(item)
}
func item(at index: Int) -> Item {
return items[index]
}
}
var intBox = IntContainer()
intBox.append(5)
intBox.append(10)
print(intBox.item(at: 0)) // 출력: 5
/*
위의 예시에서 Container 프로토콜은 Item이라는 연관 타입을 가지고 있습니다.
이 연관 타입은 Container 프로토콜을 채택하는 구체적인 타입에서 실제 타입으로 정의됩니다.
IntContainer 구조체에서 Item을 Int로 typealias하여 실제 타입을 정의하고,
이를 사용하여 배열에 Int 값을 저장하고 반환하는 메서드를 구현합니다.
*/
'iOS 앱 개발자 프로젝트 > Swift 문법 정복하기' 카테고리의 다른 글
[Swift] Generic (0) | 2024.03.13 |
---|---|
[Swift] Extension (0) | 2024.03.13 |
[Swift] Exception (throws, throw, do-catch, try) (0) | 2024.03.13 |
[Swift] Property Observer, Type Casting, Access Modifier (0) | 2024.03.13 |
[Swift] Inheritance, Initializer (0) | 2024.03.12 |