Swift Language ) Extensions
Swift 에서 Extension은,
Enumeration, Struct, Class, 그리고 Protocol 에 새로운 기능을 부여해 줄 수 있어요
또한, 소스코드에 접근할 수 없는 것도 사용할 수 있게 도와줍니다.
TableView 나 CollectionView 등 에서 Delegate, DataSource 를 이용해 기존 ViewController 에
기능을 더해주는 것도 Extension 덕분입니다.
Swift Extension이 할 수 있는 일들은 아래와 같아요!
- Add computed instance properties and computed type properties
- Define instance methods and type methods
- Provide new initializers
- Define subscripts
- Define and use new nested types
- Make an existing type conform to a protocol
또한, Protocol 에 Extension 을 사용함으로써 Protocol conform 에 필요한 requirements 를 Implementation 할 수 있고,
conform 할 Type 들이 사용할 수 있도록 새로운 기능들을 더해줄 수도 있어요! ( override 는 안되요..!)
Extension Syntax
선언하는 방식은 class, struct 등을 하는 방식과 동일합니다.
extension SomeType {
// new functionality to add to SomeType goes here
}
extension 을 이용해서 이미 존재하는 Type이 어떤 Protocols 를 conform 하도록 선언해줄 수 있어요. 쓰는 방법은 class, struct 에서 하는 방식과 동일합니다. (더 자세한 방식은 Protocol 에 써있어요 ! )
(2021.09.16 - [Swift/Swift Language] - Swift Language ) Protocol
extension SomeType: SomeProtocol, AnotherProtocol {
// implementation of protocol requirements goes here
}
이제부터, 앞서 언급했던 Extension 이 할 수 있는 일에 대해 하나하나 알아보도록 하겠습니다.
1. Add computed instance properties and computed type properties
extension Double {
var km: Double { return self * 1_000.0 }
var m: Double { return self }
var cm: Double { return self / 100.0 }
var mm: Double { return self / 1_000.0 }
var ft: Double { return self / 3.28084 }
}
let oneInch = 25.4.mm // return 25.4 / 1000 -> 0.0254
print("One inch is \(oneInch) meters")
// Prints "One inch is 0.0254 meters"
let threeFeet = 3.ft // return 3 / 3.28084 -> 0.9143...
print("Three feet is \(threeFeet) meters")
// Prints "Three feet is 0.914399970739201 meters"
위 예시에서 1.m ==> 1.0
1.km ==> 1000.0
m 를 기준으로 km, cm, mm, ft 를 변환해줬어요. (m 은 SI Unit 이라 기준으로 설정한 듯 싶어요)
( 또한, 해당 properties 는 read-only computed property이고 간결하게 표현하기 위해 get 은 생략했음을 알 수 있습니다. )
2. Define instance methods and type methods
Extension 을 이용해서 Type에 Instance Method, Type Method 를 추가해줄 수 있습니다.
extension Int {
func repetitions(task: () -> Void) {
for _ in 0 ..< self {
task()
}
}
}
5.repetitions {
print("hi")
}
// print "hi" 5 times
또한, InstanceMethod 를 이용해서 self 를 바꿀 수도 있어요 !
Struct, Enum 의 경우 value type 이므로 해당 instance 자체를 바꾸고 싶을 때는 'mutating' 을 func 앞에 붙여야 한다는걸 기억하세요!
extension Int {
mutating func square() {
self = self * self
}
func square2() -> Int {
return self * self
}
}
var someInt = 3
someInt.square()
print(someInt) // print "9"
var someInt2 = 4
someInt2 = someInt2.square2()
print(someInt2) // print "16"
3. Provide new initializers
Extension 을 이용해서 Type 에 새로운 Initializer 를 부여할 수 있습니다. 기존 타입에 본인의 Custom Type 을 Parameter 로 받는 Initializer 를 추가하거나, 또는 Type 에 본인이 원하는 Initializer Option 을 추가해보세요 ~!
Class 에는 Extension 을 이용해서 Convenience Initializer 는 추가할 수 있지만 Deinitializer, Designated Initializer 는 추가할 수 없어요 .. (해당 Initializers 는 반드시 처음에 Class 에서 정의되어야합니다. )
Value Type 에 대해 Extension 을 이용하여 Initializer 를 추가할 때는,
1. 만약 해당 Type 내 Stored Properties 의 default value 가 전부 이미 주어져 있는 경우,
2. 그리고 Custom Initializer 가 존재하지 않는 경우
추가할 Initializer 에서 Type 의 Default Initializer 와 memberwise Initializer 를 내부에서 이용할 수 있어요.
Struct Point {
var x = 0.0, y = 0.0
}
Struct Size {
var width = 0.0, height = 0.0
}
Struct Rect {
var origin = Point()
var size = Size()
}
여기서 Rect Structure 는 모든 Properties 에 대해 Default Value 를 가지므로 Default Initializer 와 Memberwise Initialier 를 갖게됩니다.
let defaultRect = Rect()
let memberwiseRect = Rect(origin: Point(x: 2.0, y: 2.0),
size: Size(width: 5.0, height: 5.0))
extension Rect {
init(center: Point, size: Size) {
let originX = center.x - size.width / 2
let originY = center.y - size.height / 2
self.init(origin: Point(x: originX, y: originY), size: size)
}
}
let centerRect = Rect(center: Point(x: 6, y: 6), size: Size(width: 10, height: 10))
print("\(centerRect.origin)") // Point(x: 1.0, y: 1.0)
위에서, Default Initializer init(origin: size) 를 이용해 Rect Structure 의 Initializer init(center: size:) 를 만든 것을 볼 수 있어요.
잘 모르는 부분: Convenience Initializer, Designated Initializer.
4. Define subscripts
Extension 을 이용해서 새로운 subscripts 를 더해줄 수 있어요 !
extension Int {
subscript(digitIndex: Int) -> Int {
var decimalBase = 1
for _ in 0..<digitIndex {
decimalBase *= 10
}
return (self / decimalBase) % 10
}
}
746381295[0]
// returns 5
746381295[1]
// returns 9
746381295[2]
// returns 2
746381295[8]
// returns 7
5. Define and use new nested types
Extension 을 이용해서 Enumeration, Structure, Class 에 Nested Type 을 만들어 줄 수 있어요.
Extension Int {
enum Kind {
case positive, zero, negative
}
var kind: Kind {
switch self {
case 0: return .zero
case let x where x > 0 : return .positive
default: return .negative
}
}
}
print(3.kind) // print positive
func printIntegerKinds(_ numbers: [Int]) {
for number in numbers {
switch number.kind {
case .negative:
print("- ", terminator: "")
case .zero:
print("0 ", terminator: "")
case .positive:
print("+ ", terminator: "")
}
}
print("")
}
printIntegerKinds([3, 19, -27, 0, -6, 0, 7])
// Prints "+ + - 0 - 0 + "
print(, terminator: "") : 보통 print 의 마지막 출력은 \n. 즉, 한줄 띄기 이지만,
terminator 를 설정해주면 \n 대신 다른 값을 끝에 넣어줍니다.
6. Make an existing type conform to a protocol
다음 Protocol Chapter 에서 함께 다루겠습니다~
출처: https://docs.swift.org/swift-book/LanguageGuide/Extensions.html