* 내가 읽으려고 내 맘대로 번역한 글.
* 원문 : https://docs.swift.org/swift-book/LanguageGuide/Extensions.html

 

 

 

Extensions

Extensions add new functionality to an existing class, structure, enumeration, or protocol type. This includes the ability to extend types for which you do not have access to the original source code (known as retroactive modeling). Extensions are similar to categories in Objective-C. (Unlike Objective-C categories, Swift extensions do not have names.)

Extensions in Swift can:

확장은 기존 클래스, 구조체, 열거형, 프로토콜 타입에 새로운 기능을 추가한다.

원본 소스코드에 접근할수 없는 타입에 대해서도 확장할수 있는 기능도 포함된다 (소급적 모델링).

확장은 objective-c 에서 카테고리와 비슷하다 (objective-c 카테고리와 다른점은, swift 확장은 이름을 가지지 않는다)

 

  • 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
  • 계산 인스턴스 속성과 계산 타입 속성을 추가한다.
  • 인스턴스 메소드와 타입 메소드를 정의한다.
  • 새로운 초기화를 제공한다.
  • 첨자를 정의한다.
  • 새로운 중첩 타입을 정의하고 사용한다.
  • 기존 타입이 프로토콜을 준수하도록 만든다.

 

In Swift, you can even extend a protocol to provide implementations of its requirements or add additional functionality that conforming types can take advantage of. For more details, see Protocol Extensions.

swift 에서, 프로토콜을 확장해서 요구사항의 구현을 제공할수 있고, 추가 기능을 제공해서 적합한 유형을 활용할수 있다.

 

NOTE

Extensions can add new functionality to a type, but they cannot override existing functionality.

확장은 새로운 기능을 타입에 추가할수 있지만, 기존의 기능을 엎어쓸수는 없다.

 

Extension Syntax

Declare extensions with the extension keyword:

extension 키워로 확장을 선언한다.

extension SomeType {
	// new functionality to add to SomeType goes here
}

 

An extension can extend an existing type to make it adopt one or more protocols. To add protocol conformance, you write the protocol names the same way as you write them for a class or structure:

확장은 기존 타입에 하나 이상의 프로토콜을 채택하여 확장할수 있다.

프로토콜 준수를 추가하려면, 클래스나 구조체에서 작성하듯이 프로토콜 이름을 써라.

 

extension SomeType: SomeProtocol, AnotherProtocol {
	// implementation of protocol requirements goes here
}

 

Adding protocol conformance in this way is described in Adding Protocol Conformance with an Extension.

An extension can be used to extend an existing generic type, as described in Extending a Generic Type. You can also extend a generic type to conditionally add functionality, as described in Extensions with a Generic Where Clause.

 

NOTE

If you define an extension to add new functionality to an existing type, the new functionality will be available on all existing instances of that type, even if they were created before the extension was defined.

기존의 타입에 새로운 기능을 추가하기 위해 확장을 정의한다면,

새로운 기능은 존재하는 그 타입의 모든 인스턴에서 사용가능해진다, 심지어 확장이 정의되기 전에 생성된 인스턴스라도.

 

Computed Properties

Extensions can add computed instance properties and computed type properties to existing types. This example adds five computed instance properties to Swift’s built-in Double type, to provide basic support for working with distance units:

확장은 기존의 타입에 계산 인스턴스 속성과 계산 타입 속성을 추가할수 있다.

이 예제는 다섯개의 계산 인스턴스 속성을 swift 의 내장된 Double 타입에 추가하여, 거리 단위로 동작하도록 지원한다.

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
print("One inch is \(oneInch) meters")
// Prints "One inch is 0.0254 meters"
let threeFeet = 3.ft
print("Three feet is \(threeFeet) meters")
// Prints "Three feet is 0.914399970739201 meters"

 

These computed properties express that a Double value should be considered as a certain unit of length. Although they are implemented as computed properties, the names of these properties can be appended to a floating-point literal value with dot syntax, as a way to use that literal value to perform distance conversions.

이 계산 속성들은 Double 값이 특정 길이 단위로 간주될수 있도록 표현한다.

이것들이 계산 속성으로 구현되었더라도, 이 속성들의 이름은 점(.) 문법을 사용하여 부동소숫점 값에 붙을수 있어서,

그 값이 거리로 변환되는 동작을 사용할수 있다.

 

In this example, a Double value of 1.0 is considered to represent “one meter”. This is why the m computed property returns self—the expression 1.m is considered to calculate a Double value of 1.0.

이 예제에서, Double 값 1.0은 1미터로 간주되어 표현된다.

m 계산 속성은 자신을 리턴하기 때문에, 1.m 표현식은 Double 값 1.0 으로 계산되는걸로 간주한다.

 

Other units require some conversion to be expressed as a value measured in meters. One kilometer is the same as 1,000 meters, so the km computed property multiplies the value by 1_000.00 to convert into a number expressed in meters. Similarly, there are 3.28084 feet in a meter, and so the ft computed property divides the underlying Double value by 3.28084, to convert it from feet to meters.

다른 단위들은 미터 단위로 측정된 값을 표현하기 위해 약간의 변환이 요구된다.

1킬로미터는 1,000미터와 동일하니까, km 계산 속성은 미터법으로 숫자를 표현하려고 값에 1_000.00 을 곱한다.

비슷하게, 1미터는 3.28084 feet고, ft 계산 속성은 Double 값을 3.28084 로 나누어,

feet 에서 미터로 변환한다.

 

These properties are read-only computed properties, and so they are expressed without the get keyword, for brevity. Their return value is of type Double, and can be used within mathematical calculations wherever a Double is accepted:

이 속성들은 읽기전용 계산 속성이고, 간결하게 get 키워드 없이 표현되었다.

그 리턴값들은 Double 타입이고, Double 을 받아들이는 모든 수학 계산에서 사용할수 있다.

let aMarathon = 42.km + 195.m
print("A marathon is \(aMarathon) meters long")
// Prints "A marathon is 42195.0 meters long"

 

NOTE

Extensions can add new computed properties, but they cannot add stored properties, or add property observers to existing properties.

확장은 새로운 계산 속성을 추가할수 있지만, 저장 속성을 추가할수 없고, 기존 속성들에 속성 옵져버를 추가할수 없다.

 

Initializers

Extensions can add new initializers to existing types. This enables you to extend other types to accept your own custom types as initializer parameters, or to provide additional initialization options that were not included as part of the type’s original implementation.

확장은 기존 타입에 새로운 초기화를 추가할수 있다.

이것은 다른 타입을 확장하여 초기화 파라메터로 너의 커스텀 타입을 받아들이도록 할수 있고,

타입의 원래 구현에 없는 추가적인 초기화를 제공할수 있게 해준다.

 

Extensions can add new convenience initializers to a class, but they cannot add new designated initializers or deinitializers to a class. Designated initializers and deinitializers must always be provided by the original class implementation.

확장은 새로운 convenience 초기화를 추가할수 있지만, 새로운 designated 초기화 또는 해제자를 추가할수 없다.

designated 초기화와 해제자는 반드시 원래 클래스 구현에 제공되어야 한다.

 

If you use an extension to add an initializer to a value type that provides default values for all of its stored properties and does not define any custom initializers, you can call the default initializer and memberwise initializer for that value type from within your extension’s initializer. This wouldn’t be the case if you had written the initializer as part of the value type’s original implementation, as described in Initializer Delegation for Value Types.

너가 모든 저장 속성에 기본값이 있고 커스텀 초기화가 없는 값타입에 초기화를 추가하려고 확장을 사용하면,

확장의 초기화에서 그 값타입에 대한 기본 초기화와 memberwise 초기화를 호출할수 있다.

값타입의 원래 구현에 작성된 초기화에는 해당되지 않는다.

 

If you use an extension to add an initializer to a structure that was declared in another module, the new initializer can’t access self until it calls an initializer from the defining module.

다른 모듈에 선언된 구조체에 초기화를 추가하려고 확장을 사용한다면,

새로운 초기화는 정의한 모듈에서 초기화를 호출하기 전까지 self에 접근할수 없다.

 

The example below defines a custom Rect structure to represent a geometric rectangle. The example also defines two supporting structures called Size and Point, both of which provide default values of 0.0 for all of their properties:

아래 예제는 Rect 구조체를 정의하여 기하학적 사각형을 표현한다.

또한 Size 와 Point 라는 2개의 구조체를 정의하였고, 둘다 자신의 속성들에 기본값 0.0을 가진다.

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()
}

 

Because the Rect structure provides default values for all of its properties, it receives a default initializer and a memberwise initializer automatically, as described in Default Initializers. These initializers can be used to create new Rect instances:

Rect 구조체는 모든 속성에 기본값을 제공하므로, 기본 초기화와 memberwise 초기화를 자동적으로 가지게 된다.

이 초기화들은 새로운 Rect 인스턴스를 만들때 사용된다.

let defaultRect = Rect()
let memberwiseRect = Rect(origin: Point(x: 2.0, y: 2.0),
size: Size(width: 5.0, height: 5.0))

 

You can extend the Rect structure to provide an additional initializer that takes a specific center point and size:

특정 중심점과 크기를 받은 추가적인 초기화를 제공하기 위해서 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)
	}
}

 

This new initializer starts by calculating an appropriate origin point based on the provided center point and size value. The initializer then calls the structure’s automatic memberwise initializer init(origin:size:), which stores the new origin and size values in the appropriate properties:

새로운 초기화는 제공받은 중심점과 크기 값을 기반으로 적절한 origin point 를 계산하는걸로 시작한다.

그 초기화는 구조체의 자동 memberwise 초기화 init(origin:size:) 를 호출하여, origin 과 size 속성에 적절한 값을 저장한다.

let centerRect = Rect(center: Point(x: 4.0, y: 4.0),
size: Size(width: 3.0, height: 3.0))
// centerRect's origin is (2.5, 2.5) and its size is (3.0, 3.0)

 

NOTE

If you provide a new initializer with an extension, you are still responsible for making sure that each instance is fully initialized once the initializer completes.

확장을 통하여 새로운 초기화를 제공하면, 초기화가 완료되었을때 각 인스턴스가 완전히 초기화 되는지를 확인해야 한다.

 

Methods

Extensions can add new instance methods and type methods to existing types. The following example adds a new instance method called repetitions to the Int type:

확장은 기존의 타입에 새로운 인스턴스 메소드와 타입 메소드를 추가할수 있다.

다음 예제는 Int 타입에 repetitions 라는 새로운 인스턴스 메소드를 추가한다.

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

 

The repetitions(task:) method takes a single argument of type () -> Void, which indicates a function that has no parameters and does not return a value.

After defining this extension, you can call the repetitions(task:) method on any integer to perform a task that many number of times:

repetitions(task:) 메소드는 type () -> Void 형식(파라메터가 없고, 리턴값도 없는) 의 하나의 매개변수를 받는다.

이 확장을 정의한후, task 를 여러번 실행하기 위하여 모든 정수에서 repetitions(task:) 메소드를 호출할수 있다.

3.repetitions {
	print("Hello!")
}
// Hello!
// Hello!
// Hello!

 

Mutating Instance Methods

Instance methods added with an extension can also modify (or mutate) the instance itself. Structure and enumeration methods that modify self or its properties must mark the instance method as mutating, just like mutating methods from an original implementation.

The example below adds a new mutating method called square to Swift’s Int type, which squares the original value:

확장을 통해 추가된 인스턴스 메소드 역시 인스턴스 자체를 수정할수 있다.

자신 또는 자신의 속성을 수정하는 구조체와 열거형 메소드는 반드시 mutating 를 붙여야한다.

원래 구현의 mutating 메소드 처럼.

* 이석우 추가. mutating 이 기억이 안나서 다시 찾아서 여기에 간략히 적음.

클래스는 reference 타입이고, 구조체와 열거형은 value 타입이다.

reference 타입의 인스턴스는 메소드 안에서 자신의 속성값을 바꿀수 있다.

value 타입의 인스턴스는 메소드안에서 자신의 속성값을 바꾸려면, 메소드 앞에 mutating 을 붙여야만 한다.

이때 mutating 메소드를 통해서 값을 바꾸면, 새로운 객체가 생성된다 (그래서 let 쓰면 안되고, var 를 써야 함)

extension Int {
	mutating func square() {
		self = self * self
	}
}
var someInt = 3
someInt.square()
// someInt is now 9

 

Subscripts

Extensions can add new subscripts to an existing type. This example adds an integer subscript to Swift’s built-in Int type. This subscript [n] returns the decimal digit n places in from the right of the number:

확장은 기존 타입에 새로운 첨자를 추가할수 있다.

이 예제는 swift의 기본 Int 타입에 정수 첨자를 추가한다.

이 첨자[n] 은 숫자의 오른쪽으로 부터 n 번째에 위치한 십진수를 리턴한다.

  • 123456789[0] returns 9
  • 123456789[1] returns 8

 

…and so on:

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

 

If the Int value does not have enough digits for the requested index, the subscript implementation returns 0, as if the number had been padded with zeros to the left:

만약 Int 값이 요청된 index보다 큰 자리숫를 가지고 있지 않으면, 첨자는 왼쪽에 0으로 채워진 것처럼 0을 리턴하게 구현되었다.

746381295[9]
// returns 0, as if you had requested:
0746381295[9]

 

Nested Types

Extensions can add new nested types to existing classes, structures, and enumerations:

확장은 기존 클래스, 구조체, 열거형에 새로운 충접 타입을 추가할수 있다.

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
		}
	}
}

 

This example adds a new nested enumeration to Int. This enumeration, called Kind, expresses the kind of number that a particular integer represents. Specifically, it expresses whether the number is negative, zero, or positive.

This example also adds a new computed instance property to Int, called kind, which returns the appropriate Kind enumeration case for that integer.

이 예제는 새로운 충접 열거형을 Int 에 추가한다. Kind 라는 이 열거형은 특정 숫자가 나타내는 종류를 표현한다.

이것은 숫자가 음수, 영, 양수 인지 표현한다.

이 예제는 또한 kind 라는 새로운 계산 인스턴스 속성을 Int 에 추가하여, 숫자에 대한 적절한 Kind 열거형을 리턴한다.

 

The nested enumeration can now be used with any Int value:

이 중첩 열거형은 모든 Int 값에 사용될수 있다.

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 + "

 

This function, printIntegerKinds(_:), takes an input array of Int values and iterates over those values in turn. For each integer in the array, the function considers the kind computed property for that integer, and prints an appropriate description.

printIntegerKinds(_:) 함수는 Int 값들의 배열을 입력으로 받고, 그 값들을 차례로 반복한다.

배열의 각 숫자에 대해, 함수는 그 숫자에 대한 kind 계산 속성을 고려하고, 적절한 설명을 출력한다.

 

NOTE

number.kind is already known to be of type Int.Kind. Because of this, all of the Int.Kind case values can be written in shorthand form inside the switch statement, such as .negative rather than Int.Kind.negative.

number.kind 는 이미 Int.Kind 타입으로 알려져있다.

그렇기 때문에, 모든 Int.Kind 케이스 값은 switch 구문 안에서 짧은 형태로 쓰여질수 있다.

Int.Kind.negative 가 아닌 .negative 처럼.

반응형
Posted by 돌비
,