ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Swift Language ) Extensions
    Swift/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
Designed by Tistory.