19. 확장(Extension)

🌈 devleeky16498·2022년 4월 20일
0

확장(Extension)은 확장한 클래스와 구조체, 열거형 또는 프로토콜 타입에 새로운 기능을 추가할 수 있다. 스위프트에서 확장은 다음의 기능들을 수행할 수 있다.

  • 계산된 인스턴스 프로퍼티와 계산된 타입 프로퍼티 추가
  • 인스턴스 메서드와 타입 메서드 정의
  • 새로운 초기화 구문 제공
  • 서브 스크립트 정의
  • 새로운 중첩된 타입의 정의와 사용
  • 기존의 타입이 프로토콜을 준수하도록 조치

사실상 확장을 통해서 프로퍼티로부터 메서드까지 다양한 기능들을 거의 제한없이 추가 할 수 있다는 것이다.

확장 구문(Extension Syntax)

  1. 확장은 extension 키워드를 통해서 사용 가능하다.
extension SomeType {
	//새로운 확장 기능과 프로퍼티를 입력
}

//확장은 하나 이상의 프로토콜을 채택해서 기존 타입 확장이 가능하다. 

extension SomeType : SomeProtocol, AnotherProtocol {
	//프로토콜 확장 기능을 추가
    //위처럼 입력 시 해당 확장은 기존의 클래사느 구조체에 대해서 프로토콜 준수를 추가할 수 있다.
}
  1. 기존 타입에 새로운 기능을 추가하기 위해 확장을 정의하면 새로운 기능은 확장의 정의되기전 생성되었어도 모든 기존의 인스턴스에서 사용이 가능하다. 따라서 추후 익스텐션을 한다고 하여 기존 인스턴스에서는 사용을 못하는 것이 아니다.

계산된 프로퍼티 확장

  1. 확장은 기존 타입에 계산된 인스턴스 프로퍼티와 계산된 타입 프로퍼티 추가가 가능하다.
extension Double {
	var km: Double {
    	return self * 1_000.0
    }
    //읽기 전용 프로퍼티이므로 별도의 get키워드 없이 다음과 같이 약식으로 표현 가능하다.
	var m: Double {
    	return self
    }
}

let aMeter = 25.4.m
print("This is \(aMeter)")
//Double뒤에 .을 찍어서 해당 프로퍼티에 접근을 하고 이를 출력해주었다.
  1. 확장은 새로운 계산된 프로퍼티를 추가할 수 있으나, 저장된 프로퍼티는 기존의 프로퍼티에 관찰자를 추가할 순 없다.

초기화 구문 확장

  1. 확장은 기존 타입에 새로운 초기화 구문을 추가할 수 있다. 확장은 클래스에 새로운 편의 초기화 구문 추가가 가능하지만, 새로운 지정된 초기화 구문이나 초기화 해제 구문은 클래스에 추가가 불가하다. 이는 반드시 기존 클래스에서 구현되어야 한다.
  2. 모든 저장된 프로퍼티에 기본 값을 제공하고 사용자 정의 초기화 구문을 정의하지 않은 값 타입으로 초기화 구문을 추가하기 위해서 확장을 사용한다면 확장 초기화 구문 내에서 값 타입에 대해 기본 초기화 구문과 멤버별 초기화 구문을 호출 가능하다.
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()
}

//다음과 같이 사각형을 나타내게 위한 두개의 구조체를 정의한 후 이를 값으로 갖는 Rect 구조체를 정의한 상태이다.

let defaultRect = Rect()
let memberwiseRect = Rect(origin : Point(x : 2.0, y : 2.0), size : Size(width : 5.0, height : 5.0))
//다음과 같이 구조체에 대한 값을 지정하고 인스턴스를 생성해준다.
//특정 중심점과 크기를 가지는 초기화 구문을 제공하기 위해서 Rect 확장이 가능하다.

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)
    }
}
//이 새로운 초기화 구문은 제공된 center와 size값을 기반으로 적절한 원점을 계산하며 시작한다. 

let centerRect = Rect(center : Point(x : 4.0, y : 4.0), size : Size(width : 3.0, height : 3.0))
//다음과 같이 초기화 구문을 통해서 새로운 지정값을 생성할 수 있다.
  1. 확장으로 새로운 초기화 구문을 제공하면 초기화 구문이 완료 될 시 각 인스턴스가 완전히 초기화 되는지 반드시 확인해야 한다.

메서드 확장

  1. 확장은 기존 타입에 새로운 인스턴스 메서드와 타입 메서드 추가가 가능하다.
extension Int {
	func repetition(task : () -> Void) {
    	for _ in 0..<self {
        	task()
        }
    }
}
//repetition(task:)메서드는 파라미터가 없고 반환값이 없는 함수타입의 인자를 가지며,
//확장 정의 후 여러번 작업 수행을 위해 모든 정수로 해당 메서드 호출이 가능하다.

3.repetition {
	print("Hello")
}
//Hello를 3회 출력한다.
  1. 확장에서 추가된 인스턴스 메서드는 인스턴스 자체로 수정 또는 변경 가능하다. self 또는 프로퍼티를 수정하는 구조체와 열거형 메서드는 기존 구현의 변경 메서드와 같이 mutating으로 표시한다.
extension Int {
	mutating func square() {
    	self = self * self
    }
}

var someInt = 3
someInt.square()
//someInt = 9이다.

서브 스크립트 확장

  1. 확장은 기존 타입에 새로운 서브 스크립트 추가가 가능하다. 아래 예시 코드에서는 서브 스크립트 [n]은 숫자의 오른쪽부터 n번째 위치하는 숫자를 반환한다. 예를 들어 123456789[0]은 9를 반환하게 된다.
extension Int {
	subscript(digitIndex : Int) -> Int {
    	var decimalBase = 1
        for _ in 0 ..< digitIndex {
        	decimalBase *= 10
        }
        return (self/decimalBase) % 10
    }
}

7412412[0]
//2를 리턴한다.

중첩된 타입의 확장

  1. 확장은 기존 클래스, 구조체, 열거형에 새로운 중첩된 타입을 추가 가능하다.
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에 중첩된 새로운 열거형을 추가한다.
//또한 해당 열거형 값에 대해 계산된 프로퍼티를 제공하는 새로운 프로퍼티를 추가 가능하다.

func printIntegerKinds(_ numbers : [Int]) {
	for number in numbers {
    	switch number.kind {
        case .negative:
        	print("-")
        case .zero:
        	print("0")
        case .positive:
        	print("+"
        }
    }
}
//다음과 같이 확장된 중첩된 타입을 활용가능해진다.
profile
Welcome to Growing iOS developer's Blog! Enjoy!🔥

0개의 댓글