** edwith - Swift 프로그래밍 입문 강의 참고 **
# 프로토콜(protocol) #
- 구조체, 클래스, 열거형 등에 프로토콜을 이용해서, 어떠한 기능을 구현해놔야 하는지 알려줍니다.
- 클래스 상속은 클래스끼리만 가능했던 것과 달리,
프로토콜을 따르는 것은 클래스 뿐만 아니라 value type인 struct, enum에도 적용 가능합니다.
- 따라서 보다 넓은 확장성과 재사용성을 보장합니다.
protocol pName {
/* 프로토콜 정의 */
}
[ 프로퍼티 요구 ]
protocol Talkable {
/* 프로퍼티 요구 - 항상 var 사용 */
var topic: String { get set } // 읽고 쓰기 모두 가능
var language: String { get } // 읽기 전용
/* 메서드 요구 */
func talk()
/* 이니셜라이저 요구 */
init(topic: String, language: String)
}
[ 프로토콜 채택 및 준수 ]
// Person 구조체는 Talkable 프로토콜 채택
struct Person: Talkable {
// 프로퍼트 요구 준수
var topic: String // get set
let language: String // get
/* 다음과 동일
var language: String { return "한국어" }
var topic: String {
set {
self.subject = newValue
}
get {
return self.subject
}
}
*/
// 메서드 요구 준수
func talk() {
print("\(topic)에 대해 \(language)로 말합니다")
}
// 이니셜라이저 요구 준수
init(topic: String, language: String) {
self.topic = topic
self.language = language
}
}
# 프로토콜 상속 #
- 하나 이상의 프로토콜을 상속받아 기존 프로토콜의 요구사항보다 더 많은 요구사항을 추가 가능
- 프로토콜 상속 문법은 클래스의 상속 문법과 유사
- 그러나 클래스와 다르게 다중상속 가능
protocol Readable {
func read()
}
protocol Writeable {
func write()
}
protocol ReadSpeakable: Readable {
func speak()
}
protocol ReadWriteSpeakable: Readable, Writeable { // 이렇게 다중 상속 가능 //
func speak()
}
struct SomeType: ReadWriteSpeakable {
func read() {
print("read")
}
func write() {
print("write")
}
func speak() {
print("speak")
}
}
[ 클래스 상속과 프로토콜 ]
- 클래스에서 상속과 프로토콜 채택을 동시에 하려면,
상속받으려는 클래스를 먼저 명시하고 그 뒤에 채택할 프로토콜 목록을 작성
class SuperClass: Readable {
func read() { }
}
class SubClass: SuperClass, Writeable, ReadSpeakable {
func write() { }
func speak() { }
}
[ 프로토콜 준수 확인 ]
- is, as 연산자를 사용하여 인스턴스가 특정 프로토콜을 준수하는지 확인 가능
let super: SuperClass = SuperClass()
let sub: SubClass = SubClass()
var someAny: Any = super
someAny is Readable // true
someAny is ReadSpeakable // false
someAny = sub
someAny is Readable // true
someAny is ReadSpeakable // true
someAny = super
if let someReadable: Readable = someAny as? Readable {
someReadable.read()
} // read
if let someReadSpeakable: ReadSpeakable = someAny as? ReadSpeakable {
someReadSpeakable.speak()
} // 동작하지 않음 -> someAny가 ReadSpeakable에 준수하지 않기 때문에
someAny = sub
if let someReadable: Readable = someAny as? Readable {
someReadable.read()
} // read
# 익스텐션 (extension) #
- 구조체, 클래스, 열거형, 프로토콜 타입에 새로운 기능을 추가할 수 있는 기능
- 기능을 추가하려는 타입의 구현된 소스코드를 몰라도, 타입만 알고 있다면 그 타입의 기능을 확장 할 수 있습니다.
- 다만, 기존에 존재하는 기능을 재정의할 수는 없습니다.
[ 클래스의 상속 vs 익스텐션 ]
상속 | 익스텐션 | |
확장 | 수직 확장 | 수평 확장 |
사용 | 클래스 타입 | 클래스, 구조체, 프로토콜, 제네릭 등 모든 타입 |
재정의 | 가능 | 불가능 |
[ 구현 예시 ]
- Int 타입에 홀수인지 짝수인지 판별해주는 Bool타입 연산 프로퍼티 추가
extension Int {
var isEven: Bool { return self%2==0 }
var isOdd: Bool { return self%2==1 }
}
print(1.isEven) // false
print(2.isEven) // true
print(1.isOdd) // true
print(2.isOdd) // false
var number: Int = 3
print(number.isEven) // false
print(number.isOdd) // true
[ 메서드 추가 ]
/* 메서드 익스텐션을 통해 Int 타입에 인스턴스 메서드인 multiply(by:) 메서드 추가 */
extension Int {
func multiply(by n: Int) -> Int { return self*n }
}
print(3.multiply(by: 2)) // 6
print(4.multiply(by: 5)) // 20
var number: Int = 3
print(number.multiply(by: 2)) // 6
[ 이니셜라이저 추가 ]
- 인스턴스를 초기화(이니셜라이즈)할 때, 인스턴스 초기화에 필요한 다양한 데이터를 전달받을 수 있도록 여러 종류의 이니셜라이즈를 만들 수 있습니다.
- 하지만, 지정이니셜라이저와 디이니셜라이저는 반드시 클래스 타입의 구현부에 위치해야 합니다.
extension String {
init(int: Int) { self = "\(int)" }
init(double: Double) { self = "\(double)" }
}
let stringFromInt: String = String(int: 100) // "100"
let stringFromDouble: String = String(double: 200.0) // "200.0"
'iOS > Swift' 카테고리의 다른 글
Swift-11. 고차 함수 - map, filter, reduce (0) | 2023.02.24 |
---|---|
Swift-10. 오류 처리 - throw, rethrows, defer (0) | 2023.02.24 |
Swift-8. assert, precondition, guard (0) | 2023.02.24 |
Swift-6. 옵셔널 체이닝, nil 병합 (0) | 2023.02.24 |
Swift-5. 인스턴스 생성 및 소멸 (0) | 2023.02.24 |
댓글