Swift)확장(extension)

윤여송·2023년 5월 24일
0

Swift

목록 보기
11/28

1. 확장(extension)이란?

기존 클래스, 구조체, 열거형 타입에 새로운 Property, Method, Initializer 등을 추가하는 것으로, 원본 타입(소스코드)에 접근하지 못하는 타입들도 확장해서 사용할 수 있다.
extension이란 키워드를 사용하여 확장한다.

extension SomeType{
}
extension SomeType: SomeProtocol, AnotherProtocol{
}

이렇게 extension을 쓰고 확장하고자 하는 타입을 쓴다! 그리고 그 뒤에 추가로 채택하고자 하는 Protocol을 추가 할 수도 있다.

let point: CGPoint = .init(x: 10, y: 20)

위 코드에서 point란 변수를 print로 출력하고 싶다고 가정해보자. CGPoint란 구조체는 값을 출력해주는 기능(함수)가 없다. 따라서 출력을 하고싶을 때마다 직접 print함수를 구현해야 한다. 만약 CGPoint가 출력해주는 함수를 자체적으로 가지고 있다면 정말 편리할 것이다. 그러나 CGPoint는 이미 프레임워크단에서 지원해주는 미리 정의된 구조체라서, 어떻게 원본코드를 건드릴 방법이 없다. 이럴 때 사용하는 것이 바로 extension이다! 원본은 코드를 그대로 두고, 내가 원하는 기능만 해당 타입에 확장하는 것이다.

extension CGPoint{
	func printPoint(){
    	print("x: \(self.x), y:\(self.y)")
    }
}

이렇게 extension을 쓰고 그 뒤에 확장할 타입의 이름을 쓴다. 그리고 그 안에 원하는 printPoint라는 메서드를 구현하면 CGPoint함수에 원래 printPoint가 있었던거 마냥 사용할 수 있다.
원본을 건드리지는 않았지만 CGPoint를 선언하는 모든 인스턴스는 CGPoint+extension으로 구현된다.

2.확장에 프로퍼티 추가하기

저장 프로퍼티는 추가할 수 없으며, 오로지 "연산프로퍼티"만 추가 가능하다.

extension Int{
	var half: Int{
    	return self/2
    }
}
let num = 100
print(num.half) //50

3.확장에 메서드 추가하기

인스턴스 메서드, 타입 메서드 모두 추가 가능하다.

//타입 메서드
extension Int{
	static func printZero(){
    	print(0)
    }
}
Int.printZero() //0
//인스턴스 메서드
extension Int{
	func printDouble(){
    	print(self*2)
    }
}
let num = 100
num.printDouble() //200

4.확장에 생성자(Initializer) 추가하기

기존 타입에 새로운 이니셜라이저를 추가할 수 있다.

4-1.Class에서의 생성자 추가

Designated initializer는 추가할 수 없고 Convenience initializer만 추가할 수 있으며, deinitializer를 추가할 수 없다.

4-2.Struct에서 생성자 추가

extension 으로 생성자를 추가할 경우, Memberwise Initializer를 보존하며 새로운 생성자를 추가할 수 있다. 구조체는 클래스와 달리 기본생성자(memberwise Initializer)를 자동으로 제공한다.

struct PointStruct{
	let x: Int
    let y: Int
    
    init(value: Int){
    	self.x = value
        self.y = value
    }
}

이렇게 생성자를 직접 구현하게되면 기본생성자는 더이상 제공되지 않는다. 하지만 extension을 사용하면 기본생성자를 보존하면서 새로운 생성자를 추가할 수 있다.

5.확장에 서브 스크립트(Subscript) 추가하기

extension String{
	subscript(idx: Int) -> String?{
    	guard (0..<count).contains(idx) else{
        	reuturn nil
        }
        let target = index(startIndex, offsetBy: idx)
        return String(self[target])
    }
}

6.확장에 중첩 타입 추가하기

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 타입의 extension 안에 Kind라는 enum을 중첩해서 선언할 수 있고,

let num = 100
print(num.kind) //positive
let num2 = -100
print(num2.kind)//negative

7.확장에 프로토콜 추가하기

struct Human{
	let name: String
}
let sodeul: Human = .init(name: "sodeul")
let sodeulsodeul = sodeul

sodeu == sodeulsodeul //error 발생

== 연산자를 사용하기 위해서는 Equatable이란 프로토콜을 채택하고 있어야 한다.

struct Human{
	let name: String
}
extension Human: Equatable{
	public static func == (lhs: Human, rhs: Human) -> Bool {
    	return lhs.name == rhs.name
    }
}

extension을 이용하여 해당 프로토콜에 맞는 메서드만 구현하는 것이 유지보수나 가독성면에서 좋다.

profile
y_some__velog

0개의 댓글