momodudu.zip

#6 Swift - Extension 본문

ios/Swift

#6 Swift - Extension

ally10 2019. 11. 28. 10:59

Swift에서는 기존에 존재하던 Class, Struct, Enum type등에 대해 추가적인 기능을 덧붙여서 사용할 수 있다.

예를 들어, Numeric structure type인 Int에 추가적인 커스터마이징을 할 수 있다. 이를 Extension 이라고 한다.

 

추가할수 있는 것에 대해는 종류가 있는데,

- Computed instance property / Computed type property

- Instance method / Type method

- new initializer

- subscript define

- 새로운 nested type 정의

- 기존에 있던 type을 특정 프로토콜을 준수하도록 정의

 

protocol에 대해서는 아직 설명하지 않았으므로, 나머지에 대해서 정리해보고자 한다.

 

1. Extension syntax

class SomeClass{
    
}

extension SomeClass{
    
}

 

기존에 존재하던 SomeClass가 있다고 가정하면, SomeClass를 확장하는 syntax는 extension keyword를 붙이면 된다.

기본적으로 존재하던 타입 선언 -> 그 타입에 대한 extension, 즉 타입 선언을 먼저하고 확장을 하더라도

이전에 쓰던 타입들에 대해서도 확장된대로 사용이 가능하다.

 

2. Extension for Computed property

extension Double{
    var m : Double{
        return self
    }
    
    var km : Double{
        return self*1_000.0
    }
}

기존에 존재하는 타입인 Double의 Extension을 위와 같이 정의했다.

computed property로 var m을 self로 리턴하고, var km로 self에 1000을 곱해서 리턴하도록 정의했다.

 

var distance = 400.0.m + 1.0.km
print(distance)

extension으로 위와 같은 출력이 가능하다. 400,0 Double의 computed property인 m을 호출하면 400.0이 그대로 리턴되고

1.0의 computed property인 km를 호출하면 self 1.0에 1000을 곱해서 리턴된다.

 

주의할점은 extension에서는 stored property나 기존에 존재하던 property observer는 추가할 수 없다.

 

3. Initializer

initializer는 추가할 수 있으나, extension 대상 타입의 designated initializer나 deinitializer는 추가할 수 없다.

designated initializer와 deinit은 class당 하나만 존재해야한다.

struct Size{
    var width = 0.0, height = 0.0
}

struct Point{
    var x = 0.0, y = 0.0
}

struct Rect{
    var origin = Point()
    var size = Size()
}

 

Size, Point를 property 로 갖는 Rect가 선언되어 있고, default initializer로 designated initializer 는 이미 구현되어 있다.

extension Rect{
    init(origin: Point, size: Size){
        // Compile error
        // Invalid redeclaration of 'init(origin:size:)'
    }
    
    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 )
    }
}

 

위와 같이 두개의 init을 정의했는데, 첫번째 init은 designated init 형식으로, 위와 같이 extension하려고 하면

redeclaration compile error를 띄운다.

 

그래서 두번째 init처럼 다른 init으로 정의해주어야 한다.

주의할점은 추가한 Init에서도 designated init을 호출하거나 해서 fully initialize를 해주어야 한다.

 

 

4. Method

기존에 존재하던 타입에 method를 추가할 수도 있다.

 

extension Int{
    func repetitions(task: ()->Void){
        for _ in 0..<self {
            task()
        }
    }
}

 

Int에 repetitions 이라는 method 를 추가했다. 특정 clousre를 인자로 전달받아서

self, 즉 지정된 숫자 만큼 반복하는 method 이다.

 

3.repetitions {
    print("Hello")
}

 

3 은 int형 이므로 위와 같이 확장된 Method 를 사용할 수 있고, 출력시 Hello가 3번 출력된다.

또한 Int 는 sturct로 구현되어 있는데, 이 self property를 변경하고 싶은 경우 mutating keyword를 사용한 method로 변경가능하다.

 

 

5. Subscript

배열 access시 사용하는 [] subscript또한 Extension 이 가능하다.

 

extension Int{
    subscript(index: Int) -> Int {
        var decimalBase = 1
        
        for _ in 0..<index {
            decimalBase *= 10
        }
        
        return (self/decimalBase)%10
    }
}

 

Int 에 위와 같이 자릿수의 숫자를 리턴하는 subscript를 정의하면, 아래와 같이 사용할 수 있다.

print(12345[0])
// prints '5'

 

6. Nested Type

확장형으로 nested type을 넣을수도 있다.

 

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 struct에 nested type enum으로 Kind를 넣어주었다.

 

print(3.kind)
// print positive

위와 같이 kind를 출력하면 positive가 출력된다.

 

 

'ios > Swift' 카테고리의 다른 글

#8 Swift - Automatic Reference Counting  (0) 2019.12.28
#7 Swift - Protocol(1)  (0) 2019.11.28
#5 Swift - Optional chaining  (0) 2019.11.27
#4 Swift - Initialization  (0) 2019.11.26
#3 Swift - Properties  (0) 2019.11.26