Merge changes from master into Snowcat8436

Snowcat8436 authored
revision ad6823dc66f38aa5ffe6ddbc766fef0032017f9f
chapter11
# 11 클래스와 구조체 (Classes and Structures)
> Translator : 이름 (메일주소문대선(daeseonmoon@gmail.com)

클래스와 구조체는 프로그램의 코드블럭을 정의할때 사용됩니다. 여러분은 프로퍼티를 정의할수 있고 기능을 추가하기 위해 상수, 변수 그리고 함수를 정의할때와 동일한 문법적 표기로 메소드를 정의하실 수도 있습니다.
다른 프로그래밍 언어와는 달리 스위프트는 사용자 클래스와 구조체를 위해서 헤더파일과 구현파일을 나누실 필요가 없습니다. 단일파일에 선언과 구현을 하며 다른 코드에서 사용하기 위한 그 클래스와 구조체의 외부 인터페이스는 자동적으로 생성됩니다.

>NOTE
>클래스의 인스턴스는 전통적으로 오브젝트라 표기하기도 합니다. 하지만 스위프트 클래스와 구조체는 다른 언어보다도 기능적인(functionality) 측면에 중점을 두고 이 챕터에서도 클래스나 구조체의 인스턴스에 적용가능한 기능적인 면을 설명할것이기 때문에 더 일반적인 인스턴스라는 용어를 사용할것입니다(#이게 먼말이여 리뷰좀 해주세요).

## 클래스와 구조체의 비교
스위프트에서 클래스와 구조체는 여러 공통점을 가지고 있습니다. 공통점으로는
* 프로퍼티를 정의하고 값을 할당할수 있습니다.
* 메소드를 정의하고 메소드의 기능(역할)을 정의할수 있습니다.
* 접근자 문법을 통해서 할당된 값에 사용할수 있는 접근자를 정의할수 있습니다.
* 초기화를 위해 생성자초기자(Initializer)를 정의할수 있습니다.
* 기본 구현에 확장가능(상속)
* 특정 종류의 표즌 기능을 제공하는 프로토콜을 준수할수 있습니다.

더 많은 정보를 원하신다면 Properties, Methods, Subscripts, Initialization, Extensions 그리고 Protocols 항목을 참조하십시오.

클래스는 구조체를 통해서는 할수없는 아래와 같은 추가적인 기능들을 지원합니다.
* 상속은 다른 클래스의 특성을 상속받는 클래스의 생성을 가능케합니다.
* 형변환은 여러분이 런타임시에 클래스의 형을 확인하고 변환을 가능케합니다.
* 소멸자해제(Deinitializer)는 클래스 인스턴스에 할당된 자원을 환원 가능케합니다.
* 참조카운팅은 하나의 클래스 인스턴스에 하나 이상의 참조를 가능케합니다.

더 많은 정보를 원하신다면 Inheritance, Type Casting, Initialization 그리고 Automatic Reference Counting 항목을 참조하십시오.

>NOTE
>여러분의 코드에서 구조체는 언제나 복사가 될뿐 참조카운팅을 사용하지 않습니다.

## 정의문법
클래스와 구조체는 유사한 문법적 구조를 가지고 있습니다. 클래스는 `class` 키워드를 구조체는 `struct` 키워드를 사용합니다. 둘다 그들의 정의를 중괄호({})내에 위치시킵니다.
```
class SomeClass {
// 이곳에 클래스를 정의하십시오
}

struct SomeStructure {
// 이곳에 구조체를 정의하십시오
}
```
>NOTE
>새로운 클래스나 구조체를 정의할때 유용한 형이름을 주십시오. 일괄성을 스위프트 타입 표준인 UpperCamelCase를 사용하십시오(ex: SomeClass, SomeStruture).
>프로퍼티나 메소드를 정의할때는 형이름과 차별화를 주기위해 lowerCamelCase를 사용하십시오(ex: frameRate, incrementCount)

클래스와 구조체 정의문의 예:
```
struct Resolution {
var width = 0
var height = 0
}

class VideoMode {
var resolution = Resolution()
var interlaced = false
var frameRate = 0.0
var name: String?
}
```
위의 예제는 픽셀기반 해상도를 정의하기 위한 `Resolution`이란 새로운 구조체를 정의합니다. 이 구조체는 `width``height`라는 두개의 프로퍼티를 가지고 있습니다. 저장된 프로퍼티는 변수나 상수로서 이 클래스나 구조체의 속하며 구조체의 부분으로서 존재합니다.
이 두 프로퍼티는 정수값 0으로 초기화됨으로써 정수형입니다.

위의 예제는 또한 특정 비디오 모드를 정의하는 VideoMode라 불리는 클래스를 정의합니다. 이 클래스는 네개의 변수 저장 프로퍼티를 가지고 있습니다. 첫번째 변수인 resolution은 새로운 Resolution 구조체의 인스턴스로 초기화됩니다. 새로 생성되는 VideoMode 인스턴스는 interlaced변수는 false로 플레이 프레임 레이트는 0.0로, name은 옵션널(?) String으로 초기화합니다. name 프로퍼티는 옵셔널이기 때문에 자동적으로 기본값 nil이나 "no name value" 값을 가지게 됩니다.

## 클래스와 구조체 인스턴스
Resolution 구조체와 VideoMode 클래스는 Resolution또는 VideoMode가 어떻게 보일지를 정의할뿐 특정 해상도나 비디오모드를 정의하진 않습니다. 그렇게학 위해서 여러분은 이 구조체나 클래스의 인스턴스를 생성해야 합니다.
구조체나 클래스 인스턴스를 생성하기 위한 문법적 구조는 유사합니다.
```
let someResolution = Resolution()
let someVideoMode = VideoMode()
```
구조체와 클래스는 새 인스턴스를 생성하기위해 초기화 문법을 사용합니다. 가장 간단한 초기화 문법은 Resolution()이나 VideoMode()와 같이 클래스나 구조체의 형 이름에 괄호(())를 덧붙여주는것 입니다. 이 구문은 프로퍼티의 기본값을 는 새 인스턴스를 생성합니다. 자세한 클래스와 구조체의 초기화는 Initialization 항목을 참조하십시오.

## 프로퍼티 접근하기
dot(.) 문법을 사용해서 여러분은 인스턴스의 프로퍼티에 접근할수 있습니다. dot 문법은 인스턴스 이름 뒤에 공백문자 없이 dot(.)과 프로퍼티 네임을 적는것입니다.
```
println("The width of someResolution is \
(someResolution.width)")
// "The width of soneResolution is 0" 출력
```
이 예제에서 `someResolution.width`는 `someResolution`의 `width` 프로퍼티를 참조하고 기본 초기값 0를 반환합니다.
여러분은 섭(sub)프로퍼티를 통해 `VideoMode`에 속한 `resolution` 프로퍼티의 `width` 프로퍼티에도 접근할수 있습니다.
```
println("The width of someVideoMode is \
(someVideoMode.resolution.width)")
// "The width of someVideoMode is 0" 출력
```
dot 문법을 통해 변수 프로퍼티에 새로운 값을 할당하는것도 가능합니다.
```
someVideoMode.resolution.width = 1280
println("The width of someVideoMode is now \
(someVideoMode.resolution.width)")
// "The width of someVideoMode is now 1280" 출력
```
> NOTE
> Objective-C와는 달리 Swift는 구조체의 프로퍼티도 섭프로퍼티를 통해 직접적으로 설정할수 있습니다. 위의 마지막 예제에서 someVideoMode에 속한 resulotion 프로퍼티의 width 프로퍼티의 값을 resolution 프로퍼티를 새로설정할 필요없이 직접적으로 할당했습니다.

##구조체형의 멤버 초기화
모든 구조체는 여러분이 새로은 구조체 인스턴스의 멤버 프로퍼티들을 초기화 할수있는 자동 생성된 멤버초기자(*member initializer*)를 제공합니다. 새로운 구조체 프로퍼티의 기본 초기화 값은 각 변수의 이름으로 멤버초기자에 넘겨줄수 있습니다.
```
let vga = Resolution(width: 640, height: 480)
```
구조체완 달리 클래스 인스턴스의 경우에는 기본 멤버초기자를 받지 않습니다. 초기자의 자세한 사항은 `Initialization`을 참조해주십시오.

## 구조체와 열거형은 값형식
갑형식(*value type*)은 함수에 매개변수로 넘겨지거나 변수나 상수에 할당될때 값을 복사하는 형입니다.

사실 여러분은 지금까지 전 챕터에서 값형식을 광범위하게 사용했습니다. 사실 스위프트에서 기본 형- 정수, 실수, 불리언, 문자열, 배열과 딕셔너리-은 전부 값형식이고 구조체로 구현되어있습니다.

Swift에서 모든 구조체와 열거형은 값형식입니다. 즉 여러분이 생성하는 모든 구조체와 열거형 인스턴스들-그리고 그들에 속한 모든 값형식 프로퍼티-은 언제나 여러분의 코드내에서 그들이 함수의 인자로 전달되거나 새로운 변수나 상수에 할당될때 복사가 됩니다.

전 챕터에서 사용된 `Resolution` 구조체의 사용예를 한번보죠
```
let hd = Resolution(width: 1920, height: 1080)
var cinema = hd
```
이 예제는 `hd` 상수를 선언하고 full HD video(1920 픽셀 넓이에 1080 픽셀 높이)의 넓이와 높이로 초기화된 Resolution 인스턴스를 할당했습니다.

그리고 `cinema` 변수를 선언하고 `hd` 상수의 값을 할당했습니다. `Resolution`이 구조체이기 때문에 존재하는 인스턴스의 복사가 이루어지고 이 새로 복사된 값이 `cinema`에 할당됩니다. `hd`와 `cinema`가 현재 같은 넓이와 높이 값을 가지고 있지만 그들은 완전히 다른 인스턴스입니다.

다음의 코드를 통해 `cinema`의 `width` 프로퍼티에 디지털 시네마 프로젝션(2048 픽셀 넓이와 1080 픽셀 높이)의 넓이를 새로 할당하도록 하겠습니다.
```
cinema.width = 2048
```
`cinema` 인스턴스의 `width`를 출력해봄으로써 이 값이 2048로 변했음을 확인할수 있습니다.
```
println("cinema is now \(cinema.width) pixels wide")
// "cinema is now 2048 pixels wide" 출력
```
하지만 아래의 코드를 통해 `hd` 인스턴스에 속한 `width` 프로퍼티의 값은 여전히 1920임을 확인할수 있습니다.
```
println("hd is still \(hd.width) pixels wide")
// "hd is still 1920 pixels wide" 출력
```
`cinema`에 `hd` 인스턴스를 할당할때 `hd`에 저장되어있던 프로퍼티의 값들이 새로 생성된 `cinema` 인스턴스로 복사가 이루어졌음을 알수 있습니다. 결과를 보면 동일한 값을 가지고 있는 완전히 분리된 인스턴스임을 알수 있습니다.
두 인스턴스는 서로 다른 인스턴스이기 때문에 `cinema`의 `width`를 2048로 할당하더라도 `hd` 인스턴스에 저장되어있는 width 값에는 어떠한 영향도 미치지 않습니다.

열거형에도 동일한 법칙이 적용됩니다
```
enum CompassPoint {
case North, South, East, West
}
var currentDirection = CompassPoint.West
let rememberedDirection = currentDirection
currentDirection = .East
if rememberedDirection == .West {
println("The remembered direction is still .West")
}
// "The remembered direction is still .West" 출력
```
`rememberedDirection`에 `currentDirection`의 값이 할당될때 실제적으로는 값의 복사가 이루어집니다. 그러므로 `currentDirection`의 값이 변경된후에도 `rememberedDirection`에 복사되어서 저장된 원래 값에는 어떠한 영향도 미치지 않습니다.

## 클래스는 참조형식
값형식과는 달리 참조형식(*reference type*)은 함수에 인자로 전달되때나 상수나 변수에 할당될때 복사가 이루어지지 않습니다. 동일한 인스턴스의 레퍼런스(reference)가 복사대신 사용됩니다.

위에서 정의한 `VideoMode` 클래스의 사용을 통한 예제를 살펴보도록 하겠습니다.
```
let tenEighty = VideoMode()
tenEighty.resolution = hd
tenEighty.interlaced = true
tenEighty.name = "1080i"
tenEighty.frameRate = 25.0
```
이 예제에서 우리는 `tenEighty`라는 상수를 선언하고 새로 생성된 `VideoMode` 클래스의 인스턴스를 할당했습니다. 비디오 모드는 전에 설정했던 1920 x 1080의 HD 해상도의 복사된 값을 할당했습니다. 또한 interlaced를 설정하고 name에 "1080i"를 주었습니다. 그리고 마지막으로 프레임 레이트를 초당 25.0로 설정했습니다.

다음으로 `tenEighty`를 `alsoTenEighty'라는 새로운 상수에 할당하고 `alsoTenEighty`의 프레임 레이트의 값을 수정하겠습니다.
```
let alsoTenEighty = tenEighty
asloTenEighty.frameRate = 30.0
```
클래스는 참조형식이기때문에 `tenEighty`와 `alsoTenEighty`는 실제적으로 동일한 `VideoMode` 인스턴스를 참조하고 있습니다. 그들은 단지 동일한 인스턴스를 참조하는 서로 다른 이름일뿐입니다.

아래의 예제코드를 통해 `tenEighty`의 `framerate` 프로퍼티가 새로운 프레임 레이트 값인 30.0임을 확인할수 있습니다.
```
println("The frameRate property of tenEighty is now
\(tenEighty.frameRate)")
// "The frameRate property of tenEighty is now 30.0" 출력
```
`tenEighty`와 `alsoTenEighty`가 변수가 아니라 상수로 선언되었음을 주의깊게 보십시오. `tenEighty`와 `alsoTenEighty` 상수의 그자체는 실제적으로 바뀌지 않기때문에 여러분은 여전히 tenEighty.frameRate과 alsoTenEighty.frameRate의 값을 바꿀수 있습니다.
`tenEighty`와 `alsoTenEighty` 자체는 `VideoMode` 인스턴스를 "저장"하지 않고 `VideoMode` 인스턴스를 참조만 합니다. 바뀌는것은 참조되고 있는 `VideoMode`의 `frameRate`프로퍼티이지 `VideoMode`를 참조하고 있는 상수의 값은 변하지 않습니다.

## 식별연산자(Identity Operators)
클래스는 참조타입이기때문에 여러 상수나 변수가 동일한 클래스의 인스턴스를 참조하는게 가능합니다.(구조체와 열거형은 할당되거나 함수에 매개변수로 전달될때 복사가 이루어지기때문에 동일한 인스턴스의 참조는 불가능합니다.)

이러한 이유로 두 상수나 변수가 정확하게 동일한 클래스의 인스턴스를 참조하고 있는지 알아내는것은 종종 유용하게 사용됩니다. 그러한 경우를 알아내기 위해서 Swift는 아래의 두가지 식별연산자를 제공합니다
* 동일한(Identical to) (===)
* 동일하지 않은(Not identical to) (!==)

두 상수나 변수가 동일한 인스턴스를 가리키는지 검사하기 위해 위의 두 연산자를 사용하십시오.
```
if tenEighty === alsoTenEighty {
println("tenEighty and alsoTenEighty refer to the same Resolution instance.")
}
// "tenEighty and alsoTenEighty refer to the same Resolution instance." 출력
```
"동일한(identical to)"("==="로 표현된)과 "같은(equal to)"("=="로 표현된)가 같지 않다라것에 주의하십시오.
* "동일한"은 클래스 형의 두 상수나 변수가 정확하게 동일한 클래스 인스턴스를 참조하고 있음을 뜻합니다.
* "같은"은 두 인스턴스가 같은 값을 가지고 있는지를 검사합니다.

여러분이 사용자 클래스나 구조체를 정의할때 두 인스턴스가 "같은"조건을 결정하는것은 여러분의 결정입니다.
여러분만의 "같은"과 "같지않은(not equal to)"연사자를 구현하는 과정에 대한 자세한 사항은 `Equivalence Operators`를 참조하십시오.

## 포인터
만약 여러분이 C나 C++ 또는 Objective-C를 사용해본 경험이 있으시다면 이 언어들이 메모리주소를 참조하기 위해 포인터를 사용한다는 것을 아실겁니다. 어떤 참조형식 인스턴스를 참조하는 Swift 상수나 변수는 C에서의 포인터와 유사합니다. 하지만 이것은 메모리상의 주소를 직접적으로 가르키는 것은 아니고 또한 여러분이 생성한 인스턴스를 가르키기 위해 asterisk(*)를 필요로 하지도 않습니다. 대신 Swift에서는 이러한 레퍼런스들은 다른 상수나 변수처럼 정의할수 있습니다.

## 클래스와 구조체중에 선택하기
여러분 프로그램 코드의 특정 분리된 블록을 사용자 데이터 형으로 정의하기위해 여러분은 클래스나 구조체를 사용할수 있습니다.

하지만 구조체 인스턴스는 언제나 값을 전달하고 클래스 인스턴스는 참조변수를 전달합니다. 즉 이것은 이들이 서로 다른 종류의 작업에 적합하다는것을 뜻합니다. 여러분은 프로젝트에 필요한 데이터 집합이나 기능을 정의할때 그것들이 클래스로 정의되어야 할지 구조체로 정의되어야 할지 결정해야 한다는걸 생각하십시오.

일반적인 가이드로는 아래의 조건중에 한가지또는 그 이상일 경우에는 구조체를 생각하십시오.
* 구조체의 주목적이 몇몇 연관성있는 간단한 데이터 값의 캡슐화일 경우
* 캡술화된 값들이 그 구조체의 인스턴스가 할당될때나 전달될때 참조보다는 복사가 예상될 경우
* 구조체에 저장되는 모든 프로퍼티들이 참조보다는 복사가 예상되는 값형식일 경우
* 구조체가 다른 형(type)에서부터 프로퍼티나 기능이 상속될 필요가 없을 경우

구조체를 사용하는 좋은 예:
* `Double`형을 갖는 width와 height 프로퍼티의 캡슐화를 하는 기하학적 모형의 사이즈.
* `Int`형을 갖는 start와 length 프로퍼티의 캡슐화를 하는 시리즈의 범위에 접근하는 방법.
* `Double`형을 갖는 x,y와 z 프로퍼티의 캡슈화를 하는 3차원 좌표시스템의 포인터.

이외의 경우에는 클래스로 정의하고 레퍼런스로 전달되고 관리되는 클래스의 인스턴스를 생성하십시오. 실질적으로는 대부분의 사용자 데이터 형은 구조체가 아닌 클래스로 정의되어야 합니다.

## 컬렉션 형의 할당과 복사
Swift의 `Array`와 `Dictionary` 형은 구조체로 구현되어 있습니다. 하지만 배열의 경우에는 다른 구조체가 함수나 메소드에 전달될때나 상수나 변수에 할당될때와는 약간 다르게 복사가 작동합니다.

이후에 설명할 `Array`와 `Dictionary`의 복사는 구조체가 아닌 클래스로 구현된 `NSArray`와 `NSDictionary`의 복사와도 또한 다르게 작동합니다. `NSArray`와 `NSDictionary`인스턴스는 언제나 복사가 아니라 인스턴스의 레퍼런스가 전달되거나 할당됩니다.

> NOTE
> 밑에 설명은 배열, 딕셔너리, 문자열 그리고 다른 값의 "복제"를 설명합니다. 복제가 언급된곳에서 여러분은 여러분의 코드가 언제나 복사처럼 작동하는것을 보게 될것입니다. 하지만 Swift는 절대적으로 필요할 경우에만 실제 값의 복사가 일어납니다. Swift는 추가적인 성능적 향상을 위해서 모든 값의 복사를 관리합니다. 그리고 이러한 최적화를 선점하기위해서 대체적인 할당문의 사용을 해서는 안됩니다.

## 딕셔너리의 할당과 복사
여러분이 `Dictionary` 인스턴스를 상수또는 변수에 할당할때나 함수또는 메소드에 매개변수로 전달할때 딕셔너리는 할당이되거나 함수가 호츨되는 그 시점에 복제가 됩니다. 이 과정의 자세한 사항은 `Structures and Enumerations Are Value Types` 항목을 참조하십시오.

만약 딕셔너리 인스턴스에 저장되어있는 키 또는 값이 값형식(구조체이거나 열거형)일 경우 그들 역시 할당될시나 함수의 호출시에 복제가 일어납니다. 이와는 다르게 만약 키 또는 값이 참조형식(클래스이거나 함수)일 경우에는 레퍼런스의 복제가 일어납니다. 하지만 이것은 그들이 참조하고 있는 클래스 인스턴스나 함수가 아닙니다. 이러한 딕셔너리의 키또는 값의 복제 방식은 구조체가 복사될때 구조체의 저장속성의 복제방식과 같습니다.

밑의 예제에서는 네 사람의 이름과 나이를 갖는 `ages`라는 딕셔너리를 정의합니다. `copiedAges`라 명명된 새로운 변수에 이 `ages` 딕셔너리를 할당합니다. 할당후에 `ages`와 `copiedAges`는 서로 다른 딕셔너리입니다.
```
var ages = ["Peter": 23, "Wei": 35, "Anish": 65, "Katya": 19]
var copiedAges = ages
```
이 딕셔너리의 키는 `String`타입이고 값은 `Int`형입니다. 두 형은 Swift에서 값형식입니다. 그러므로 딕셔너리의 복제가 일어날때 키와 값들 또한 복제됩니다.

여러분은 두 딕셔너리중에 하나의 age값을 바꾸고 확인함으로써 `ages` 딕셔너리가 복제되었음을 증명할수 있습니다. 여러분이 `copiedAges` 딕셔너리의 "Peter"의 값을 24로 바꿔도 `ages` 딕셔너리의 반환값은 복제가 일어나기전과 동일한 23을 반환함을 알수 있습니다.
```
copiedAges["Peter"] = 24
println(ages["Peter"])
// "23" 출력
```
## 배열의 할당과 복제
Swift의 배열형의 할당과 복제방식은 딕셔너리 형보다 더 복잡합니다. `Array`는 여러분이 배열의 요소들을 다룰때와 복제할때 반드시 필요할 경우에만 복제를 행함으로써 C와 비슷한 성능을 제공합니다. 만약 여러분이 `Array` 인스턴스를 상수또는 변수에 할당하거나 함수 또는 메소드의 매개변수로 전달할때 배열의 요소들은 할당이 될때나 함수가 호츨될때 복제되지 않습니다. 대신 두 배열은 동일하게 정렬된 요소들의 값을 공유합니다. 여러분은 한 배열에서 요소의 값을 수정할때 다른 또 하나의 배열을 통해서 그 결과를 관찰하실 수 있습니다.

배열에서 복제는 여러분이 배열의 길이를 수정할 가능성이 있는 코드를 실행할때 일어납니다. 이것은 요소의 추가, 삽입, 삭제 또는 배열요소들의 범위를 바꾸기 위해 사용되어지는 범위지정된 subscript들을 포함합니다. 배열의 복제가 일어날때의 배열 요소들의 복제 작동방식은 `Assignment and Copy Behavior for Dictionaries`에 설명된 딕셔너리의 키, 값의 복제와 동일합니다.

아래 예제는 `a`라 명명된 변수에 `Int`값들을 갖는 새로운 배열을 할당합니다. 그리고 이 배열은 또다시 `b`와 `c`로 명명된 두 변수에 할당됩니다.
```
var a = [1, 2, 3]
var b = a
var c = a
```
여러분은 supscript 문법을 통해 a 또는 b 또는 c 배열의 첫번째 값을 구할수 있습니다.
```
println(a[0])
// 1
println(b[0])
// 1
println(c[0])
// 1
```
만약 여러분이 supscript 문법을 통해 배열에 새로운 값을 할당하면 `a`, `b`, `c` 세개의 배열은 새로 할당된 값을 반환할것입니다. supcript 문법을 통한 단일 값의 수정은 배열의 길이를 변화시키지 않기때문에 배열의 요소에 새로운 값을 할당할때에는 복제가 일어나지 않습니다.
```
a[0] = 42
println(a[0])
// 42
println(b[0])
// 42
println(c[0])
// 42
```
하지만 만약 여러분이 `a`배열에 새로운 요소를 추가한다면 여러분은 배열의 길이를 수정하게 됩니다. 이것은 Swift로 하여금 요소가 추가될시에 새로운 배열의 복제를 생성하게 합니다. 더욱이 `a`는 별도의 독립적인 원배열의 복제된 배열입니다.

만약 여러분이 복제가 된후에 `a`배열의 요소를 수정하면 `a`는 여전히 원배열 요소를 참조하고 있는 `b`나 `c`와는 다른 값을 반환할것입니다.
```
a.append(4)
a[0] = 777
println(a[0])
// 777
println(b[0])
// 42
println(c[0])
// 42”
```
## 배열 유니크 확인
배열을 함수나 메소드에 전달하거나 배열의 요소들을 조작하기전에 그 배열이 유니크한지 확인하는것은 유용합니다. 배열형 변수의 메소드인 `unshare`를 호출함으로써 여러분은 배열의 유니크함을 확인하실 수 있습니다. (`unshare` 메소드는 상수 배열로는 호출할수 없습니다.)

만약 여러 변수들이 동일한 배열을 참조하고 있고 여러분이 그중에 하나의 변수를 이용해서 `unshare`메소드를 호출했다면 그 배열은 복제가 됨으로써 그 변수가 그 변수만의 독립적인 배열의 복사를 가지게 됩니다. 하지만 그 변수가 그 배열에 대한 유일한 참조변수라면 복제가 일어나지 않습니다.

위 예제코드의 마지막에 `b`와 `c`는 동일한 배열을 참조하고 있습니다 `b`배열 `unshare` 메소드를 호출해서 유니크한 배열을 만들도록 하겠습니다.
```
b.unshare()
```
만약 여러분이 `unshare` 메소드를 호출한뒤에 `b` 배열의 첫번째 요소의 값을 수정한다면 세 배열은 모두 다른 값을 보여줄겁니다.
```
b[0] = -105
println(a[0])
// 777
println(b[0])
// -105
println(c[0])
// 42
```
## 복수의 배열이 동일한 요소들을 공유하는지 검사
식별 연산자(===와 !===)를 통해 하나 이상의 배열 또는 subarray들이 동일한 저장소와 요소들을 공유하는지를 확인할수 있습니다.

아래 예제에서는 "동일한(identical to)" 연산자(===)를 사용해서 배열 `b`와 `c`가 여전히 배열요소들을 공유하는지 확인합니다.
```
if b === c {
println("b and c still share the same array elements.")
} else {
println("b and c now refer to two independent sets of array elements.")
}
// "b and c now refer to two independent sets of array elements." 출력
```
또한 식별연산자를 사용해 subarray들이 동일한 요소를 공유하는지도 검사할수 있습니다. 아래 예제는 `b`의 동일한 subarray를 비교함으로써 그 둘이 동일한 요소를 참조하고 있음을 확인합니다.
```
if b[0...1] === b[0...1] {
printls("These two subarrays share the same elements.")
} else {
println("These two subarrays do not share the same elements.")
}
// "These two subarrays share the same elements." 출력
```
## 강제로 배열 복제하기
배열의 `copy` 메소드를 호출함으로 강제적으로 배열의 복제를 할수 있습니다. 이 메소드는 얕은복제(shallow copy)를 행하며 복사된 요소들을 갖는 새로운 배열을 반환합니다.
아래 예제에서 우리는 `names`라는 배열을 정의하고 7명의 이름을 저장합니다. `copiedNames`로 명명된 새로운 변수에 `names`배열의 `copy`메소드를 호출하고 결과값을 할당합니다.
```
var names = ["Mohsen", "Hilary", "Justyn", "Amy", "Rich", "Graham", "Vic"]
var copiedNames = names.copy()
```
여러분은 둘중 하나의 배열 요소의 값을 수정하고 다른 배열에서의 요소값을 확인함으로써 `names` 배열의 복제가 제대로 이루어졌는지 확인하실수 있습니다.
만약 여러분이 `copiedNames` 배열의 첫번째 요소의 값을 `Mohsen`에서 "Mo"로 수정해도 `names`배열은 여전히 복제가 일어나기전의 원래 값인 "Mohsen"을 반환합니다.
```
copiedNames[0] = "Mo"
println(names[0])
// "Mohsen" 출력
```
> NOTE
> 여러분이 단지 특정배열이 존재하는 유일한 레퍼런스임을 확실시 하시고 싶으시다면 `copy`가 아닌 `unshare`메소드를 호출하십시오. `unshare`메소드는 필요한 경우가 아닐경우 배열의 복제를 생성하지 않습니다. 반면 `copy` 메소드는 그 배열이 다른 배열과 공유하고 있지 않더라도 언제나 복제 배열을 생성합니다.
chapter3
# 03 기초 다지기 (The Basics)
> Translator : FlashMaestro (masterofflash@nate.com)

Swift는 iOS와 OS X 앱을 개발하기 위한 새로운 프로그래밍 언어 입니다. 그러나 많은 부분이 C나 Objective-C로 개발하면서 얻었던 경험들과 유사할 것입니다.

Swift는 정수형을 위한 `Int`, 부동소숫점 값을 위한 `Double`과 `Float`, 불리언값을 위한 `Bool`, 문자열 데이터를 위한 `String`을 포함해 C와 Objective-C의 기본적인 데이터 타입에서 약간 변형된 형태로 제공합니다. 또한 `컬랙션 타입`으로 통칭되는 `Array`와 `Dictionary` 이 두가지 주요한 컬랙션 타입 또한 강력한 형태로 제공합니다.

Swift도 C처럼 식별 가능한 이름을 가지고 값을 참조하거나 저장하기 위한 변수를 사용합니다. 또한 변경 불가능한 값들 또한 폭넓게 사용되도록 했습니다. 보통 상수라고 알려져 있는데, 이것은 C에서의 상수보다 훨씬 강력합니다. 상수는 변경될 필요가 없는 값을 가지고 작업하려고 할 때 코드를 조금 더 안전하고 깔끔하게 만들 수 있도록 Swift 전반에 걸쳐 쓰이게 됩니다.

Swift는 잘 알려진 타입들 뿐 아니라 Objective-C에는 없었던 고급 타입들도 선보이고 있습니다. 값들의 묶음을 만들고 전달할 수 있도록 하는 튜플도 이 고급 타입들 중에 하나입니다. 튜플은 함수의 반환값으로 여러개의 값을 하나로 결합해 돌려줄 수 있도록 합니다.

Swift는 어떤 값의 부재를 다룰 수 있는 선택형 타입도 제공 합니다. 이 선택형은 "값이 존재하고, 그 값은 x입니다." 혹은 "값이 존재 하지 않습니다."라고 할 수 있습니다. 선택형은 Objective-C의 포인터에서 `nil`을 사용하는 것과 비슷합니다. 하지만 클래스 뿐만 아니라 어떤 타입에도 사용할 수 있습니다. 선택형은 Objective-C의 `nil` 포인터보다 훨씬 안전하고 쓰임새 있습니다. 또 Swift의 강력한 기능들중 핵심적인 기능입니다.

선택형은 Swift가 `type safe`하다는 예시 입니다. Swift는 당신이 코드를 통해 다루는 값들의 타입을 확실히 하는 것을 돕습니다. 당신이 만든 코드중에 일부가 `String` 타입을 사용해야 할 때 타입 세이프는 `Int`같은 값을 전달하는 실수를 막아줍니다. 이를 통해 개발하는 동안 가능한한 빨리 에러는 인지하고 고치는 것이 가능합니다.

##상수(Constants)와 변수(Variables)
상수와 변수는 어떤 이름(`maximumNumberOfLoginAttempts`나 `welcomeMessage`)과 특정한 형태의 값(숫자 `10`이나 문자열 `Hello`)의 결합으로 구성됩니다. 상수의 값은 한번 지정되고 난 후에는 변경될 수 없고 변수는 값이 지정되고 난 이후에도 변경될 수 있습니다.


###상수와 변수의 선언
상수와 변수는 사용되기 전에 선언되어야 합니다. 상수는 let키워드, 변수는 var 키워드를 가지고 정의할 수 있습니다. 여기 사용자가 로그인을 시도한 횟수를 추적하는데 사용되는 변수와 상수를 만드는 예제가 있습니다.

```c
let maximumNumberOfLoginAttempts = 10
var currentLoginAttempt = 0
```

이 코드는 다음과 같이 해석할 수 있습니다.

"maxiumNumberOfLoginAttempts라는 새로운 상수를 선언하고 값은 10으로 할당한다. 그리고 currentLoginAttempt라는 변수를 선언하고 0이라는 초기값을 할당한다."

예제에서 보면 최대값은 변하지 않기 때문에 로그인을 시도할 수 있는 최대 횟수가 상수에 정의되어 있습니다. 그리고 매번 로그인을 실패할 때마다 숫자가 증가해야 하기 때문에 현재 로그인 시도 횟수는 변수로 정의되어 있습니다.

콤마로 구분해서 한줄에 여러개의 상수나 변수를 선언하는 것도 가능합니다.

var x = 0.0, y = 0.0, z = 0.0

>노트
코드를 작성할 때 변경할 필요가 없는 값을 저장하는 경우 항상 `let` 키워드를 사용해 상수로 선언하라. 그리고 변경할 필요가 있을 경우에만 변수로 선언하라.

###타입 명시(Type Annotations)
상수나 변수를 만들 때 어떤 형태의 값이 저장될 지 명확하게 하기 위해 타입을 명시할 수 있습니다. 상수나 변수의 이름뒤에 콜론을 쓰고 한칸을 띄우고 사용하고 싶은 타입의 이름을 써서 타입을 명시할 수 있습니다.

다음 예시는 `welcomeMessage`라는 변수에 `String`값이 저장될 수 잇다는 것을 표시하기 위해 타입 명시를 하는 것입니다.

var welcomeMessage: String

콜론은 "~타입 의"라는 의미를 가집니다. 따라서 위의 코드는 다음과 같이 해석할 수 있습니다.

"`String`타입의 변수 welcomeMessage를 선언한다."

"`String`타입의" 라는 말은 "어떤 `String`값이든 저장할 수 있다."라는 의미 입니다. "어떤타입의"(혹은 "어떤 종류의") 라는 것은 그것이 저장될 수 있다 라는 의미로 생각하면 됩니다.

이제 `welcomeMessage`변수에는 오류없이 어떤 문자열 값이든 저장할 수 있습니다.

welcomeMessage = "Hello"

>노트
연습중에 타입 명시를 해야하는 경우는 드물다. 만약 상수나 변수를 정의하는 지점에 초기값을 지정한다면, Swift는 그 상수나 변수를 위해 사용할 타입을 추측한다. 이것이 바로 `타입 세이프`와 `타입 추정`이다. 위의 예제에서 `welcomeMessage`에 초기값을 지정하지 않았다. 그래서 초기값으로 부터 타입을 추정하기 힘들기 때문에 타입을 명시해준 것이다.

###상수와 변수 이름 짓기
상수와 변수의 이름을 지정하기 위해서 유니코드를 포함한 어떤 문자든지 사용할 수 있습니다.

```c
let π = 3.14159
let 你好 = "你好世界"
let 🐶🐮 = "dogcow"
```

상수와 변수의 이름에는 수학기호, 화살표, 개인용(혹은 유효하지 않은) 유니코드, -선, 상자 그리기용 문자 등을 사용할 수 없다. 또 숫자로 시작해서도 안되고 이름 중간에 숫자가 들어가서도 안됩니다.

특정 타입의 상수나 변수를 한번 선언 했다면, 같은 이름으로 다시 선언하는 것이나 다른 형태의 값을을 저장하도록 하는 것은 불가능 합니다. 또 변수에 상수를 저장하거나 상수에 변수를 저장하는 것 또한 불가능 합니다.

>노트
만약 Swift 예약어로 상수나 변수명을 만들고 싶다면 변수명을 ```표시로 묶어서 쓸 수 있다. 그러나 정말 다른 대안이 없는 경우가 아니면 사용하지 않는 것이 좋다.

기존 변수의 값을 호환 가능한 다른 값으로 변경할 수 있습니다.. 예를 들면 `friendlyWelcome`의 값은 `"Hello!"`에서 `"Bonjour!"`로 변경됩니다.

```c
var friendlyWelcome = "Hello!"
friendlyWelcome = "Bonjour!"
// friendlyWelcome is now "Bonjour!
```

변수와는 다르게 상수는 한번 값이 정해지면 변경할 수 없습니다.. 컴파일할 때 에러가 발생하도록 시도해 봅시다.

```c
let languageName = "Swift"
languageName = "Swift++"
// this is a compile-time error - languageName cannot be changed
```


### 상수와 변수의 출력
`println` 함수를 사용하면 상수와 변수의 현재 값을 출력할 수 있습니다.

```c
println(friendlyWelcome)
// prints "Bonjour!
```

`println`은 출력하기 적절하게 줄단위로 끊어서 값을 출력해주는 전역 함수 입니다. Xcode에서 작업을 하고 있다면 `println`을 사용하면 Xcode의 "console"창에 결과가 나옵니다. (다음으로 `print` 함수는 `println`함수와 동일한 기능을 수행하지만 값을 출력하기 위해 한줄의 끝을 표시해줄 필요가 없습니다.)

`println`함수는 전달된 어떤 `String`값이든 출력해줍니다.

```c
println("This is a string")
// prints "This is a string
```

`println`함수는 코코아의 `NSLog`함수와 비슷한 방식으로 복잡한 로그 메시지를 출력하는 것도 가능합니다. 메시지에는 상수와 변수의 현재값을 포함할 수 있습니다.

Swift는 긴 문자열에서 상수나 변수명을 대체문자로 사용해 Swift가 상수나 변수의 현재 값으로 즉시 대체할 수 있도록 문자열 해석 방식을 사용합니다. 다음과 같이 이름을 괄호로 감싸고 이스케이프 시키기 위해 여는 괄호 앞에 백슬래시를 써주면 됩니다.

```c
println("The current value of friendlyWelcome is \(friendlyWelcome)")
// prints "The current value of friendlyWelcome is Bonjour!
```

>노트
문자열 해석에 관한 모든 옵션은 `문자열 해석` 부분에 설명되어 있습니다.

###주석(Comments)

스스로 상기하기 위해서 혹은 메모하기 위해 코드내에 실행되지 않는 글을 쓰려고 할 때 주석을 사용할 수 있습니다. 작성한 코드를 컴파일 할 때 Swift의 컴파일러는 주석을 무시합니다.

Swift의 주석은 C의 주석과 흡사합니다. 한줄 주석은 /(슬래시)를 두번 연속해서 쓰면 시작됩니다.

// this is a comment

또 여러줄 주석도 쓸 수 있습니다. 여러줄 주석은 슬래시와 별표를 쓰고(/*) 끝에는 별표와 슬래시(*/)를 순서대로 써주면 됩니다.

```c
/* this is also a comment,
but written over multiple lines */
```

C의 여러줄 주석과는 다르게 Swift에서는 여러줄 주석 안에 다른 여러줄 주석을 쓸 수 있습니다. 내부 여러줄 주석을 쓰려면 첫번째 여러줄 주석 부분을 시작하고 두번째 여러줄 주석을 첫번째 주석 안에서 시작합니다. 그리고 두번째 주석을 닫아준 후 첫번째 주석을 닫아주면 됩니다.

```c
/* this is the start of the first multiline comment
/* this is the second, nested multiline comment */
this is the end of the first multiline comment */
```

내부 여러줄 주석은 이미 코드에 여러줄 주석을 포함하고 있더라도 넓은 범위의 코드를 빠르고 쉽게 주석처리 할 수 있게해줍니다.

###세미콜론(Semicolons)
많은 다른 언어들과는 다르게 Swift는 코드의 각 문장 끝마다 세미콜론이 꼭 필요하지는 않습니다. 하지만 쓰고 싶다면 써도 됩니다. 하지만 한줄에 여러 문장을 처리하려고 한다면 세미콜론이 꼭 필요 합니다.

```c
let cat = "🐱"; println(cat)
// prints "🐱"
```

###정수(Integers)
정수는 `42`나 `-23`같이 소수점 단위가 없는 숫자들 전체 입니다. 정수는 부호가 있는 것(양수,0, 음수)와 부호가 없는 것(양수, 0) 모두를 포함합니다.

Swift는 8, 16, 32, 64 비트 형태로 부호있는 정수와 부호없는 정수를 지원합니다. 정수형은 부호 없는 8비트 정수형 `UInt8`, 부호있는 32비트 정수형 `Int32` 처럼 C와 비슷한 관습을 따른 이름을 갖고 있습니다. Swift의 다른 모든 타입과 마찬가지고 정수형 타입명 역시 대문자로 시작합니다.

####정수범위
각 정수형 타입에 최대값과 최소값은 `min`과 `max` 속성을 가지고 접근할 수 있습니다.

```c
let minValue = UInt8.min // minValue is equal to 0, and is of type UInt8
let maxValue = UInt8.max // maxValue is equal to 255, and is of type UInt8
```

이런 속성값들은 예제에서 볼 수 있는 `Uint8`과 같은 타입들의 적정 범위를 나타내는 값이기 때문에 다른 타입들에도 동일 표현으로 사용할 수 있습니다.

####Int
대부분의 경우 코드 내에서 사용하기 위해 특정 크기를 지정할 필요가 없습니다. Swift가 현재의 플랫폼에 해당하는 워드(word) 크기를 갖는 `Int`라는 추가 타입을 지원하기 때문입니다.

- 32비트 플랫폼에서 `Int`는 `Int32`와 동일한 크기를 갖습니다.
- 64비트 플랫폼에서 `Int`는 `Int64`와 동일한 크기를 갖습니다.

정수형의 특정 크기가 필요한 것이 아니라면 코드 내에서 항상 `Int`를 사용하면 됩니다. 이것은 코드가 일관성을 갖고 상호처리가 가능하도록 합니다. 32비트 플랫폼에서 조차 `Int`는 넓은 범위의 정수를 포함하기에 충분할 만한 `-2,147,483,648` ~ `2,147,483,647`의 범위를 갖습니다.

####UInt
Swift는 `UInt`라는 부호없는 정수 타입도 지원합니다. 이것 또한 현재 플랫폼에 해당하는 워드 크기를 갖습니다.

- 32비트 플랫폼에서 `UInt`는 `UInt32`와 동일한 크기를 갖습니다.
- 64비트 플랫폼에서 `UInt`는 `UInt64`와 동일한 크기를 갖습니다.

>노트
특별히 현재 플랫폼 해당 워드 크기의 부호없는 정수형이 필요할 때만 `UInt`를 사용하라. 그런 경우가 아니라면 양수만 저장하는 경우일지라도 `Int`가 더 적절하다. 정수형을 위한 `Int`의 일관성이 코드가 `타입 세이프`와 `타입 추정`으로 묘사되는 다른 숫자 형태로의 변환또는 정수의 추정 타입일치가 필요한 경우를 피해 상호처리가 가능하도록 합니다.

###부동 소수점 수
부동 소수점 수란 `3.14159`, `0.1`, `-273.15` 처럼 소수 부분을 갖는 숫자를 말합니다.

부동 소수점 타입은 `Int` 타입에 저장될 수 있는 것보다 훨씬 크거나 작은 숫자를 저장하거나 더 넓은 범위의 숫자를 표현할 수 있습니다. Swift는 두가지의 부동 소수점 타입을 제공합니다.

- `Double`은 64비트 부동 소수점 수를 표현합니다. 매우 크거나 특별히 정밀한 부동 소수점 값을 원할 경우 사용합니다.
- `Float`은 32비트 부동 소수점 수를 표현합니다. 64비트의 정밀함이 필요하지 않은 경우 사용합시다.

>노트
`Float`이 6자리의 소수를 표현할 수 있는 것에 비해 `Double`은 최소 15자리의 소수를 표현할 수 있는 정도의 정밀도를 갖습니다. 코드에서 다루는데 필요한 속성이나 값의 범위에 따라 적절히 부동 소수점 타입을 골라서 사용합니다.

### 타입 세이프와 타입 추정(Type Safty and Type Inference)
Swift는 타입 세이프 언어입니다. 타입 세이프 언어들은 코드 내에서 다루는 값들의 타입이 명확하도록 만듭니다. 코드의 어떤 부분에서 `String`타입이 기대된다면 실수로 `Int`타입을 전달하는 것은 불가능합니다.

Swift가 타입 세이프이기 때문에 컴파일을 할 때 타입 검사를 수행하고 일치하지 않는 타입들에 대해서 에러로 표시합니다. 이를 통해 개발을 진행하면서 가능한 일찍 오류를 인지하고 고칠 수 있도록 합니다.

타입 검사는 다른 형태의 값들을 가지고 일을할 때 에러를 피할 수 있도록 해줍니다. 그러나 이것이 항상 상수나 변수를 선언할 때 타입을 명시해줘야 한다는 것을 의미하지는 않습니다. 필요로 하는 값의 타입을 명시해야 하지 않는 경우 Swift는 적절한 타입을 찾기 위해 타입 추정을 수행합니다. 타입 추정은 코드를 컴파일할 때 프로그래머가 공급한 값을 가지고 컴파일러가 자동적으로 특정 표현식의 타입을 알아내도록 합니다.

Swift는 타입 추정 때문에 C나 Objective-C에 비해 타입을 지정해줘야 하는 경우가 적습니다. 상수나 변수는 여전히 명시적으로 타입이 지정되지만 그 타입을 특정하는 많은 일들이 대신 수행됩니다.(*역자주: 상수나 변수는 타입 추정을 통해 타입을 확실하게 가지게 되기 때문에 타입을 지정해주기 위해 프로그래머가 해야할 일들이 줄었다는 것입니다.)

타입 추정은 상수나 변수를 초기값과 함께 선언할 때 특히 유용합니다. 종종 타입 추정은 상수나 변수가 선언되는 지점에서 문자 그대로의 값을 할당하는 것을 통해 이뤄집니다.(문자 그대로의 값이란 아래쪽 예시에서 볼 수 있는 `42`나 `3.14159`와 같은 소스코드에 직접적으로 쓰여져 있는 값을 말합니다.)

예를 들면, 타입을 명시하지 않고 새로운 상수를 선언할 때 `42`라는 문자그대로의 값을 할당하면 Swift는 정수형처럼 보이는 숫자를 가지고 초기화를 했기 때문에 상수가 `Int`값을 갖기를 원한다고 추정합니다.

```c
let meaningOfLife = 42
// meaningOfLife is inferred to be of type Int
```

이와 비슷하게 부동 소수점 수를 위한 타입을 특정하지 않으면 Swift는 `Double`형 타입을 생성하길 원하다고 추정합니다.

```c
let pi = 3.14159
// pi is inferred to be of type Double
```

Swift는 부동 소수점 수를 위한 타입을 추정할 때 `Float`보다는 항상 `Double`을 선택합니다.

만약 한 표현식 안에 정수와 부동 소수점 수를 결합해서 사용하면 문맥으로부터 `Double` 타입이라고 추정될 것입니다.

```c
let anotherPi = 3 + 0.14159
// anotherPi is also inferred to be of type Double
```

문자 그대로의 `3`은 스스로 어떤 타입인지 명시되어 있지 않습니다. 또 덧셈 부분에 부동 소수점 수가 존재하기 때문에 `Double`이 출력 지정 타입으로 추정됩니다.

## 숫자의 문자표현
정수 문자표현은 다음과 같이 쓸 수 있습니다.
- 10진수는 아무런 접두어 없이
- 2진수는 접두어 `0b`를 붙여서
- 8진수는 접두어 `0o`를 붙여서
- 16진수는 접두어 `0x`를 붙여서

다음 정수 문자 표현들은 모두 십진수 `17`을 나타냅니다.

```c
let decimalInteger = 17
let binaryInteger = 0b10001 // 17 in binary notation
let octalInteger = 0o21 // 17 in octal notation
let hexadecimalInteger = 0x11 // 17 in hexadecimal notation
```

부동 소수점 수의 문자 표현은 10진수(접두어 없이) 혹은 16진수(접두어 `0x`를 붙여서)가 될 수 있습니다. 이런 문자표현은 소수점 앞뒤로 항상 숫자(혹은 16진수 숫자)를 갖습니다. 또 이것은 10진수의 소수점을 나타내기 위한 대소문자 `e` 혹은 16진수의 소수점을 나타내기 위한 `p`로 표현되는 *지수*를 가지고 있을 수도 있습니다.

`exp` 지수를 가지고 있는 10진수는 기수에 10의 exp승을 곱해 얻을 수 있습니다.

- 1.25e2 means 1.25 × 10^2, or 125.0.
- 1.25e-2 means 1.25 × 10^-2, or 0.0125.

`exp` 지수를 가지고 있는 16진수는 기수에 2의 exp승을 곱해 얻을 수 있습니다.

- 0xFp2 means 15 × 2^2, or 60.0.
- 0xFp-2 means 15 × 2^-2, or 3.75.

다음 부동 소수점 수의 문자표현은 모두 10진수 `12.1875`의 값을 갖습니다.

```c
let decimalDouble = 12.1875
let exponentDouble = 1.21875e1
let hexadecimalDouble = 0xC.3p0
```

숫자의 문자표현은 좀 더 쉽게 읽을 수 있도록 추가 형식을 포함하기도 합니다. 정수나 소수 모두 좀 더 읽기 쉽도록 여분의 0이나 _(underscores)를 포함할 수 있습니다. 두 양식 모두 문자표현의 실제 값에는 영향을 주지 않습니다.

```c
let paddedDouble = 000123.456
let oneMillion = 1_000_000
let justOverOneMillion = 1_000_000.000_000_1
```