-
Swift Language ) ExtensionsSwift/Swift Language 2021. 9. 14. 12:06
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
'Swift > Swift Language' 카테고리의 다른 글
Swift Language ) Closure (0) 2021.10.06 Swift Language) ARC ( Automatic Reference Counting) (0) 2021.10.04 Swift Language ) Generics (0) 2021.09.23 Swift Language ) Access Control (0) 2021.09.16 Swift Language ) Protocol (0) 2021.09.16