확장 (Extension) 이란?
클래스, 구조체, 열거형 타입에 새로운 property, method, initializer 등을 추가하는 것을 말하는데,
원본 타입에 접근하지 못하는 타입에도 확장해서 사용할 수 있다.
확장은 어떻게 사용하나?
⭐ 포인트는 "기존에 것에 추가한다" 이다. ⭐
아래와 같이 CGPoint 라는 구조체가 있다.
let point: CGPoint = .init(x: 10, y: 20)
여기서 point 라는 변수를 print 문을 이용하여 아래와 같이 출력하고 싶다면?
x: 10, y: 20
근데 CGPoint란 구조체에는 위에 처럼 출력해줄 수 있는 기능이 없다.
따라서 출력하려면 아래와 같이 직접 print 문을 사용하여 구현해야 한다.
print("x: \(point.x), y: \(point.y)")
CGPoint에 직접 출력할 수 있는 print 기능을 넣을 때 사용하는게 바로
"extension" 이다.
extension CGPoint {
func printPoint() {
print("x: \(self.x), y: \(self.y)")
}
}
point 변수를 출력할 떄는 아래와 같이 사용하면 된다.
HomeViewController 라는 클래스에 TweetTableViewCellDelegate 라는 프로토콜을 준수하고 싶다면?
아래와 같이 사용해도 되지만 이러면 가독성이 떨어진다.
class HomeViewController: TweetTableViewCellDelegate {
...
}
이 때 "extension" 이라는 키워드를 사용하여 클래스 입장에서 준수해야 하는 또는 추가해야 하는 것을
분리하여 작성하면 가독성이 좋다.
class HomeViewController: UIViewController {
...
}
extension HomeViewController: TweetTableViewCellDelegate {
...
}
확장에 연산 프로퍼티 추가
저장 프로퍼티는 추가할 수 없고, "연산 프로퍼티"만 추가 가능하다.
저장 프로퍼티를 추가하면 에러가 발생한다.
연산 프로퍼티는 아래와 같이 사용된다.
extension Int {
var half: Int {
return self / 2
}
}
사용하려면?
let num = 100
print(num.half) // 50
확장에 메서드 추가
인스턴스 메서드, 타입 메서드 모두 추가 가능하다.
// 타입 메서드
extension Int {
static func printZero() {
print(0)
}
}
Int.printZero() // 0
// 인스턴스 메서드
extension Int {
func printDouble() {
print(self * 2)
}
}
let num = 100
num.printDouble() //200
확장에 생성자 (initializer) 추가
기존 타입에 새로운 이니셜라이저를 추가할 수 있다.
Class에 생성자 추가
Designated initializer는 추가할 수 없고 Convenience initializer만 추가할 수있으며,
deinitializer를 추가할 수 없다.
deinit 안되고,
init 안되고
convenience init 메서드만 구현할 수 있다.
Struct에 생성자 추가
extension으로 생성자를 추가할 경우, Memberwise Initializer를 보존하며 새로운 생성자를 추가할 수 있다
✅ Memberwise Initializer는 "기본 생성자를 자동으로 제공하는 기능"을 갖고 있다.
✅ Class는 생성자를 지정해야줘야하지만, Struct는 그렇지 않다는 것을 말한다.
여기서 자동으로 제공해주는 Memberwise Initializer를 대신하여 struct에 직접 생성자를 구현한다면?
struct PointStruct {
let x: Int
let y: Int
init(value: Int) {
self.x = value
self.y = value
}
}
이 경우에는 더이상 "Memberwise Initializer" 기능은 제공되지 않는다.
여기서 "extension"을 사용한다면?
기존의 Memberwise Initializer를 보존하면서 새로운 생성자를 추가할 수 있다
struct PointStruct {
let x: Int
let y: Int
}
extension PointStruct {
init(value: Int) {
self.x = value
self.y = value
}
}
Memberwise Initializer를 보존하면서 생성자를 추가할 수 있다.
확장에 서브스크립트(Subscript) 추가
extension String {
subscript(idx: Int) -> String? {
guard (0..<count).contains(idx) else {
return nil
}
let target = index(startIndex, offsetBy: idx)
return String(self[target])
}
}
위의 extension을 통해 서브스크립트를 구현하면
let sodeul = "Hello, Sodeul!"
sodeul[0] // Optional("H")
sodeul[100] // nil
[]를 통해 내가 원하는 index의 문자에 접근할 수 있다.
확장에 중첩 타입 추가
extension Int {
enum Kind {
case negative, zero, positive
}
var kind: Kind {
switch self {
case 0:
return .zero
case let x where x > 0:
return .positive
default:
return .negative
}
}
}
위의 코드처럼 Int 탸입의 extension 안에 Kind라는 enum을 중첩해서 선언할 수 있다.
let num = 100
print(num.kind) // positive
let num2 = -100
print(num2.kind) // negative
'iOS > Swift' 카테고리의 다른 글
고차함수 (Map, Filter, Reduce) (0) | 2024.05.26 |
---|---|
MVC 패턴 (Model - View - Controller) (0) | 2024.05.25 |
클로저 6편 (1) | 2024.02.17 |
클로저 5편 (1) | 2024.02.13 |
클로저 4편 (0) | 2024.02.10 |