Merge changes from master into Seoh

Seoh Cha authored
revision bea266cacbda316cb740510fc4923f0d846cdf8a
About
# Apple Swift Programming Language translation for KOREAN
**“Apple Inc. Copyright © 2014 Apple Inc. All rights reserved.”**
This is a [The Swift Programming Language](https://developer.apple.com/swift/) guide documentation translation project.

_This project is **never used for commercial purposes**.
By translating "The Swift Programming Language" we want to help a lot of korean learners who may otherwise struggle to understand it._

> 이 프로젝트는 애플의 새로운 프로그래밍 언어 **swift** 번역 프로젝트입니다. 자유롭게 참여하세요 =)
**이 번역 프로젝트는 절대로 상업적인 목적으로 사용되지 않습니다.**

## DownloadOiginal Contents
- [Download “The Swift Programming Language” from the iBooks Store](https://itunes.apple.com/us/book/the-swift-programming-language/id881256329?mt=11)
- [Download "The Swift Programming Language" from private dropbox](https://www.dropbox.com/s/rd79pw1bhhvg22h/the-swift-rogramming-language.pdf)

## 현재 번역 상태
- _**두껍고 이탤릭의**_ 글씨는 번역이 1차적으로 완료 된 페이지 입니다. 오역이나 더 나은 표현이 있을 경우에는 [Discussion](https://www.penflip.com/jjuakim/swift-korean/discussions)페이지에 가셔서 해당 chapter를 찾고 같이 이야기를 나눠보세요.
- 일단 `Chapter 25` 까지 우선적으로 번역할 예정입니다.
- Chapter 25까지 번역 후 P.R로 피드백 수렴하면서 뒷부분(Chapter 26~ ) 번역을 진행하겠습니다.
- `@멘션` 표시가 없는 챕터는 아직 할당되지 않은 챕터입니다. [Discussion-챕터 분배 (얼른 와서 찜하세요)](https://www.penflip.com/jjuakim/swift-korean/discussions/2) 에 가서 원하는 챕터를 `댓글`로 찜 하세요! 확인후 운영자가 `assign` 해드립니다

## 작업 할당
01. _**Swift에 대해서 by @FlashMaestro**_
02. Swift 둘러보기 (Assign to @FlashMaestro)
03. 기초 다지기 (Assign to @FlashMaestro)
04. 기본 연산자 (Assign to @Nirvana)
05. 문자열과 문자 (Assign to @Nirvana)
06. 컬렉션 타입 (Assign to @justinchronicle)
07. 통제 흐름 (Assign to @nassol)
08. 함수 (Assign to @Quartet)
09. 클로저(Closures) (Assign to @inureyes)
10. 열거형 (Assign to @inureyes )
11. 클래스와 구조체 (Assign to @seanmoon)
12. 속성 (Assign to @mango)
13. 메서드 (Assign to @northPenguin)
14. 서브 스크립트 (Assign to @Snowcat8436)
15. 상속 (Assign to @hoppingbonny)
16. 초기화 (Assign to @qwneed)
17. 해제(Deinitialization) (Assign to @qwneed)
18. 자동 참조 계수(ARC) (Assign to @RoyTheGame)
19. 옵션 연쇄 (Assign to @hyukhur)
20. 타입 변환 (Assign to @Snowcat8436)
21. 내부 타입 (Assign to @jjuakim)
22. 확장 (Assign to @easthelper)
23. 프로토콜
24. 제네릭 (Assign to @eonil)
25. 고급 연산자 (Assign to @dyanos)


## Rule
[추가논의](https://www.penflip.com/jjuakim/swift-korean/discussions/1)는 이 곳에서..
- 문서 작성은 개인 version에서 작업 한뒤 pull request로 merge 합니다.

## Translation Guide
[추가논의](https://www.penflip.com/jjuakim/swift-korean/discussions/1)는 이 곳에서..
- 담당 부분에서 최초 등장 용어에 영문을 함께 표기. 그 이후로는 번역단어로만 표기
> Ex) (최초) 함수(Function)란 xxxx -> (이후) 함수는 xxxx
The Swift Programming Language 웹 사이트](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/)

## Let's tralate it!
- 누가 어떤 챕터를 번역하고 있을까..? 저도 참여할 수 있을까요? - [번역작업 할당 현황](https://www.penflip.com/jjuakim/swift-korean/discussions/35)
- 번역을 시작하기전에 그리고 submit 하기 전에 꼭 읽어주세요! - [번역 가이드](https://www.penflip.com/jjuakim/swift-korean/discussions/36)
- 이러한 단어는 어떻게 번역해야 할까요? - [Dictionary](https://www.penflip.com/jjuakim/swift-korean/discussions/27)

Contents
> These files will be included in your book:

About.txt
chapter1.txt
chapter2.txt
chapter3.txt
chapter4.txt
chapter5.txt
chapter6.txt
chapter7.txt
chapter8.txt
chapter9.txt
chapter10.txt
chapter11.txt
chapter12.txt
chapter13.txt
chapter14.txt
chapter15.txt
chapter16.txt
chapter17.txt
chapter18.txt
chapter19.txt
chapter20.txt
chapter21.txt
chapter22.txt
chapter23.txt
chapter24.txt
chapter25.txt
translator.txt
chapter1
# 01 Swift에 대해서 (About Swift)
> Translator : 이름 (메일주소)


Swift는 C언어 호환성에 대한 제약없이 C언어 그리고 Objective-C언어 중 최고의 것들을 기반으로 iOS와 OS X 앱을 개발하기 위한 언어입니다. Swift는 안전한 프로그래밍 패턴을 채용했고 프로그래밍을 더욱 쉽고 유연하고 재미있게 만들어주는 최신 특징들을 더했습니다. 성숙하고 많은 사랑을 받고 있는 코코아, 코코아 터치 프레임워크를 기반으로한 Swift의 이런 훌륭함은 소프트웨어 개발 방법에 대한 새로운 상상의 기회입니다.

Swift는 몇년에 걸쳐 만들어져 왔습니다. 애플은 Swift를 위한 현존하는 진보한 컴파일러, 디버거, 프레임워크 기반의 토대를 만들었습니다. 우리는 자동 레퍼런스 계수( ARC)로 메모리 관리를 단순화 했습니다. Foundation(Apple Foundation Framework)과 코코아의 견고한 기초를 기반으로 만들어진 우리의 프레임워크 스텍은 최신화와 표준화의 결과물입니다. Objective-C는 블록, 문자집합, 모듈, 혼란없는 최신 언어 기술 프레임워크 적용 가능 등을 지원하도록 발전해왔습니다. 이러한 기초작업에 감사하며 애플 소프트웨어 개발의 미래를 위한 새로운 언어를 소개합니다.

Swift는 Objective-C 개발자들에게 매우 친숙한 느낌을 줍니다. Swift가 Objective-C의 명명식 파라미터의 읽기 쉬움과 다이나믹 객체 모델의 능력을 적용했기 때문입니다. 이를 통해 끊김없는 기존 코코아 프레임워크에 대한 접근과 Objective-C와의 혼합된 상호운영을 제공합니다. 이러한 공통점을 기반으로 만들어진 Swift는 많은 새로운 특징들과 언어의 절차지향과 객체지향적 부분에 대한 통합을 도입했습니다.

Swift는 초보 프로그래머 친화적입니다. Swift는 스크립트 언어만큼이나 표현하기 쉽고 즐거운데다가 산업품질에 적합한 시스템 프로그래밍 언어입니다. Swift는 프로그래머들이 빌드하고 실행하는 낭비없이 즉기 Swift의 코드를 실험하고 결과를 볼 수 있도록하는 혁신적인 요소인 playgrounds를 지원합니다.

Swift는 폭넓은 애플 엔지니어링 문화로 부터 나온 지혜와 뜻을 같이하는 최신 언어들중 최고의 것들을 겸비하고 있습니다. 성능과 개발편리성에 대한 타협이 필요없을 만큼 컴파일러는 성능에 최적화되어 있고, 언어는 개발편리성에 최적화 되어 있습니다. Swift는 "hello, world"로부터 전체 운영체제로 확장할 수 있게 디자인 되었습니다. 이 모든것이 Swift 때문에 애플과 개발자들에게 투자할 가치가 있다고 생각하게 합니다.

Swift는 iOS와 OS X 앱을 만들고 또 계속 새로운 기능을 추가하고 개선하기 위한 환상적인 방법입니다. Swift를 향한 우리의 목표는 야심찹니다. 우리는 당신이 Swift로 무언가 만드는 것을 빨리 보고싶습니다.
chapter10
# 10 열거형 (Enumerations)
> Translator : 이름 (메일주소)


Enumerations
An enumeration defines a common type for a group of related values and enables you to
work wi th those values in a type-safe way wi thin your code.
If you are fami l iar wi th C, you wi l l know that C enumerations assign related names to a
set of integer values. Enumerations in Swi ft are much more flexible, and do not have to
provide a value for each member of the enumeration. If a value (known as a “raw” value)
i s provided for each enumeration member, the value can be a string, a character, or a
value of any integer or floating-point type.
Al ternatively, enumeration members can speci fy associated values of any type to be
stored along wi th each di fferent member value, much as unions or variants do in other
languages. You can define a common set of related members as part of one enumeration,
each of whi ch has a di fferent set of values of appropriate types associated wi th i t.
Enumerations in Swi ft are fi rst-class types in thei r own right. They adopt many features
tradi tional ly supported only by classes, such as computed properties to provide addi tional
information about the enumeration’s current value, and instance methods to provide
functional i ty related to the values the enumeration represents. Enumerations can al so
define ini tial i zers to provide an ini tial member value; can be extended to expand thei r
functional i ty beyond thei r original implementation; and can conform to protocol s to
provide standard functional i ty.
For more on these capabi l i ties, see Properties, Methods, Ini tial i zation, Extensions, and
Protocol s.
Enumeration Syntax
You introduce enumerations wi th the enum keyword and place thei r enti re defini tion wi thin
a pai r of braces:
enum SomeEnumerati on {
// enumerati on defi ni ti on goes here
}
Here’s an example for the four main points of a compass:
enum CompassPoi nt {
case North
case South
case East
case West
}
The values defined in an enumeration (such as North, South, East, and West) are the member
values (or members) of that enumeration. The case keyword indi cates that a new l ine of
member values i s about to be defined.
N O T E
Unl i ke C and Objecti ve-C, Sw i ft enumerati on members are not assi gned a defaul t i nteger val ue w hen they are
created. In the CompassPoi nts exampl e above, North, South, East and West do not i mpl i ci tl y equal 0, 1, 2
and 3. Instead, the di fferent enumerati on members are ful l y- fl edged val ues i n thei r ow n ri ght, w i th an
expl i ci tl y-defi ned type of CompassPoi nt.
Mul tiple member values can appear on a single l ine, separated by commas:
enum Pl anet {
case Mercury, Venus, Earth, Mars, Jupi ter, Saturn, Uranus, Neptune
}
Each enumeration defini tion defines a brand new type. Like other types in Swi ft, thei r
names (such as CompassPoi nt and Pl anet) should start wi th a capi tal letter. Give enumeration
types singular rather than plural names, so that they read as sel f-evident:
var di recti onT oHead = CompassPoi nt.West
The type of di recti onT oHead i s inferred when i t i s ini tial i zed wi th one of the possible values of
CompassPoi nt. Once di recti onT oHead i s declared as a CompassPoi nt, you can set i t to a di fferent
CompassPoi nt value using a shorter dot syntax:
di recti onT oHead = . East
The type of di recti onT oHead i s al ready known, and so you can drop the type when setting i ts
value. Thi s makes for highly readable code when working wi th expl i ci tly-typed
enumeration values.
Matching Enumeration Values with a Switch Statement
You can match individual enumeration values wi th a sw i tch statement:
di recti onT oHead = . South
sw i tch di recti onT oHead {
case . North:
pri ntl n("Lots of pl anets have a north")
case . South:
pri ntl n("Watch out for pengui ns")
case . East:
pri ntl n("Where the sun ri ses")
case .West:
ri ntl n("Where the ski es are bl ue")
i nts "Watch out for pengui ns"
You can read thi s code as:
“Consider the value of di recti onT oHead. In the case where i t equal s . North, print "Lots of pl anets
have a north". In the case where i t equal s . South, print "Watch out for pengui ns".”
…and so on.
As described in Control Flow, a sw i tch statement must be exhaustive when considering an
enumeration’s members. If the case for .West i s omi tted, thi s code does not compi le,
because i t does not consider the complete l i st of CompassPoi nt members. Requi ring
exhaustiveness ensures that enumeration members are not accidental ly omi tted.
When i t i s not appropriate to provide a case for every enumeration member, you can
provide a defaul t case to cover any members that are not addressed expl i ci tly:
l et somePl anet = Pl anet. Earth
sw i tch somePl anet {
case . Earth:
pri ntl n("Mostl y harml ess")
defaul t:
pri ntl n("Not a safe pl ace for humans")
}
// pri nts "Mostl y harml ess"
Associated Values
The examples in the previous section show how the members of an enumeration are a
defined (and typed) value in thei r own right. You can set a constant or variable to
Pl anet. Earth, and check for thi s value later. However, i t i s sometimes useful to be able to
store associated values of other types alongside these member values. Thi s enables you
to store addi tional custom information along wi th the member value, and permi ts thi s
information to vary each time you use that member in your code.
You can define Swi ft enumerations to store associated values of any given type, and the
value types can be di fferent for each member of the enumeration i f needed.
Enumerations simi lar to these are known as di scriminated unions, tagged unions, or
variants in other programming languages.
For example, suppose an inventory tracking system needs to track products by two
di fferent types of barcode. Some products are labeled wi th 1D barcodes in UPC-A format,
whi ch uses the numbers 0 to 9. Each barcode has a “number system” digi t, fol lowed by
ten “identi fier” digi ts. These are fol lowed by a “check” digi t to veri fy that the code has
been scanned correctly:
Other products are labeled wi th 2D barcodes in QR code format, whi ch can use any ISO
8859-1 character and can encode a string up to 2,953 characters long:
It would be convenient for an inventory tracking system to be able to store UPC-A
barcodes as a tuple of three integers, and QR code barcodes as a string of any length.
In Swi ft, an enumeration to define product barcodes of ei ther type might look l ike thi s:
enum Barcode {
case UPCA(Int, Int, Int)
case QRCode(Stri ng)
}
Thi s can be read as:
“Define an enumeration type cal led Barcode, whi ch can take ei ther a value of UPCA wi th an
associated value of type (Int, Int, Int), or a value of QRCode wi th an associated value of type
Stri ng.”
Thi s defini tion does not provide any actual Int or Stri ng values—i t just defines the type of
associated values that Barcode constants and variables can store when they are equal to
Barcode. UPCA or Barcode.QRCode.
New barcodes can then be created using ei ther type:
var productBarcode = Barcode. UPCA(8, 85909_51226, 3)
Thi s example creates a new variable cal led productBarcode and assigns i t a value of
Barcode. UPCA wi th an associated tuple value of (8, 8590951226, 3). The provided “identi fier”
value has an underscore wi thin i ts integer l i teral—85909_51226—to make i t easier to read as
a barcode.
The same product can be assigned a di fferent type of barcode:
productBarcode = .QRCode("ABCDEFGHIJKLMNOP")
At thi s point, the original Barcode. UPCA and i ts integer values are replaced by the new
Barcode.QRCode and i ts string value. Constants and variables of type Barcode can store ei ther a
. UPCA or a .QRCode (together wi th thei r associated values), but they can only store one of
them at any given time.
The di fferent barcode types can be checked using a swi tch statement, as before. Thi s
time, however, the associated values can be extracted as part of the swi tch statement.
You extract each associated value as a constant (wi th the l et prefix) or a variable (wi th
the var prefix) for use wi thin the sw i tch case’s body:
sw i tch productBarcode {
case . UPCA(l et numberSystem, l et i denti fi er, l et check):
pri ntl n("UPC-A w i th val ue of \(numberSystem), \(i denti fi er), \(check). ")
case .QRCode(l et productCode):
pri ntl n("QR code w i th val ue of \(productCode). ")
}
// pri nts "QR code w i th val ue of ABCDEFGHIJKLMNOP. "
If al l of the associated values for a enumeration member are extracted as constants, or i f
al l are extracted as variables, you can place a single var or l et annotation before the
member name, for brevi ty:
sw i tch productBarcode {
case l et . UPCA(numberSystem, i denti fi er, check):
pri ntl n("UPC-A w i th val ue of \(numberSystem), \(i denti fi er), \(check). ")
case l et .QRCode(productCode):
pri ntl n("QR code w i th val ue of \(productCode). ")
}
// pri nts "QR code w i th val ue of ABCDEFGHIJKLMNOP. "
Raw Values
The barcode example in Associated Values shows how members of an enumeration can
declare that they store associated values of di fferent types. As an al ternative to
associated values, enumeration members can come prepopulated wi th defaul t values
(cal led raw values), whi ch are al l of the same type.
Here’s an example that stores raw ASCII values alongside named enumeration members:
enum ASCIIControl Character: Character {
case T ab = "\t"
case Li neFeed = "¶
"
case Carri ageReturn = "\r"
}
Here, the raw values for an enumeration cal led ASCIIControl Character are defined to be of type
Character, and are set to some of the more common ASCII control characters. Character
values are described in Strings and Characters.
Note that raw values are not the same as associated values. Raw values are set to
prepopulated values when you fi rst define the enumeration in your code, l ike the three
ASCII codes above. The raw value for a parti cular enumeration member i s always the
same. Associated values are set when you create a new constant or variable based on
one of the enumeration’s members, and can be di fferent each time you do so.
Raw values can be strings, characters, or any of the integer or floating-point number
types. Each raw value must be unique wi thin i ts enumeration declaration. When integers
are used for raw values, they auto-increment i f no value i s speci fied for some of the
enumeration members.
The enumeration below i s a refinement of the earl ier Pl anet enumeration, wi th raw integer
values to represent each planet’s order from the sun:
enum Pl anet: Int {
case Mercury = 1, Venus, Earth, Mars, Jupi ter, Saturn, Uranus, Neptune
}
Auto-incrementation means that Pl anet. Venus has a raw value of 2, and so on.
Access the raw value of an enumeration member wi th i ts toRaw method:
l et earthsOrder = Pl anet. Earth. toRaw ()
// earthsOrder i s 3
Use an enumeration’s fromRaw method to try to find an enumeration member wi th a
parti cular raw value. Thi s example identi fies Uranus from i ts raw value of 7:
l et possi bl ePl anet = Pl anet. fromRaw (7)
// possi bl ePl anet i s of type Pl anet? and equal s Pl anet. Uranus
Not al l possible Int values wi l l find a matching planet, however. Because of thi s, the
fromRaw method returns an optional enumeration member. In the example above,
possi bl ePl anet i s of type Pl anet?, or “optional Pl anet.”
If you try to find a Planet wi th a posi tion of 9, the optional Pl anet value returned by fromRaw
wi l l be ni l :
l et posi ti onT oFi nd = 9
i f l et somePl anet = Pl anet. fromRaw (posi ti onT oFi nd) {
sw i tch somePl anet {
case . Earth:
pri ntl n("Mostl y harml ess")
defaul t:
pri ntl n("Not a safe pl ace for humans")
}
} el se {
ri ntl n("T here i sn't a pl anet at posi ti on \(posi ti onT oFi nd)")
i nts "T here i sn't a pl anet at posi ti on 9"
Thi s example uses optional binding to try to access a planet wi th a raw value of 9. The
statement i f l et somePl anet = Pl anet. fromRaw (9) retrieves an optional Pl anet, and sets somePl anet to
the contents of that optional Pl anet i f i t can be retrieved. In thi s case, i t i s not possible to
retrieve a planet wi th a posi tion of 9, and so the el se branch i s executed instead.
chapter11
# 11 클래스와 구조체 (Classes and Structures)
> Translator : 이름 (메일주소)


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

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

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

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

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

더 많은 정보를 원하신다면 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` 프로퍼티에도 접근할수 있습니다.
chapter12
# 12 속성 (Properties)
> Translator : 이름 (메일주소)


Properties
Properties associate values wi th a parti cular class, structure, or enumeration. Stored
properties store constant and variable values as part of an instance, whereas computed
properties cal culate (rather than store) a value. Computed properties are provided by
classes, structures, and enumerations. Stored properties are provided only by classes and
structures.
Stored and computed properties are usual ly associated wi th instances of a parti cular
type. However, properties can al so be associated wi th the type i tsel f. Such properties are
known as type properties.
In addi tion, you can define property observers to moni tor changes in a property’s value,
whi ch you can respond to wi th custom actions. Property observers can be added to stored
properties you define yoursel f, and al so to properties that a subclass inheri ts from i ts
superclass.
Stored Properties
In i ts simplest form, a stored property i s a constant or variable that i s stored as part of an
instance of a parti cular class or structure. Stored properties can be ei ther variable stored
properties (introduced by the var keyword) or constant stored properties (introduced by
the l et keyword).
You can provide a defaul t value for a stored property as part of i ts defini tion, as described
in Defaul t Property Values. You can al so set and modi fy the ini tial value for a stored
property during ini tial i zation. Thi s i s true even for constant stored properties, as
described in Modi fying Constant Properties During Ini tial i zation.
The example below defines a structure cal led Fi xedLengthRange, whi ch describes a range of
integers whose range length cannot be changed once i t i s created:
struct Fi xedLengthRange {
var fi rstVal ue: Int
l et l ength: Int
}
var rangeOfT hreeItems = Fi xedLengthRange(fi rstVal ue: 0, l ength: 3)
// the range represents i nteger val ues 0, 1, and 2
rangeOfT hreeItems. fi rstVal ue = 6
// the range now represents i nteger val ues 6, 7, and 8
Instances of Fi xedLengthRange have a variable stored property cal led fi rstVal ue and a constant
stored property cal led l ength. In the example above, l ength i s ini tial i zed when the new range
i s created and cannot be changed thereafter, because i t i s a constant property.
Stored Properties of Constant Structure Instances
If you create an instance of a structure and assign that instance to a constant, you cannot
modi fy the instance’s properties, even i f they were declared as variable properties:
l et rangeOfFourItems = Fi xedLengthRange(fi rstVal ue: 0, l ength: 4)
// thi s range represents i nteger val ues 0, 1, 2, and 3
rangeOfFourItems. fi rstVal ue = 6
// thi s w i l l report an error, even thought fi rstVal ue i s a vari abl e property
Because rangeOfFourItems i s declared as a constant (wi th the l et keyword), i t i s not possible
to change i ts fi rstVal ue property, even though fi rstVal ue i s a variable property.
Thi s behavior i s due to structures being value types. When an instance of a value type i s
marked as a constant, so are al l of i ts properties.
The same i s not true for classes, whi ch are reference types. If you assign an instance of a
reference type to a constant, you can sti l l change that instance’s variable properties.
Lazy Stored Properties
A lazy stored property i s a property whose ini tial value i s not cal culated unti l the fi rst time
i t i s used. You indi cate a lazy stored property by wri ting the @l azy attribute before i ts
declaration.
N O T E
Y ou must al w ays decl are a l azy property as a vari abl e (w i th the var keyw ord), because i ts i ni ti al val ue may not
be retri eved unti l after i nstance i ni ti al i zati on compl etes. Constant properti es must al w ays have a val ue before
i ni ti al i zati on compl etes, and therefore cannot be decl ared as l azy.
Lazy properties are useful when the ini tial value for a property i s dependent on outside
factors whose values are not known unti l after an instance’s ini tial i zation i s complete.
Lazy properties are al so useful when the ini tial value for a property requi res complex or
computational ly expensive setup that should not be performed unless or unti l i t i s
needed.
The example below uses a lazy stored property to avoid unnecessary ini tial i zation of a
complex class. Thi s example defines two classes cal led DataImporter and DataManager, nei ther
of whi ch i s shown in ful l :
cl ass DataImporter {
/*
DataImporter i s a cl ass to i mport data from an external fi l e.
T he cl ass i s assumed to take a non- tri vi al amount of ti me to i ni ti al i ze.
*/
var fi l eName = "data. txt"
// the DataImporter cl ass w oul d provi de data i mporti ng functi onal i ty here
}
DataManager {
@l azy var i mporter = DataImporter()
ar data = Stri ng[]()
/ the DataManager cl ass w oul d provi de data management functi onal i ty here
manager = DataManager()
ager. data += "Some data"
ager. data += "Some more data"
e DataImporter i nstance for the i mporter property has not yet been created
The DataManager class has a stored property cal led data, whi ch i s ini tial i zed wi th a new,
empty array of Stri ng values. Al though the rest of i ts functional i ty i s not shown, the purpose
of thi s DataManager class i s to manage and provide access to thi s array of Stri ng data.
Part of the functional i ty of the DataManager class i s the abi l i ty to import data from a fi le.
Thi s functional i ty i s provided by the DataImporter class, whi ch i s assumed to take a non-
trivial amount of time to ini tial i ze. Thi s might be because a DataImporter instance needs to
open a fi le and read i ts contents into memory when the DataImporter instance i s ini tial i zed.
It i s possible for a DataManager instance to manage i ts data wi thout ever importing data
from a fi le, so there i s no need to create a new DataImporter instance when the DataManager
i tsel f i s created. Instead, i t makes more sense to create the DataImporter instance i f and
when i t i s fi rst used.
Because i t i s marked wi th the @l azy attribute, the DataImporter instance for the i mporter
property i s only created when the i mporter property i s fi rst accessed, such as when i ts
fi l eName property i s queried:
pri ntl n(manager. i mporter. fi l eName)
// the DataImporter i nstance for the i mporter property has now been created
// pri nts "data. txt"
Stored Properties and Instance Variables
If you have experience wi th Objective-C, you may know that i t provides two ways to store
values and references as part of a class instance. In addi tion to properties, you can use
instance variables as a backing store for the values stored in a property.
Swi ft uni fies these concepts into a single property declaration. A Swi ft property does not
have a corresponding instance variable, and the backing store for a property i s not
accessed di rectly. Thi s approach avoids confusion about how the value i s accessed in
di fferent contexts and simpl i fies the property’s declaration into a single, defini tive
statement. Al l information about the property—including i ts name, type, and memory
management characteri sti cs—i s defined in a single location as part of the type’s
defini tion.
Computed Properties
In addi tion to stored properties, classes, structures, and enumerations can define
computed properties, whi ch do not actual ly store a value. Instead, they provide a getter
and an optional setter to retrieve and set other properties and values indi rectly.
struct Poi nt {
var x = 0. 0, y = 0. 0
}
struct Si ze {
var w i dth = 0. 0, hei ght = 0. 0
}
struct Rect {
var ori gi n = Poi nt()
var si ze = Si ze()
ar center: Poi nt {
et {
l et centerX = ori gi n. x + (si ze.w i dth / 2)
l et centerY = ori gi n. y + (si ze. hei ght / 2)
return Poi nt(x: centerX, y: centerY )
et(new Center) {
ori gi n. x = new Center. x - (si ze.w i dth / 2)
ori gi n. y = new Center. y - (si ze. hei ght / 2)
square = Rect(ori gi n: Poi nt(x: 0. 0, y: 0. 0),
ze: Si ze(w i dth: 10. 0, hei ght: 10. 0))
i ti al SquareCenter = square. center
re. center = Poi nt(x: 15. 0, y: 15. 0)
("square. ori gi n i s now at (\(square. ori gi n. x), \(square. ori gi n. y))")
i nts "square. ori gi n i s now at (10. 0, 10. 0)"
Thi s example defines three structures for working wi th geometri c shapes:
The Rect structure al so provides a computed property cal led center. The current center
Poi nt encapsulates an (x, y) coordinate.
Si ze encapsulates a w i dth and a hei ght.
Rect defines a rectangle by an origin point and a si ze.
posi tion of a Rect can always be determined from i ts ori gi n and si ze, and so you don’t need to
store the center point as an expl i ci t Poi nt value. Instead, Rect defines a custom getter and
setter for a computed variable cal led center, to enable you to work wi th the rectangle’s
center as i f i t were a real stored property.
The preceding example creates a new Rect variable cal led square. The square variable i s
ini tial i zed wi th an origin point of (0, 0), and a width and height of 10. Thi s square i s
represented by the blue square in the diagram below.
The square variable’s center property i s then accessed through dot syntax (square. center), whi ch
causes the getter for center to be cal led, to retrieve the current property value. Rather than
returning an exi sting value, the getter actual ly cal culates and returns a new Poi nt to
represent the center of the square. As can be seen above, the getter correctly returns a
center point of (5, 5).
The center property i s then set to a new value of (15, 15), whi ch moves the square up and to
the right, to the new posi tion shown by the orange square in the diagram below. Setting
the center property cal l s the setter for center, whi ch modi fies the x and y values of the stored
ori gi n property, and moves the square to i ts new posi tion.
Shorthand Setter Declaration
If a computed property’s setter does not define a name for the new value to be set, a
defaul t name of new Val ue i s used. Here’s an al ternative version of the Rect structure, whi ch
takes advantage of thi s shorthand notation:
struct Al ternati veRect {
var ori gi n = Poi nt()
var si ze = Si ze()
var center: Poi nt {
get {
l et centerX = ori gi n. x + (si ze.w i dth / 2)
l et centerY = ori gi n. y + (si ze. hei ght / 2)
return Poi nt(x: centerX, y: centerY )
}
et {
ori gi n. x = new Val ue. x - (si ze.w i dth / 2)
ori gi n. y = new Val ue. y - (si ze. hei ght / 2)
Read-Only Computed Properties
A computed property wi th a getter but no setter i s known as a read-only computed
property. A read-only computed property always returns a value, and can be accessed
through dot syntax, but cannot be set to a di fferent value.
N O T E
Y ou must decl are computed properti es—i ncl udi ng read-onl y computed properti es—as vari abl e properti es w i th
the var keyw ord, because thei r val ue i s not fi xed. T he l et keyw ord i s onl y used for constant properti es, to
i ndi cate that thei r val ues cannot be changed once they are set as part of i nstance i ni ti al i zati on.
You can simpl i fy the declaration of a read-only computed property by removing the get
keyword and i ts braces:
struct Cuboi d {
var w i dth = 0. 0, hei ght = 0. 0, depth = 0. 0
var vol ume: Doubl e {
return w i dth * hei ght * depth
}
}
l et fourByFi veByT w o = Cuboi d(w i dth: 4. 0, hei ght: 5. 0, depth: 2. 0)
pri ntl n("the vol ume of fourByFi veByT w o i s \(fourByFi veByT w o. vol ume)")
// pri nts "the vol ume of fourByFi veByT w o i s 40. 0"
Thi s example defines a new structure cal led Cuboi d, whi ch represents a 3D rectangular box
wi th w i dth, hei ght, and depth properties. Thi s structure al so has a read-only computed
property cal led vol ume, whi ch cal culates and returns the current volume of the cuboid. It
doesn’t make sense for vol ume to be settable, because i t would be ambiguous as to whi ch
values of w i dth, hei ght, and depth should be used for a parti cular vol ume value. Nonetheless, i t
i s useful for a Cuboi d to provide a read-only computed property to enable external users to
di scover i ts current cal culated volume.
Property Observers
Property observers observe and respond to changes in a property’s value. Property
observers are cal led every time a property’s value i s set, even i f the new value i s the
same as the property’s current value.
You can add property observers to any stored properties you define, apart from lazy
stored properties. You can al so add property observers to any inheri ted property
(whether stored or computed) by overriding the property wi thin a subclass. Property
overriding i s described in Overriding.
N O T E
Y ou don’t need to defi ne property observers for non-overri dden computed properti es, because you can
observe and respond to changes to thei r val ue from di rectl y w i thi n the computed property’s setter.
You have the option to define ei ther or both of these observers on a property:
w i l l Set i s cal led just before the value i s stored.
di dSet i s cal led immediately after the new value i s stored.
If you implement a w i l l Set observer, i t i s passed the new property value as a constant
parameter. You can speci fy a name for thi s parameter as part of your w i l l Set
implementation. If you choose not to wri te the parameter name and parentheses wi thin
your implementation, the parameter wi l l sti l l be made avai lable wi th a defaul t parameter
name of new Val ue.
Simi larly, i f you implement a di dSet observer, i t wi l l be passed a constant parameter
containing the old property value. You can name the parameter i f you wi sh, or use the
defaul t parameter name of ol dVal ue.
N O T E
w i l l Set and di dSet observers are not cal l ed w hen a property i s fi rst i ni ti al i zed. T hey are onl y cal l ed w hen the
property’s val ue i s set outsi de of an i ni ti al i zati on context.
Here’s an example of w i l l Set and di dSet in action. The example below defines a new class
cal led StepCounter, whi ch tracks the total number of steps that a person takes whi le
walking. Thi s class might be used wi th input data from a pedometer or other step counter
to keep track of a person’s exerci se during thei r dai ly routine.
cl ass StepCounter {
var total Steps: Int = 0 {
w i l l Set(new T otal Steps) {
pri ntl n("About to set total Steps to \(new T otal Steps)")
}
di dSet {
i f total Steps > ol dVal ue {
pri ntl n("Added \(total Steps - ol dVal ue) steps")
}
tepCounter = StepCounter()
Counter. total Steps = 200
bout to set total Steps to 200
dded 200 steps
Counter. total Steps = 360
bout to set total Steps to 360
dded 160 steps
Counter. total Steps = 896
bout to set total Steps to 896
dded 536 steps
The StepCounter class declares a total Steps property of type Int. Thi s i s a stored property wi th
w i l l Set and di dSet observers.
The w i l l Set and di dSet observers for total Steps are cal led whenever the property i s assigned a
new value. Thi s i s true even i f the new value i s the same as the current value.
Thi s example’s w i l l Set observer uses a custom parameter name of new T otal Steps for the
upcoming new value. In thi s example, i t simply prints out the value that i s about to be
set.
The di dSet observer i s cal led after the value of total Steps i s updated. It compares the new
value of total Steps against the old value. If the total number of steps has increased, a
message i s printed to indi cate how many new steps have been taken. The di dSet observer
does not provide a custom parameter name for the old value, and the defaul t name of
ol dVal ue i s used instead.
N O T E
If you assi gn a val ue to a property w i thi n i ts ow n di dSet observer, the new val ue that you assi gn w i l l repl ace
the one that w as just set.
Global and Local Variables
The capabi l i ties described above for computing and observing properties are al so
avai lable to global variables and local variables. Global variables are variables that are
defined outside of any function, method, closure, or type context. Local variables are
variables that are defined wi thin a function, method, or closure context.
The global and local variables you have encountered in previous chapters have al l been
stored variables. Stored variables, l ike stored properties, provide storage for a value of a
certain type and al low that value to be set and retrieved.
However, you can al so define computed variables and define observers for stored
variables, in ei ther a global or local scope. Computed variables cal culate rather than store
a value, and are wri tten in the same way as computed properties.
N O T E
Gl obal constants and vari abl es are al w ays computed l azi l y, i n a si mi l ar manner to Lazy Stored Properti es. Unl i ke
l azy stored properti es, gl obal constants and vari abl es do not need to be marked w i th the @l azy attri bute.
Local constants and vari abl es are never computed l azi l y.
Type Properties
Instance properties are properties that belong to an instance of a parti cular type. Every
time you create a new instance of that type, i t has i ts own set of property values,
separate from any other instance.
You can al so define properties that belong to the type i tsel f, not to any one instance of
that type. There wi l l only ever be one copy of these properties, no matter how many
instances of that type you create. These kinds of properties are cal led type properties.
Type properties are useful for defining values that are universal to al l instances of a
parti cular type, such as a constant property that al l instances can use (l ike a stati c
constant in C), or a variable property that stores a value that i s global to al l instances of
that type (l ike a stati c variable in C).
For value types (that i s, structures and enumerations), you can define stored and
computed type properties. For classes, you can define computed type properties only.
Stored type properties for value types can be variables or constants. Computed type
properties are always declared as variable properties, in the same way as computed
instance properties.
N O T E
Unl i ke stored i nstance properti es, you must al w ays gi ve stored type properti es a defaul t val ue. T hi s i s because
the type i tsel f does not have an i ni ti al i zer that can assi gn a val ue to a stored type property at i ni ti al i zati on ti me.
Type Property Syntax
In C and Objective-C, you define stati c constants and variables associated wi th a type as
global stati c variables. In Swi ft, however, type properties are wri tten as part of the type’s
defini tion, wi thin the type’s outer curly braces, and each type property i s expl i ci tly scoped
to the type i t supports.
You define type properties for value types wi th the stati c keyword, and type properties for
class types wi th the cl ass keyword. The example below shows the syntax for stored and
computed type properties:
struct SomeStructure {
stati c var storedT ypeProperty = "Some val ue. "
stati c var computedT ypeProperty: Int {
// return an Int val ue here
}
}
enum SomeEnumerati on {
stati c var storedT ypeProperty = "Some val ue. "
stati c var computedT ypeProperty: Int {
/ return an Int val ue here
SomeCl ass {
ass var computedT ypeProperty: Int {
/ return an Int val ue here
N O T E
T he computed type property exampl es above are for read-onl y computed type properti es, but you can al so
defi ne read-w ri te computed type properti es w i th the same syntax as for computed i nstance properti es.
Querying and Setting Type Properties
Type properties are queried and set wi th dot syntax, just l ike instance properties.
However, type properties are queried and set on the type, not on an instance of that
type. For example:
pri ntl n(SomeCl ass. computedT ypeProperty)
// pri nts "42"
pri ntl n(SomeStructure. storedT ypeProperty)
// pri nts "Some val ue. "
SomeStructure. storedT ypeProperty = "Another val ue. "
pri ntl n(SomeStructure. storedT ypeProperty)
// pri nts "Another val ue. "
The examples that fol low use two stored type properties as part of a structure that
model s an audio level meter for a number of audio channel s. Each channel has an integer
audio level between 0 and 10 inclusive.
The figure below i l lustrates how two of these audio channel s can be combined to model a
stereo audio level meter. When a channel ’s audio level i s 0, none of the l ights for that
channel are l i t. When the audio level i s 10, al l of the l ights for that channel are l i t. In thi s
figure, the left channel has a current level of 9, and the right channel has a current level
of 7:
The audio channel s described above are represented by instances of the Audi oChannel
structure:
struct Audi oChannel {
stati c l et threshol dLevel = 10
stati c var maxInputLevel ForAl l Channel s = 0
var currentLevel : Int = 0 {
di dSet {
i f currentLevel > Audi oChannel . threshol dLevel {
// cap the new audi o l evel to the threshol d l evel
currentLevel = Audi oChannel . threshol dLevel
}
i f currentLevel > Audi oChannel .maxInputLevel ForAl l Channel s {
// store thi s as the new overal l maxi mum i nput l evel
Audi oChannel .maxInputLevel ForAl l Channel s = currentLevel
}
The Audi oChannel structure defines two stored type properties to support i ts functional i ty.
The fi rst, threshol dLevel , defines the maximum threshold value an audio level can take. Thi s
i s a constant value of 10 for al l Audi oChannel instances. If an audio signal comes in wi th a
higher value than 10, i t wi l l be capped to thi s threshold value (as described below).
The second type property i s a variable stored property cal led maxInputLevel ForAl l Channel s. Thi s
keeps track of the maximum input value that has been received by any Audi oChannel
instance. It starts wi th an ini tial value of 0.
The Audi oChannel structure al so defines a stored instance property cal led currentLevel , whi ch
represents the channel ’s current audio level on a scale of 0 to 10.
The currentLevel property has a di dSet property observer to check the value of currentLevel
whenever i t i s set. Thi s observer performs two checks:
If the new value of currentLevel i s greater than the al lowed threshol dLevel , the property
observer caps currentLevel to threshol dLevel .
If the new value of currentLevel (after any capping) i s higher than any value
N O T E
In the fi rst of these tw o checks, the di dSet observer sets currentLevel to a di fferent val ue. T hi s does not,
how ever, cause the observer to be cal l ed agai n.
You can use the Audi oChannel structure to create two new audio channel s cal led l eftChannel and
ri ghtChannel , to represent the audio level s of a stereo sound system:
var l eftChannel = Audi oChannel ()
var ri ghtChannel = Audi oChannel ()
If you set the currentLevel of the left channel to 7, you can see that the maxInputLevel ForAl l Channel s
type property i s updated to equal 7:
l eftChannel . currentLevel = 7
pri ntl n(l eftChannel . currentLevel )
// pri nts "7"
pri ntl n(Audi oChannel .maxInputLevel ForAl l Channel s)
// pri nts "7"
If you try to set the currentLevel of the right channel to 11, you can see that the right
channel ’s currentLevel property i s capped to the maximum value of 10, and the
maxInputLevel ForAl l Channel s type property i s updated to equal 10:
ri ghtChannel . currentLevel = 11
pri ntl n(ri ghtChannel . currentLevel )
// pri nts "10"
pri ntl n(Audi oChannel .maxInputLevel ForAl l Channel s)
// pri nts "10"
chapter13
# 13 메서드 (Methods)
> Translator : 이름 (메일주소)


Methods
Methods are functions that are associated wi th a parti cular type. Classes, structures, and
enumerations can al l define instance methods, whi ch encapsulate speci fi c tasks and
functional i ty for working wi th an instance of a given type. Classes, structures, and
enumerations can al so define type methods, whi ch are associated wi th the type i tsel f.
Type methods are simi lar to class methods in Objective-C.
The fact that structures and enumerations can define methods in Swi ft i s a major
di fference from C and Objective-C. In Objective-C, classes are the only types that can
define methods. In Swi ft, you can choose whether to define a class, structure, or
enumeration, and sti l l have the flexibi l i ty to define methods on the type you create.
Instance Methods
Instance methods are functions that belong to instances of a parti cular class, structure, or
enumeration. They support the functional i ty of those instances, ei ther by providing ways
to access and modi fy instance properties, or by providing functional i ty related to the
instance’s purpose. Instance methods have exactly the same syntax as functions, as
described in Functions.
You wri te an instance method wi thin the opening and closing braces of the type i t
belongs to. An instance method has impl i ci t access to al l other instance methods and
properties of that type. An instance method can be cal led only on a speci fi c instance of
the type i t belongs to. It cannot be cal led in i solation wi thout an exi sting instance.
Here’s an example that defines a simple Counter class, whi ch can be used to count the
number of times an action occurs:
cl ass Counter {
var count = 0
func i ncrement() {
count++
}
func i ncrementBy(amount: Int) {
count += amount
}
func reset() {
count = 0
The Counter class defines three instance methods:
The Counter class al so declares a variable property, count, to keep track of the current
counter value.
You cal l instance methods wi th the same dot syntax as properties:
l et counter = Counter()
// the i ni ti al counter val ue i s 0
counter. i ncrement()
// the counter's val ue i s now 1
counter. i ncrementBy(5)
// the counter's val ue i s now 6
counter. reset()
// the counter's val ue i s now 0
Local and External Parameter Names for Methods
Function parameters can have both a local name (for use wi thin the function’s body) and
an external name (for use when cal l ing the function), as described in External Parameter
Names. The same i s true for method parameters, because methods are just functions
that are associated wi th a type. However, the defaul t behavior of local names and
external names i s di fferent for functions and methods.
Methods in Swi ft are very simi lar to thei r counterparts in Objective-C. As in Objective-C,
the name of a method in Swi ft typi cal ly refers to the method’s fi rst parameter using a
preposi tion such as w i th, for, or by, as seen in the i ncrementBy method from the preceding
i ncrement increments the counter by 1.
i ncrementBy(amount: Int) increments the counter by an speci fied integer amount.
reset resets the counter to zero.
Counter class example. The use of a preposi tion enables the method to be read as a
sentence when i t i s cal led. Swi ft makes thi s establ i shed method naming convention easy
to wri te by using a di fferent defaul t approach for method parameters than i t uses for
function parameters.
Speci fi cal ly, Swi ft gives the fi rst parameter name in a method a local parameter name by
defaul t, and gives the second and subsequent parameter names both local and external
parameter names by defaul t. Thi s convention matches the typi cal naming and cal l ing
convention you wi l l be fami l iar wi th from wri ting Objective-C methods, and makes for
expressive method cal l s wi thout the need to qual i fy your parameter names.
Consider thi s al ternative version of the Counter class, whi ch defines a more complex form of
the i ncrementBy method:
cl ass Counter {
var count: Int = 0
func i ncrementBy(amount: Int, numberOfT i mes: Int) {
count += amount * numberOfT i mes
}
}
Thi s i ncrementBy method has two parameters—amount and numberOfT i mes. By defaul t, Swi ft
treats amount as a local name only, but treats numberOfT i mes as both a local and an external
name. You cal l the method as fol lows:
l et counter = Counter()
counter. i ncrementBy(5, numberOfT i mes: 3)
// counter val ue i s now 15
You don’t need to define an external parameter name for the fi rst argument value,
because i ts purpose i s clear from the function name i ncrementBy. The second argument,
however, i s qual i fied by an external parameter name to make i ts purpose clear when the
method i s cal led.
Thi s defaul t behavior effectively treats the method as i f you had wri tten a hash symbol
(#) before the numberOfT i mes parameter:
func i ncrementBy(amount: Int, #numberOfT i mes: Int) {
count += amount * numberOfT i mes
}
The defaul t behavior described above mean that method defini tions in Swi ft are wri tten
wi th the same grammati cal style as Objective-C, and are cal led in a natural , expressive
way.
Modifying External Parameter Name Behavior for Methods
Sometimes i t’s useful to provide an external parameter name for a method’s fi rst
parameter, even though thi s i s not the defaul t behavior. You can ei ther add an expl i ci t
external name yoursel f, or you can prefix the fi rst parameter’s name wi th a hash symbol
to use the local name as an external name too.
Conversely, i f you do not want to provide an external name for the second or subsequent
parameter of a method, override the defaul t behavior by using an underscore character
(_) as an expl i ci t external parameter name for that parameter.
The self Property
Every instance of a type has an impl i ci t property cal led sel f, whi ch i s exactly equivalent to
the instance i tsel f. You use thi s impl i ci t sel f property to refer to the current instance wi thin
i ts own instance methods.
The i ncrement method in the example above could have been wri tten l ike thi s:
func i ncrement() {
sel f. count++
}
In practi ce, you don’t need to wri te sel f in your code very often. If you don’t expl i ci tly wri te
sel f, Swi ft assumes that you are referring to a property or method of the current instance
whenever you use a known property or method name wi thin a method. Thi s assumption
i s demonstrated by the use of count (rather than sel f. count) inside the three instance
methods for Counter.
The main exception to thi s rule occurs when a parameter name for an instance method
has the same name as a property of that instance. In thi s si tuation, the parameter name
takes precedence, and i t becomes necessary to refer to the property in a more qual i fied
way. You use the impl i ci t sel f property to di stingui sh between the parameter name and
the property name.
Here, sel f di sambiguates between a method parameter cal led x and an instance property
that i s al so cal led x:
struct Poi nt {
var x = 0. 0, y = 0. 0
func i sT oT heRi ghtOfX(x: Doubl e) -> Bool {
return sel f. x > x
}
}
l et somePoi nt = Poi nt(x: 4. 0, y: 5. 0)
i f somePoi nt. i sT oT heRi ghtOfX(1. 0) {
pri ntl n("T hi s poi nt i s to the ri ght of the l i ne w here x == 1. 0")
i nts "T hi s poi nt i s to the ri ght of the l i ne w here x == 1. 0"
Wi thout the sel f prefix, Swi ft would assume that both uses of x referred to the method
parameter cal led x.
Modifying Value Types from Within Instance Methods
Structures and enumerations are value types. By defaul t, the properties of a value type
cannot be modi fied from wi thin i ts instance methods.
However, i f you need to modi fy the properties of your structure or enumeration wi thin a
parti cular method, you can opt in to mutating behavior for that method. The method can
then mutate (that i s, change) i ts properties from wi thin the method, and any changes
that i t makes are wri tten back to the original structure when the method ends. The
method can al so assign a completely new instance to i ts impl i ci t sel f property, and thi s
new instance wi l l replace the exi sting one when the method ends.
You can opt in to thi s behavior by placing the mutati ng keyword before the func keyword for
that method:
struct Poi nt {
var x = 0. 0, y = 0. 0
mutati ng func moveByX(del taX: Doubl e, y del taY : Doubl e) {
x += del taX
y += del taY
}
}
var somePoi nt = Poi nt(x: 1. 0, y: 1. 0)
somePoi nt.moveByX(2. 0, y: 3. 0)
("T he poi nt i s now at (\(somePoi nt. x), \(somePoi nt. y))")
i nts "T he poi nt i s now at (3. 0, 4. 0)"
The Poi nt structure above defines a mutating moveByX method, whi ch moves a Poi nt instance
by a certain amount. Instead of returning a new point, thi s method actual ly modi fies the
point on whi ch i t i s cal led. The mutati ng keyword i s added to i ts defini tion to enable i t to
modi fy i ts properties.
Note that you cannot cal l a mutating method on a constant of structure type, because i ts
properties cannot be changed, even i f they are variable properties, as described in Stored
Properties of Constant Structure Instances:
l et fi xedPoi nt = Poi nt(x: 3. 0, y: 3. 0)
fi xedPoi nt.moveByX(2. 0, y: 3. 0)
// thi s w i l l report an error
Assigning to self Within a Mutating Method
Mutating methods can assign an enti rely new instance to the impl i ci t sel f property. The
Poi nt example shown above could have been wri tten in the fol lowing way instead:
struct Poi nt {
var x = 0. 0, y = 0. 0
mutati ng func moveByX(del taX: Doubl e, y del taY : Doubl e) {
sel f = Poi nt(x: x + del taX, y: y + del taY )
}
}
Thi s version of the mutating moveByX method creates a brand new structure whose x and y
values are set to the target location. The end resul t of cal l ing thi s al ternative version of
the method wi l l be exactly the same as for cal l ing the earl ier version.
Mutating methods for enumerations can set the impl i ci t sel f parameter to be a di fferent
member from the same enumeration:
enum T ri StateSw i tch {
case Off, Low , Hi gh
mutati ng func next() {
sw i tch sel f {
case Off:
sel f = Low
case Low :
sel f = Hi gh
case Hi gh:
sel f = Off
}
ovenLi ght = T ri StateSw i tch. Low
nLi ght. next()
venLi ght i s now equal to . Hi gh
nLi ght. next()
venLi ght i s now equal to .Off
Thi s example defines an enumeration for a three-state swi tch. The swi tch cycles between
three di fferent power states (Off, Low and Hi gh) every time i ts next method i s cal led.
Type Methods
Instance methods, as described above, are methods that are cal led on an instance of a
parti cular type. You can al so define methods that are cal led on the type i tsel f. These
kinds of methods are cal led type methods. You indi cate type methods for classes by
wri ting the keyword cl ass before the method’s func keyword, and type methods for
structures and enumerations by wri ting the keyword stati c before the method’s func
keyword.
N O T E
In Objecti ve-C, you can defi ne type- l evel methods onl y for Objecti ve-C cl asses. In Sw i ft, you can defi ne typel evel methods for al l cl asses, structures, and enumerati ons. Each type method i s expl i ci tl y scoped to the type
i t supports.
Type methods are cal led wi th dot syntax, l ike instance methods. However, you cal l type
methods on the type, not on an instance of that type. Here’s how you cal l a type method
on a class cal led SomeCl ass:
cl ass SomeCl ass {
cl ass func someT ypeMethod() {
// type method i mpl ementati on goes here
}
}
SomeCl ass. someT ypeMethod()
Wi thin the body of a type method, the impl i ci t sel f property refers to the type i tsel f, rather
than an instance of that type. For structures and enumerations, thi s means that you can
use sel f to di sambiguate between stati c properties and stati c method parameters, just as
you do for instance properties and instance method parameters.
More general ly, any unqual i fied method and property names that you use wi thin the body
of a type method wi l l refer to other type-level methods and properties. A type method
can cal l another type method wi th the other method’s name, wi thout needing to prefix i t
wi th the type name. Simi larly, type methods on structures and enumerations can access
stati c properties by using the stati c property’s name wi thout a type name prefix.
The example below defines a structure cal led Level T racker, whi ch tracks a player’s progress
through the di fferent level s or stages of a game. It i s a single-player game, but can store
information for mul tiple players on a single devi ce.
Al l of the game’s level s (apart from level one) are locked when the game i s fi rst played.
Every time a player fini shes a level , that level i s unlocked for al l players on the devi ce.
The Level T racker structure uses stati c properties and methods to keep track of whi ch level s
of the game have been unlocked. It al so tracks the current level for an individual player.
struct Level T racker {
stati c var hi ghestUnl ockedLevel = 1
stati c func unl ockLevel (l evel : Int) {
i f l evel > hi ghestUnl ockedLevel { hi ghestUnl ockedLevel = l evel }
}
stati c func l evel IsUnl ocked(l evel : Int) -> Bool {
return l evel <= hi ghestUnl ockedLevel
}
var currentLevel = 1
mutati ng func advanceT oLevel (l evel : Int) -> Bool {
i f Level T racker. l evel IsUnl ocked(l evel ) {
currentLevel = l evel
return true
} el se {
return fal se
}
The Level T racker structure keeps track of the highest level that any player has unlocked.
Thi s value i s stored in a stati c property cal led hi ghestUnl ockedLevel .
Level T racker al so defines two type functions to work wi th the hi ghestUnl ockedLevel property. The
fi rst i s a type function cal led unl ockLevel , whi ch updates the value of hi ghestUnl ockedLevel
whenever a new level i s unlocked. The second i s a convenience type function cal led
l evel IsUnl ocked, whi ch returns true i f a parti cular level number i s al ready unlocked. (Note that
these type methods can access the hi ghestUnl ockedLevel stati c property wi thout your needing
to wri te i t as Level T racker. hi ghestUnl ockedLevel .)
In addi tion to i ts stati c property and type methods, Level T racker tracks an individual player’s
progress through the game. It uses an instance property cal led currentLevel to track the level
that a player i s currently playing.
To help manage the currentLevel property, Level T racker defines an instance method cal led
advanceT oLevel . Before updating currentLevel , thi s method checks whether the requested new
level i s al ready unlocked. The advanceT oLevel method returns a Boolean value to indi cate
whether or not i t was actual ly able to set currentLevel .
The Level T racker structure i s used wi th the Pl ayer class, shown below, to track and update the
progress of an individual player:
cl ass Pl ayer {
var tracker = Level T racker()
l et pl ayerName: Stri ng
func compl etedLevel (l evel : Int) {
Level T racker. unl ockLevel (l evel + 1)
tracker. advanceT oLevel (l evel + 1)
}
i ni t(name: Stri ng) {
pl ayerName = name
The Pl ayer class creates a new instance of Level T racker to track that player’s progress. It al so
provides a method cal led compl etedLevel , whi ch i s cal led whenever a player completes a
parti cular level . Thi s method unlocks the next level for al l players and updates the
player’s progress to move them to the next level . (The Boolean return value of
advanceT oLevel i s ignored, because the level i s known to have been unlocked by the cal l to
Level T racker. unl ockLevel on the previous l ine.)
You can create a instance of the Pl ayer class for a new player, and see what happens when
the player completes level one:
var pl ayer = Pl ayer(name: "Argyri os")
pl ayer. compl etedLevel (1)
pri ntl n("hi ghest unl ocked l evel i s now \(Level T racker. hi ghestUnl ockedLevel )")
// pri nts "hi ghest unl ocked l evel i s now 2"
If you create a second player, whom you try to move to a level that i s not yet unlocked
by any player in the game, the attempt to set the player’s current level fai l s:
pl ayer = Pl ayer(name: "Beto")
i f pl ayer. tracker. advanceT oLevel (6) {
pri ntl n("pl ayer i s now on l evel 6")
} el se {
pri ntl n("l evel 6 has not yet been unl ocked")
}
// pri nts "l evel 6 has not yet been unl ocked"
chapter14
# 14 서브 스크립트 (Subscripts)
> Translator : 이름 (메일주소)


Class, Structures, 그리고 enumeratione의 경우 subscripts을 통해서 정의할 수 있습니다.
subscripts는 collection, list, sequence의 memberelements에 접근하기 위한 일종의 바로가기입니다. 또한 subscirpts를 사용하면 추가적인 method들을 사용하지 않고도 값을 지정하거나 검색할 수 있습니다. 예를들어서 someArray[index] 나 someDictionary[key]를 사용하여 값에 접근할 수 있습니다.

한 타입을 위해서 여러개의 subscript를 선언할 수도 있고, 또한 적절한 subscript overload의 사용은 subscript로 넘기는 index value의 type을 기본으로 하여 선택된다.
subscripts는 1차원에 제한되지 않고, 당신의 원하는 타입 형태에 따라서 다수의 input parameter를 가진 subscripts를 선언할 수 있습니다.

Subscript 문법
Subscripts는 당신이 instance의 이름 뒤에 한개 혹은 그 이상의 '[ ]'를 통해서 instance의 타입을 요청을 할수 있게 해줍니다. 그들의 문법은 instance method와 computed property의 문법과 유사합니다. subscript 선언들은 instance method와 유사하게 subscript 키워드와 특정한 하나 혹은 그 이상의 input parameter들과 return type으로 구성됩니다. 다만 instance method들과 달리 subscripts는 read-write이거나 read-only입니다.

다음 behavior는 subscript가 computed property들과 동일한 방식으로 getter와 setter를 통해 커뮤니케이션 하는 것을 보여줍니다.
/////
subscript(index: Int) -> Int {
get {
// return an appropriate subscript value here
}
set(newValue) {
// perform a suitable setting action here
}
}
/////
newValue의 type은 해당 subscript의 return 값과 동일합니다.
computed properties와 같이 당신은 setter의 parameter인 (newValue)를 특정하게 선택할수 없습니다. 만일 당신이 setter를 위한 타입을 아무것도 제공하지 않는다면, 그제서야 기본 parameter인 newValue가 setter를 위해 제공될 것입니다.

read-only computed properties와 같이 get 키워드를 빼서 read-only subscript를 만들 수 있다.:
/////
subscript(index: Int) -> Int {
// return an appropriate subscript value here
}
////
이곳에 정수의 n 배 표현을 하려는 TimesTable structure를 선언하기 을 위한 read-only subscript구현 예제가 하나 있습니다.
/////
struct TimesTable {
let multiplier: Int
subscript(index: Int) -> Int {
return multiplier * index
}
}
let threeTimesTable = TimesTable(multiplier: 3)
println("six times three is \(threeTimesTable[6])")
// prints "six times three is 18"
/////
이 예제에서 새로운 TimesTable instance는 3의 배수를 출력을 하도록 생성되고.
이것은 넘겨준 값인 3을 structure의 initializer가 instance의 multiplier parameter로 사용한 것을 의미합니다.
해당 subscript를 call하는 것으로 threeTimesTable instance 에게 요청할 수 있다.보는바와같이 threeTimesTable[6]과 같이 call하는 것으로 threeTimesTable instance의 subscript를 call할 수 있다. 해당 요청은 6의 3배 테이블을 요청했으며 그 값은 18=6*3 이 된다.

NOTE
n배 테이블은 고정된 숫자값을 출력하는 규칙에 기반합니다. 따라서 newValue등을 통하여 treeTimesTable[someindex]를 설정하는 것은 적절하지 않으며 그러기에 위의 TimesTable을 위한 subscript는 read-only subscript로 선언되었습니다.

Subscript Usage

아주 정확한 의미의 "subscript"는 그것이 사용되는 문맥에 따라 결정된다. Subscripts는 일반적으로 collection, list, 또는 sequence에 특정 member elements에 접근하기 위한 바로가기라는 의미로 사용되며. 당신은 당신의 particular class나 structure의기능을 위해 대부분의 적절한 방식으로 자유롭게 subscripts를 구현할 수있다.
예를 들어서 Swift의 Dictionary type은 Dictionary instance에 저장된 값들을 설정하고 retrieve하기 위한 하나의 subscript로 구현했다.
당신은 dictionary안에 dictionary의 key 타입의 key값을 subscript의 brace안에 넣는 것으로 값을 세팅할 수 있으며 dictionary안에 들어갈 값을 subscript에 할당할 수도 있다.
You can set a value in a dictionary by providing a key of the
dictionary’s key type within subscript braces, and assigning a value of the dictionary’s
value type to the subscript:
/////
var numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
numberOfLegs["bird"] = 2
/////
위 예제는 numberOfLegs라는 변수를 선언하고 이를 3가지 key-value 쌍을 가진 dictionary literal로 초기화 하고있다.
numberOfLegs dictionary의 타입은 Dictionary를 뜻하며. dictionary가 생성이 된 후, 이 예제는 subscript assignment을 사용하여 String key "bird"와 int 값인 2를 dictionary에 추가하는 것을 볼 수있다.
Dictionary subscripting에 관한 보다 많은 정보를 원한다면, Accessing and Modifying a Dicionary(link)를 참고하기 바란다.

NOTE
Swift의 Dictionary type은 내부적인 key-value subscripting 이 요구하고 반환하는 타입이 optional type인 subscript로 구현하였습니다. 위의 numberOfLegs dictionary를 보면, key-value subscript 요구하고 반환하는 타입이 Int일까요?, 그렇지 않으면 “optional int”일까요? Dictionary type은 '모든 키가 값을 가지는 것은 아니다'라는 사실을 위한 모델을 지원하는 optional subscript type을 사용합니다. 그리고 어떤 key에 value를 삭제하는 방법을 제공하는데, 이경우 해당 key값의 value는 nill로 할당된다.

Subscript Options

Subscripts은 어떠한 숫자의 input parameter들도 처리가 가능하다.그리고 그리고 이 input parameter들은 어떠한 타입도 가능하다. Subscripts는 또한 어떠한 타입으로도 return이 가능하다. Subscripts는 variable parameters와 variadic parameters도 가능하지만, in-out parameters 나 default parameter 값은 지원하지 않습니다.
class나 structure는 필요한 만큼의 subscript를 구현하는 것이 가능하며, 적절한 subscript는 보통각 subscript가 사용되는 요소요소에서 subscript에 포함된이 서로 대비하도록 한 값이나 값들의 타입이 기초라고 생각할 수 있습니다.
이러한 다수의 subscripts에 관한 정의는 subscript overloading으로도 알려져 있습니다.
대부분의 한개의 parameter만을 요구하는 subscript와는 다르게, 만일 네가 만들 것에 필요하다면, 다수의 parameter를 요구하는 subscript를 선언할 수도 있습니다.
다음 예제는 Double값을 가지는 2차원 matrix를 표현하는 Matrix라는 structure를 선언하고 있습니다. Matrix structure의 subscript는 두개의 integer parameter를 요구 하고 있습니다:
/////
struct Matrix {
let rows: Int, columns: Int
var grid: Double[]
init(rows: Int, columns: Int) {
self.rows = rows
self.columns = columns
grid = Array(count: rows * columns, repeatedValue: 0.0)
}
func indexIsValidForRow(row: Int, column: Int) -> Bool {
return row >= 0 && row < rows && column >= 0 && column < columns
subscript(row: Int, column: Int) -> Double {
get {
assert(indexIsValidForRow(row, column: column), "Index out of range")
return grid[(row * columns) + column]
}
set {
assert(indexIsValidForRow(row, column: column), "Index out of range")
grid[(row * columns) + column] = newValue
}
/////
Matrix는 rows 와 columns이라는 두개의 parameter를 요구하는 initializer 를 제공하며, Double type의 충분이 커서 rows * columns 만큼의 저장이 가능한 array를 생성합니다. 각 Matrix의 위치의 초기값은 0.0으로 주어지며. 이러한 작업이 모두 이루어 진 다음에는 만들어진 array를 array의 initializer로 보내서 올바른 크기의 array를 만듭니다. 이 initializer에 다한 자세한 사항은 Creating and Initializing an Array(링크)를 참고하세요.

이제 다음과 같은 방식으로 적절한 row와 column을 initializer에 넘기는 것으로 new Matrix instance를 생성할 수 있습니다.
/////
var matrix = Matrix(rows: 2, columns: 2)
/////
아래의 예제는 2x2의 크기를 가진 새로운 Matrix instance를 생성하는 예제입니다. matrix instace를 효과적으로 평평하게 펴서 보여주기 위한 grid array를 참고하면 왼쪽위에서부터 오른쪽 아래로 읽어 나가는 것을 볼 수 있습니다.
/////
(그림있음)
/////
matrix의 값을 넣을때는 ,를 이용해서 subscript에 맞는 형태로 값을 넘겨주면 세팅할 수 있습니다:
////
matrix[0, 1] = 1.5
matrix[1, 0] = 3.2
/////
이 두 문장은 우측 상단의 값([0, 1])을 1.5로, 좌측 하단의 값([1, 0])을 3.2로 설정합니다:
/////
(그림있음)
/////
Matrix의 subscript의 getter와 setter는 모두 올바른 row와 column값이 들어오는지 체크하는 assertion을 포함하고 있습니다. 이 assertion들을 돕기 위하여 Matrix는 자체적으로 indexIsValid라는 convenience method를 가지고 있으며 이는 주어진 값이 matrix의 범위를 넘어가는지 아닌지를 체크합니다:
func indexIsValidForRow(row: Int, column: Int) -> Bool {
return row >= 0 && row < rows && column >= 0 && column < columns
}
만일 matrix의 경계를 넘어가는 값이 subscript로 들어오게 된다면 assertion이 triggered됩니다:
let someValue = matrix[2, 2]
// this triggers an assert, because [2, 2] is outside of the matrix bounds



chapter15
# 15 상속 (Inheritance)
> Translator : 이름 (메일주소)


Write here...

chapter16
# 16 초기화 (Intialization)
> Translator : 이름 (메일주소)


Write here...
chapter17
# 17 해제 (Deinitialization)
> Translator : 이름 (메일주소)

deinitializer 는 임의의 class 인스턴스가 할당해제(deallocate) 되기 직전에 호출된다. initializer를 init 키워드 안에 기술했던 것처럼, deinitializer는 deinit 키워드 안에 적어 넣는다. deinitializer는 class 타입 인스턴스에서만 사용할 수 있다.

## Deinitialization (해제)의 원리

Swift에서는 더 이상 사용되지 않는 인스턴스는 자동으로 할당해제 된다. 이는 Automatic Reference Counting에서 설명한 바와 같이 ARC를 통해 이루어지는데, 일반적인 경우 사용자가 직접 메모리 사용을 할당해제할 필요가 없다. 하지만, 사용자의 인스턴스에서 직접 리소스를 할당하여 사용했다면, 해제할 때도 직접 해제해 주어야 한다. 가령, 사용자의 인스턴스에서 파일을 열어서 사용했다면, 해제할 때, 직접 파일을 닫아주어야 한다. class마다 오직 한 개의 deinitializer만을 사용할 수 있으며, 파라미터 없이 정의한다.

deinit {
// perform the deinitialization
}

deinitializer는 할당해제(deallocation)가 일어나기 직전에 자동으로 호출되기 때문에, 사용자가 직접 호출하는 것을 허용하지 않는다. subclass는 superclass의 deinitializer를 상속받기 때문에, subclass의 deinitializer가 호출되어 작업을 마친 후, superclass의 deinitializer가 자동으로 호출된다. superclass의 deinitializer는 subclass의 deinitializer가 정의되지 않았더라도 항상 호출된다. deinitializer가 아직 호출되지 않은 인스턴스는 해제(deallocation)가 되지 않은 상태이고, deinitializer는 자신이 속한 인스턴스의 모든 속성(가령, 닫아야할 파일의 이름과 상태)을 변경할 수 있다.

## Deinitializer 사용 예

deinitializer를 사용하는 간단한 예를 들어보자. 간단한 게임을 만들기 위해, Bank와 Player 라는 두개의 데이터 타입을 정의하기로 하자. Bank는 화폐를 만드는데, 최대 10,000개의 동전을 유통할 수 있다. 게임에서는 오직 한 개의 Bank만 있다고 가정, Bank는 static으로 구현되었다.

struct Bank {
static var coinsInBank = 10000
static func vendCoins(var numberOfCoinsToVend: Int) -> Int {
numberOfCoinsToVend = min(numberOfCoinsToVend, coinsInBank)
coinsInBank -= numberOfCoinsToVend
return numberOfCoinsToVend
}
static func receiveCoins(coins: Int) {
coinsInBank += coins
}

Bank클래스는 coinsInBank속성으로 현 상태의 동전 수를 유지한다. vendCoins과 receiveCoins 메소드는 동전을 인출하거나 예치할 때 사용한다.

vendCoins 메소드는 은행에 동전이 남아 있는지 확인하고 Player에게 인출을 허용한다. Player 가 요청한 것보다 동전이 적게 남아 있으면, 남아 있는 만큼만 인출할 수 있다. (물론 은행에 동전이 전혀 없다면, ‘0’ 를 리턴한다). numberOfCoinsToVend 변수는 파라미터로 입력받아 변경이 가능하게 만들었다. receiveCoins메소드는 단순히 Player가 예치하는 동전을 은행에 더해서 쌓도록 되어 있다.

Player 클래스를 보면, coinsInPurse 속성에 게임 플레이어가 현재 보유한 동전을 기록한다.

class Player {
var coinsInPurse: Int
init(coins: Int) {
coinsInPurse = Bank.vendCoins(coins)
}
func winCoins(coins: Int) {
coinsInPurse += Bank.vendCoins(coins)
}
deinit {
Bank.receiveCoins(coinsInPurse)
}
}

Player인스턴스는 은행으로부터 어느 정도의 동전을 받으면서 초기화된다. 경우에 따라서 은행에 충분한 코인이 남아 있지 않다면 요청한 만큼의 동전보다 적게 받을 수도 있다. winCoins 메소드는 은행에서 (coins : Int) 만큼의 동전을 받아 Player의 지갑에 더해 준다. Player클래스에는 deinitializer 가 정의되어 있는데, 앞서 설명한 바 처럼 Player 인스턴스가 해제(deallocate)되기 직전에 호출된다. 여기서는 단순히 플레이어가 가진 모든 동전을 다시 은행에 리턴하는 역할을 한다.


var playerOne: Player? = Player(coins: 100)
println("A new player has joined the game with \(playerOne!.coinsInPurse) coins")
// prints "A new player has joined the game with 100 coins"
println("There are now \(Bank.coinsInBank) coins left in the bank")
// prints "There are now 9900 coins left in the bank"


--> 요기서 부터 다시 재개


A new Player instance is created, with a request for 100 coins if they are available. This Player instance is stored in an optional Player variable called playerOne. An optional variable is used here, because players can leave the game at any point. The optional lets you track whether there is currently a player in the game.
Because playerOne is an optional, it is qualified with an exclamation mark (!) when its coinsInPurse property is accessed to print its default number of coins, and whenever its winCoins method is called:

playerOne!.winCoins(2000)
println("PlayerOne won 2000 coins & now has \(playerOne!.coinsInPurse) coins")
// prints "PlayerOne won 2000 coins & now has 2100 coins"
println("The bank now only has \(Bank.coinsInBank) coins left")
// prints "The bank now only has 7900 coins left"

Here, the player has won 2,000 coins. The player’s purse now contains 2,100 coins, and the bank has only 7,900 coins left.

playerOne = nil
println("PlayerOne has left the game")
// prints "PlayerOne has left the game"
println("The bank now has \(Bank.coinsInBank) coins")
// prints "The bank now has 10000 coins"

The player has now left the game. This is indicated by setting the optional playerOne variable to nil, meaning “no Player instance.” At the point that this happens, the playerOne variable’s reference to the Player instance is broken. No other properties or variables are still referring to the Player instance, and so it is deallocated in order to free up its memory.
Just before this happens, its deinitializer is called automatically, and its coins are returned to the bank.
chapter18
# 18 자동 참조 계수 (Automatic Reference Counting)
> Translator : 이름 (메일주소)


Write here...
chapter19
# 19 옵션 연쇄 (Optional Chaining)
> Translator : 이름 (메일주소)

Write here...
chapter2
# 02 Swift 둘러보기 (Swift Tour)
> Translator : 이름 (메일주소)


새로운 언어를 배울 때 첫번째 프로그램은 전통적으로 화면에 "Hello, world"란 구문을 출력해 보는 것입니다. Swift에서는 단 한줄로 이것이 가능합니다.

println("Hello, world")

C나 Objective-C에서 코드를 작성해본적이 있다면 Swift에서 이 한줄의 코드가 완전한 프로그램을 구성하는 이런 문법이 매우 익숙할 것입니다. 입.출력이나 문자열을 다루기 위한 함수들 같은 기능들을 위한 분리된 라이브러리를 임포트할 필요가 없습니다. 프로그램의 전체 지점에 있어서 코드는 전역 범위(Global scope)로 쓰여지고, 때문에 main 함수는 필요하지 않습니다. 또한 모든 문장끝에 세미콜론을 쓸 필요도 없습니다.

이 둘러보기는 다양한 프로그래밍 과제를 어떻게 완수해 나가는지 보여주면서 Swift로 어떻게 코드를 작성해야하는지에 대한 충분한 정보를 제공할 것입니다. 몇몇가지를 이해하지 못한다고 해서 걱정하지 마세요. 이번 장에서 소개되는 모든 것들은 책의 뒷 부분에서 자세히 설명될 것입니다.

` 노트
최선의 경험을 위해서 이번 장을 Xcode안에서 playground로 열어보세요. Playground는 코드의 수정과 즉시 결과를 볼 수 있도록 해줄 것입니다.

##간단한 값

let을 사용하면 상수를 만들고 var를 사용하면 변수를 만들 수 있습니다. 상수는 컴파일 타임에 알고 있을 필요가 없습니다. 그러나 오직 한번만 값을 할당해야합니다. 이것은 상수를 값을 한번만 결정하고 여러곳에 쓰일 이름으로 사용할 수 있다는 것을 의미합니다.

1| var myVariable =42
2| myVariable = 50
3| let myConstant = 42

상수나 변수 모두 당신이 할당하고 싶은 값의 타입을 가질 수 있습니다. 그러나 항상 타입을 명시해야만 하는 것은 아닙니다. 당신이 상수나 변수를 만들 때 할당한 값을 통해 컴파일러는 그 값의 타입을 추측합니다. 위의 예를 보면, myVariable이 정수형 값으로 초기화되었기 때문에 컴파일러는 정수형이라고 추측합니다.

만약 초기값이 충분한 정보를 제공하지 못한 경우(혹은 초기값이 없는 경우) 특정한 타입을 변수명 뒤에 세미콜론으로 분리하여 써주어야 합니다.

1| let inplicitInteger = 70
2| let implicitDouble = 70.0
3| let explicitDouble: Double = 70

` 실험
4와 명시적으로 Float 형태의 값을 갖는 상수를 만들어보자.

값은 절대 암시적으로 다른 형태의 값으로 변환할 수 없습니다. 만약 다른 형태의 값으로 변화해야 한다면 명시적으로 원하는 형태의 인스턴스로 만들어야 합니다.

1| let label = "The width is "
2| let width = 94
3| let widthLabel = label + String(width)

` 실험
마지막줄에 있는 String으로 변환 부분을 제거해보자. 어떤 에러가 발생하는가?

문자열 안에 값들을 포함하는 쉬운 방법도 있습니다. 괄호 안에 값을 쓰고 괄호 앞에 백슬래시를 쓰면 됩니다. 예를 들면

1| let apples = 3
2| let oranges = 5
3| let appleSummary = "I have \(apples) apples."
4| let fruitSummary = "I have \(apples + oranges) pieces of fruit."

` 실험
문자열안에 \()를 이용해 실수형 계산을 포함하도록 해보고, 인사말 안에 누군가의 이름을 넣어보자.

배열과 딕셔너리는 대괄호([])를 이용해 만들 수 있습니다. 그리고 대괄호 안에 인덱스나 키를 이용해 각각의 요소에 접근할 수 있습니다.

1| var shoppingList = ["catfish", "water", "tulips", "blue paint"]
2| shoppingList[1] = "bottle of water"
3|
4| var occupations = [
5| "Malcolm":"Captian",
6| "Kaylee":"Mechanic",
7| ]
8| occupations["Jayne"] = "Public Relations"

빈 배열이나 딕셔너리를 만들려면, 초기화자(initializer) 문법을 사용하면 됩니다.

1| let emptyArray = String[]()
2| let emptyDictionary = Dictionary()

타입 정보를 추론할 수 없다면 빈 배열은 []로 빈 딕셔너리는 [:]로 쓸 수 있습니다. 예를 들어 변수에 새로운 값을 할당하거나 함수에 인자로 넘겨줄 때

shoppingList = [] //쇼핑을 가서 모든 것을 샀다.

##흐름
if와 switch를 사용해서 조건문을 만들 수 있고 for-in, for, while, do-while을 이용해서 반복문을 만들 수 있습니다. 조건문과 반복문을 괄호로 감싸는 것은 선택사항입니다. 중괄호로 몸통을 감싸는 것은 필수입니다.

1| let individualScores = [75, 43, 103, 87, 12]
2| var teamScore = 0
3| for score in individualScores {
4| if score > 50 {
5| teamScore += 3
6| } else {
7| teamScore += 1
8| }
9|}
10|teamScore

if문 안에 조건은 꼭 불리언(Boolean) 표현이어야 합니다. 이것은 if score {...} 이 0과의 비교를 암시하지 않기 때문에 에러가 발생합니다.

사라질 값을 가지고 if와 let을 함께 사용하는 것도 가능합니다. 이런 값들은 옵션으로 대표됩니다. 옵션값은 어떤 값을 가지거나 사라질 값을 표현하는 nil을 가지기도 합니다. 값의 타입 뒤에 물음표를 쓰면 옵션값이라는 것을 나타냅니다.

1| var optionalString: String? = "Hello"
2| optionalString == nil
3|
4| var optionalName: String? = "John Appleseed"
5| var greeting = "Hello!"
6| if let name = optionalName {
7| greeting = "Hello, \(name)"
8| }

` 실험
optionalName의 값을 nil로 바꿔보자. 어떤 greeting의 값을 받을 수 있는가? optionalName이 nil일 때 다른 값을 greeting에 할당하도록 else 절을 추가해보자.

만약 옵션값이 nil이라면 조건문은 false이고 중괄호 안에 있는 코드를 건너뛰게 됩니다. 반대의 경우에는 중괄호 블록 안에서 사용할 수 있도록 let 뒷부분의 상수에 값이 할당되고 옵션값으로 사용할 수 있습니다.

스위치(Switch) 구문에는 정수형 값이나 동등 비교연산 뿐만 아니라 어떤 종류의 데이터든 사용할 수 있고 다양한 비교 연산자들을 사용할 수 있습니다.

1| let vegetable = "red pepper"
2| switch vegetable {
3| case "celery":
4| let vegetableComment = "Add some raisins and make ants on a log."
5| case "cucumber", "watercress":
6| let vegetableComment = "That would make a good tea sandwich."
7| case let x where x.hasSuffix("pepper"):
8| let vegetableComment = "Is it a spicy \(x)?"
9| default:
10| let vegetableComment = "Everything tastes good in soup."
11| }

실험
스위치 구문에서 default의 경우를 제거해 보자. 어떤 에러가 발생하는가?

스위치 구문안의 일치하는 경우의 코드를 실행하고 나면 프로그램은 스위치 구문을 빠져나옵니다. 실행한 코드 이후에 나오는 내용은 실행하지 않기 때문에 각 경우의 코드 끝마다 빠져나오도록 명시적으로 써주지 않아도됩니다.(*역자 주: 보통 사용되는 break를 굳이 쓸 필요가 없다는 것입니다.)

for-in 문을 사용하면 각각 키-값 쌍으로 사용할 수 있는 이름들의 쌍을 이용해 딕셔너리에 있는 요소들을 반복처리할 수 있습니다.

1| let interestingNumbers = [
2| "Prime": [2, 3, 5, 7, 11, 13],
3| "Fibonacci": [1, 1, 2, 3, 5, 8],
4| "Square": [1, 4, 9, 16, 25],
5| ]
6| var largest = 0
7| for (kind, numbers) in interestingNumbers {
8| for number in numbers {
9| if number > largest {
10| largest = number
11| }
12| }
13| }
14| largest

실험
계속 알아 보기 위해서 기존의 제일 큰 값만큼 큰 값을 가지는 요소를 추가해보자.

조건문이 변경될 때까지 코드 블록을 반복 실행하기 위해서 while 문을 사용해 봅시다.

반복문이 적어도 한번은 실행될 수 있도록 보장하기 위해서 조건문을 반복문 끝에 쓸수도 있습니다.

1| var n = 2
2| while n < 100 {
3| n = n * 2
4| }
5| n
6|
7| var m = 2
8| do {
9| m = m * 2
10| } while m < 100
11| m

반복문안에서 ..을 사용해 인덱스의 범위를 만들어 사용하거나 명시적으로 초기화, 조건문, 증감식을 사용하는 것 또한 가능합니다. 아래쪽에 나오는 두가지 반복문은 동일한 일을 수행합니다.

1| var firstForLoop = 0
2| for i in 0..3 {
3| firstForLoop += i
4| }
5| firstForLoop
6|
7| var secondForLoop = 0
8| for var i = 0; i < 3; ++i {
9| secondForLoop += 1
10| }
11| secondForLoop

..을 사용해서 범위를 지정하면 제일 나중값은 제외가 됩니다. 대신 ...을 사용하면 양쪽 끝값 모두 포함하게 됩니다.

##함수(Functions)와 클로저(Closures)

func를 사용해 함수를 선언할 수 있습니다. 함수의 이름과 괄호안에 인자들을 넣어서 함수를 호출할 수 있습니다. 매개변수들의 이름과 분리해서 ->를 사용해 타입을 써주면 함수 반환값의 타입을 지정할 수 있습니다.

1| func greet(name: String, day: String) -> String {
2| return "Hello \(name), today is \(day)."
3| }
4| greet("Bob", "Tuesday")


실험
매개변수 day를 제거하고 오늘의 스페셜 런치 매개변수를 greeting에 추가해보자.

튜플(tuple)을 사용하면 여러개의 값을 반환할 수 있습니다.

1| func getGasPrices() -> (Double, Double, Double) {
2| return (3.59, 3.69, 3.79)
3| }
4| getGasPrices()

함수는 배열을 이용해서 여러개의 값을 인자로 받는 것도 가능합니다.

1| func sumOf(numbers: Int...) -> Int {
2| var sum = 0
3| for number in numbers {
4| sum += number
5| }
6| return sum
7| }
8| sumOf()
9| sumOf(42, 597, 12)

실험
인자들의 평균값을 계산하는 함수를 만들어보자.

함수는 다른 것에 포함될 수도 있습니다. 내장된(Nested) 함수는 감싸고 있는 함수에서 선언된 변수에 접근할 수 있습니다. 길어지고 복잡한 함수의 코드를 정리하기 위해 내장된 함수를 사용할 수 있습니다.

1| func returnFifteen() -> Int {
2| var y = 10
3| func add() {
4| y += 5
5| }
6| add()
7| return y
8| }
9| returnFifteen()

함수는 최상위 타입입니다. 이것은 어떤 함수가 다른 함수를 반환값형태로 반환할 수 있다는 것을 의미합니다.

1| func makeIncrementer() -> (Int -> Int) {
2| func addOne(number: Int) -> Int {
3| return 1 + number
4| }
5| return addOne
6| }
7| var increment = makeIncrementer()
8| increment(7)

또 함수는 다른 함수를 인자로 받을 수 있습니다.

1| func hasAnyMatches(list: Int[], condition: Int -> Bool) -> Bool {
2| for item in list {
3| if condition(item) {
4| return true
5| }
6| }
7| return false
8| }
9| func lessThanTen(number: Int) -> Bool {
10| return number < 10
11| }
12| var numbers = [20, 19, 7, 12]
13| hasAnyMatches(numbers, lessThanTen)

함수는 실제로는 클로저의 특별한 예입니다. 중괄호로 묶기만 해서 이름없이 클로저를 사용할 수도 있습니다. in을 사용해 몸통에서 인자와 반환값 타입을 분리해 쓸 수 있습니다.

1| numbers.map({
2| (number: Int) -> Int in
3| let result = 3 * number
4| return result
5| })

실험
모든 홀수값에 대해 0을 반환하도록 클로저를 수정해보자.

클로저를 간결하게 쓰기 위한 몇가지 옵션이 있습니다. 델리게이트(delegate)를 위한 콜백같이 이미 클로저의 타입을 아는 경우라면 매개변수의 타입, 반환값 타입을 모두 생략하거나 선택적으로 생략할 수 있습니다. 한줄짜리 구문을 가진 클로저라면 구문만 가지고도 반환 타입을 추측할 수 있습니다.

numbers.map({ number in 3 * number })

매개변수의 이름 대신에 번호로 참조하는 것은 클로저를 짧게 만드는데 특히 유용합니다. 이때 클로저는 함수의 바로 뒤에 중괄호를 이용해 인자로 전달됩니다.

sort([1, 5, 3, 12, 2]) { $0 > $1 }

##객체(Objects)와 클래스(Classes)

클래스를 만들기 위해서는 클래스 이름과 함께 class 키워드를 사용하면 됩니다.클래스 컨텍스트(context) 내부를 제외하고 클래스 안에 속성을 선언하기 위해서는 상수나 변수를 선언하는 것과 똑같은 방식으로 쓰면 됩니다. 마찬가지로 메서드와 함수도 선언할 수 있습니다.

1| class Shape {
2| var numberOfSides = 0
3| func simpleDescription() -> String {
4| return "A shape with \(numberOfSides) sides."
5| }
6| }

어떤 클래스의 인스턴스를 만들려면 클래스 이름 다음에 괄호를 넣으면 됩니다. .(점) 문법을 사용하면 인스턴스의 속성이나 메서드에 접근할 수 있습니다.

1| var shape = Shape()
2| shape.numberOfSides = 7
3| var shapeDescription = shape.simpleDescription()

현재 상태의 Shape클래스는 중요한 것이 빠져있습니다. 바로 클래스가 생성될 때 클래스를 초기화하기 위한 초기화자 입니다. init 키워드를 사용해 만들어 봅시다.

1| class NamedShape {
2| var numberOfSides: Int = 0
3| var name: String
4| init(name: String) {
5| self.name = name
6| }
7| func simpleDescription() -> String {
8| return "A shape with \(numberOfSides) sides."
9| }
10| }

인자의 name과 속성의 name을 구분하기 위해서 self 키워드가 어떻게 사용되는지 주의해서 봅시다. 클래스의 인스턴스를 만들 때 초기화자에 인자를 전달하는 방식은 함수에 전달하는 방식과 동일합니다. 모든 속성은 numberOfSides 처럼 값을 선언 할 때 혹은 name처럼 클래스를 초기화 할 때 처럼 적어도 둘중에 한가지 방법을 통해 값을 할당해줘야 합니다.

오브젝트를 해제하기전 정리 작업이 필요하다면 deinit을 사용해서 디이니셜라이저(deinitializer)를 만들 수 있습니다.

하위 클래스는 클래스명 뒤에 상위 클래스의 이름을 세미콜론으로 구분해 포함합니다. 꼭 기본 루트 클래스가 필요한 것은 아니기 때문에 상위 클래스를 포함해도 되고 생략해도 됩니다.

하위 클래스에서 상위 클래스에서 구현된 메서드를 오버라이드(override) 하려면 override 키워드를 이용해 표시해줘야 합니다. override키워드를 사용하지 않고 어떤 메서드를 갑자기 오버라이드하면 컴파일러에서 에러로 인식합니다. 또 override 키워드를 사용했는데 실제로 상위 클래스에는 해당 메서드가 없다면 이것 또한 컴파일러가 잡아냅니다.

```c
class Square: NamedShape {
var sideLength: Double

init(sideLength: Double, name: String) {
self.sideLength = sideLength
super.init(name: name)
numberOfSides = 4
}

func area() -> Double {
return sideLength * sideLength
}

override func simpleDescription() -> String {
return "A square with sides of length \(sideLength)."
}
}
let test = Square(sideLength: 5.2, name: "my test square")
test.area()
test.simpleDescription()
```

실험
NamedShape클래스의 또 다른 하위 클래스인 Circle을 만들어보자. 이 클래스는 이니셜 라이저를 통해 radius와 name을 인자로 받는다. Circle 클래스 안에 area, describe 함수를 구현해보자.

저장되어 있는 간단한 속성 외에도 속성은 getter와 setter를 가질 수 있습니다.

```c
class EquilateralTriangle: NamedShape {
var sideLength: Double = 0.0

init(sideLength: Double, name: String) {
self.sideLength = sideLength
super.init(name: name)
numberOfSides = 3
}

var perimeter: Double {
get {
return 3.0 * sideLength
}
set {
sideLength = newValue / 3.0
}
}

override func simpleDescription() -> String {
return "An equilateral triagle with sides of length \(sideLength)."
}
}
var triangle = EquilateralTriangle(sideLength: 3.1, name: "a triangle")
triangle.perimeter
triangle.perimeter = 9.9
triangle.sideLength
```
perimeter의 setter안에서는 newValue라는 이름이 새로운 값을 나타내고 있습니다. 반면에 명시적으로 set 뒤에 괄호를 이용해 명시적으로 이름을 지정해 줄수도 있습니다.

EquilateralTriangle 클래스의 이니셜라이저는 세가지의 다른 단계를 가지고 있음을 살펴봅시다.

1. 하위 클래스에서 선언한 속성의 값을 지정합니다.
2. 상위 클래스의 이니셜라이저를 호출합니다.
3. 상위 클래스에 의해 정의된 속성값을 변경합니다. 어떤 메서드나 setter,getter를 사용하지 않고도 가능 하다는 것이 중요한점 입니다.

속성의 값을 계산할 필요는 없지만 새로운 값을 할당하기 전이나 후에 수행해야할 코드가 있다면 willSet, didSet을 사용할 수 있습니다. 예를 들면 아래쪽에 나오는 클래스에서는 삼각형의 빗면의 길이가 사각형의 옆면의 길이와 항상 동일하다는 것을 보장합니다.

```c
class TriangleAndSquare {
var triangle: EquilateralTriangle {
willSet {
square.sideLength = newValue.sideLength
}
}
var square: Square {
willSet {
triangle.sideLength = newValue.sideLength
}
}
init(size: Double, name: String) {
square = Square(sideLength: size, name: name)
triangle = EquilateralTriangle(sideLength: size, name: name)
}
}
var triangleAndSquare = TriangleAndSquare(size: 10, name: "another test shape")
triangleAndSquare.square.sideLength
triangleAndSquare.triangle.sideLength
triangleAndSquare.square = Square(sideLength: 50, name: "larger square")
triangleAndSquare.triangle.sideLength
```

클래스에 있는 메서드들은 함수와는 다른 중요한 특징이 한가지 있습니다.함수에서 사용되는 매개변수의 이름들은 함수 내부에서만 사용합니다. 그러나 메서드에 사용되는 매개변수의 이름은 메서드를 호출할 때도 사용됩니다(첫번째 매개변수의 이름은 제외하고). 기본적으로 메서드는 호출할 때 혹은 메서드에서 사용되는 이름과 동일한 매개변수 이름을 갖습니다. 하지만 메서드 내부에서 사용될 두번째 이름을 특별히 정해줄 수도 있습니다.

```c
class Counter {
var count: Int = 0
func incrementBy(amount: Int, numberOfTimes times: Int) {
count += amount * times
}
}
var counter = Counter()
counter.incrementBy(2, numberOfTimes: 7)
```
옵션 값을 사용할 때는 메서드나 속성, 서브스크립트 앞에 ?를 쓸 수 있습니다. 만약 ? 앞에 값이 nil 이라면 ? 이후에 나오는 모든 것은 무시되고 표현의 값들은 nil을 갖습니다. 반면에 값이 있는 경우라면 ? 이후의 모든 그 값을 기준으로 동작합니다. 양쪽 경우 모두 옵션 값으로 사용됩니다.

##열거형(Enumerations)과 구조체(Structures)
enum 키워드를 사용하면 열거형을 만들 수 있습니다. 클래스나 모든 알려진 타입들의 경우 열거형에 메서드를 포함할 수 있습니다.

```c
enum Rank: Int {
case Ace = 1
case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten
case Jack, Queen, King
func simpleDescription() -> String {
switch self {
case .Ace:
return "ace"
case .Jack:
return "jack"
case .Queen:
return "queen"
case .King:
return "king"
default:
return String(self.toRaw())
}
}
}
let ace = Rank.Ace
let aceRawValue = ace.toRaw()
```

>실험
두개의 Rank 값의 원본 값을 비교하는 함수를 만들어보자.

위의 예를 보면 열거형의 원본 값의 타입은 int 입니다. 그래서 특별히 첫번째 원본값만 가지고 있는 것입니다. 나머지 원본 값들은 순서에 따라 자동으로 할당됩니다. 또 문자열이나 실수형태의 값들도 원본값으로 가진 열거형을 만들 수 있습니다.

toRaw와 fromRaw 함수를 사용해서 원본값과 열거형 값을 상호 변환할 수 있습니다.

```c
if let convertedRank = Rank.fromRaw(3) {
let threeDescription = convertedRank.simpleDescription()
}
```

열거형의 구성값들은 실제 값을 쓰는 다른 방법일 뿐 아니라. 모두 실제 값입니다. 사실 실제값이 의미있는 경우가 아니라면 굳이 첫번째 값을 제공할 필요가 없습니다.

```c
enum Suit {
case Spades, Hearts, Diamonds, Clubs
func simpleDescription() -> String {
switch self {
case .Spades:
return "spades"
case .Hearts:
return "hearts"
case .Diamonds:
return "diamonds"
case .Clubs:
return "clubs"
}
}
}
let hearts = Suit.Hearts
let heartsDescription = hearts.simpleDescription()
```

>실험
Suit에 color 메서드를 추가해 보자. color 메서드는 스페이드와 클로버는 'black'을 반환하고 하트와 다이아몬드는 'red'를 반환하도록 하면 됩니다.

열거형의 구성중 하나인 Heart가 상단값을 어떻게 참조하는지 두가지 방법을 살펴봅시다. 상수 hearts에 값을 할당 할 때, 상수는 명시적으로 타입을 가지고 있지 않기 때문에 Suit.Hearts 처럼 전체 이름을 살펴봅니다. 스위치문 안에서는 열거형은 .Hearts로 축약형을 써서 참조하는데, 이것은 self가 이미 suit라는 것을 알고 있기 때문입니다. 값의 형을 이미 알고 있다면 언제든지 축약형을 사용해도 됩니다.

구조체를 만들기 위해서는 struct 키워드를 사용합니다. 구조체는 메서드나 이니셜라이저 같은 클래스와 비슷한 기능들을 지원합니다. 클래스와 구조체의 가장 중요한 차이점중 하나는 구조체의 경우 코드 내에서 전달될 때 값복사 형태로 전달되지만 클래스의 경우에는 참조복사 형태로 전달된 다는 것입니다.

```c
struct Card {
var rank: Rank
var suit: Suit
func simpleDescription() -> String {
return "The \(rank.simpleDescription()) of \(suit.simpleDescription())"
}
}
let threeOfSpades = Card(rank: .Three, suit: .Spades)
let threeOfSpadesDescription = threeOfSpades.simpleDescription()
```
>실험
각 카드를 rank와 suit를 조합해서 만들어 전체 카드를 만들어 주는 메서드를 Card에 추가해보자.



































chapter20
# 20 타입 변환

Write here...
(Type Casting)
> Translator : 이름 (메일주소)

## 타입변환(Type Casting)

타입 변환이란 인스탄스(instance)의 타입을 체크하기 위한 방법이며, 또한
and/or to treat that instance as if
it is a different superclass or subclass from somewhere else in its own class hierarchy.
Swift에서 타입 변환은 'is'와 'as'라는 연산자로 구현할 수 있으며, 이 두 연산자는 값의 타입을 체크하거나 다른 타입으로 변환하는 간단하고 표현적인 방법을 제공합니다.
또한 해당 타입이 프로토콜에 적합하지 아닌지 체크하기 위해서 타입 변환을 사용할 수 있으며 보다 자세한 사항은 [Protocol Conformance](링크)를 참조하시기 바랍니다.

## 타입 캐스팅을 위한 클래스 계층 정의(Defining a Class Hierarchy for Type Casting)

타입 캐스팅을
You can use type casting with a hierarchy of classes and subclasses to check the type of a
particular class instance and to cast that instance to another class within the same
hierarchy.
아래의 세가지의 코드조각(code snippets)는 타입 캐스팅이 사용되는 예제를 보여주기 위한 계층적인 클래스들과 각각의 클래스들의 인스턴스를 포함하는 배열(array)를 정의하고 있습니다.
첫번째 코드 조각은 MediaItem 새로운 기본 클래스(base calss)를 정의하고 있습니다. 이 클래스는 디지털 미디어 라이브러리에 있는 모든 아이템들을 위한 기본적인 기능을 제공합니다. 특히 문자열(String)타입의 name 속성(Property)를 선언하고, initializer를 통해서 'name'을 초기화 합니다(이것은 모든 미디어 아이템(영화나 노래)들이 이름을 가지고 있다고 가정합니다)

```c
class MediaItem {
var name: String
init(name: String) {
self.name = name
}
}
```

다음 코드 조각은 MediaItem의 두가지 하위클래스(subclasses)들입니다. 첫번째 하위클래스인 Moive는 내부적으로 영화에 관한 추가적인 데이터를 가지고 있는데. 이는 'director'라는 속성 및 초기화 부분을 MediaItem클래스의 initalizer의 윗부분에 추가하는것으로 더할 수 있으며. 두번째 하위 클래스인 'Song'도 artist 속성의 관한 내용을 선언하고 base class의 윗부분에서 이를 초기화 한다:
```c
class Movie: MediaItem {
var director: String
init(name: String, director: String) {
self.director = director
super.init(name: name)
}
}

class Song: MediaItem {
var artist: String
init(name: String, artist: String) {
self.artist = artist
super.init(name: name)
}
}
```
마지막 코드조각은 2개의 Movie 인스탄스와 3개의 Song 인스탄스를 포함하는 library로 불리는 상수형 배열(constant array)를 만든다.
library배열의 타입은 각각의 배열 내부의 콘텐츠를 초기화 하는 타입으로 추정할 할 수 있다.
Swift의 타입 체커는 Movie나 Song이 공통의 상위 클래스(superclass)인 MediaItem을 가진다고 추정할 수 있고, 따라서 library의 array는 MediaItem[]로 추정할 수 있다 :
```c
let library = [
Movie(name: "Casablanca", director: "Michael Curtiz"),
Song(name: "Blue Suede Shoes", artist: "Elvis Presley"),
Movie(name: "Citizen Kane", director: "Orson Welles"),
Song(name: "The One And Only", artist: "Chesney Hawkes"),
Song(name: "Never Gonna Give You Up", artist: "Rick Astley")
]
// the type of "library" is inferred to be MediaItem[]
```
library에 저장된 요소들은 해당 Scenes뒤에서는 여전히 Movie와 Song인스탄스이다. 그러나 만일 네가 이 array의 컨텐츠들을 반복자 등을 이용하여 뽑아낸 다면, 네가 받게된 그 아이템들의 타입은 Song이나 Movie이 아닌 MediaItem일 것이다. 그것들을 원래의 타입으로 작업을 하기 위해얻고 싶다면, 당신은 그들의 타입을 체크하는 것이 필요하고, 또한 그들을 downcast해서 다른 타입으로 변경하여야 한다. 이는 아래서 설명하도록 하겠다.

## 타입 체크(Checking Type)

어떠한 instance가 확실히 하위클래스 타입인지 아닌지를 체크하기 위해서는 타입 체크 연산자인 'is'를 이용합니다. 이 타입체크용 연산자는 만일 해당 인스탄스가 해당 하위 클래스라면 true를, 아니라면 false를 반환합니다.
아래의 예시는 library배열에 있는 Movie의 instance의 수와 Song의 instance의 수를 세기 위한movieCount와 songCount라는 두개의 변수를 선언하는 것을 보여줍니다.:
```c
var movieCount = 0
var songCount = 0

for item in library {
if item is Movie {
++movieCount
} else if item is Song {
++songCount
}
("Media library contains \(movieCount) movies and \(songCount) songs")
// prints "Media library contains 2 movies and 3 songs"
```
이 예시에서는 library배열의 모든 아이템에 대해서 작업하며, 각각의 1번의 과정마다 for-in loop는 배열에 MediaItem 상수를 가져오고, 각각의 아이템이 만일 Movie 인스탄스이면 is Movie에서 true를 아니라면 false를 반환하고, 이와 유시하게 아이템이 만일 Song의 인스탄스인지 아닌지에 따라 is Song 체크부분의 리턴값이 결정됩니다. for-in loop의 마지막이 되면, moveCount와 songCount의 값을 보고 전체 MediaItem인스탄스중에 각각의 타입이 얼마만큼의 수가 들어있는지 찾아낼 수 있다.

## 다운캐스팅( Downcasting )

상수와 변수의 명확한 클래스 타입은 사실은 아마도 the scenes뒤에 있는 하위 클래스의 인스탄스에 속할것이다.
당신이 위와 같은 케이스를 믿는 경우, 당신은 타입 변환 연산자인 'as'를 통하여 하위클래스타입으로 다운캐스팅을 시도 할 수 있다.
다운캐스팅은 실패할 수 있기때문에, 타입 캐스팅연산자는 두가지의 다른 형태를 가집니다.
하나는 as?와 같은 연산자를 사용하는 optional form으로 다운캐스팅을 시도하여 optional value를 리턴합니다.
다른 하나는 as와 같은 연산자를 사용하는 forced form으로 다운 캐스팅을 시도하고 강제로 unwrap한 결과를 한번에 합한 작업을 합니다.
네가 만일 다운캐스트가 성공할지 확신을 가지지 못한다면 타입변환 연산자인 as?를 이용하는 optional form을 사용한다. 위 연산자를 사용하는 form은 항상 optional value를 리턴하며 그래서 만일 다운 캐스트가 가능하지 않은 경우에는 nil을 리턴할 수 있도록 할 수 있다. 이 것은 당신이 다운 캐스팅의 성공 유무를 체크할 수 있도록 하게 한다.
오직 당신이 다운캐스트가 항상 성공할 것이라는 확신이 있다면 타입 변환 연산자인 as를 이용하는 forced form을 사용할 수 있다. 위의 연산자를 사용하는 form은 만일 올바르지 않은 클래스 타입으로 다운캐스팅을 시도했을 시에 런타임 에러를 발생시킨다.
아래에 library 내의 각 MediaItem을 반복해가면서 각 아이템들을 위한 적절한 설명을 출력하는 예시를 만들었다. 이를 위해서 각 아이템이 단순히 MediaItme이 아닌 진정으로 Movie나 Song인지억세스 해볼 필요가 있다. 이를 위해서설명을 출력하기 위해서 Movie나 Song의 director나 artist 속성에 접근할수 있게 할 필요가 있다.
예시에서 배열내의 각각의 item은 Movie이거나 Song이라고 생각된다. 당신은 각각의 아이템이 실제 어떠한 클래스인지 미리 알 수가 없습니다. 그러므로 optional form을 위한 as? 연산자를 사용하여 루프를 통해 각 케이스마다 다운캐스팅을 체크하는 것이 적절합니다:
```c
for item in library {
if let movie = item as? Movie {
println("Movie: '\(movie.name)', dir. \(movie.director)")
} else if let song = item as? Song {
println("Song: '\(song.name)', by \(song.artist)")
}
}

// Movie: 'Casablanca', dir. Michael Curtiz
// Song: 'Blue Suede Shoes', by Elvis Presley
// Movie: 'Citizen Kane', dir. Orson Welles
// Song: 'The One And Only', by Chesney Hawkes
// Song: 'Never Gonna Give You Up', by Rick Astley
```
이 예시는 현재 아이템이 Movie라고 생각하고 다운 캐스팅을 시도하는 것으로 시작합니다. 아이템이 MediaItem 인스탄스이므로 이 아이템은 Movie일 수 있습니다, 또한 똑같은 이유로 Song도 가능합니다, 혹은 오로지 단순히 MediaItem일수도 있습니다. 이것이 불확실 하기 때문에, as? 타입변환 연산자를 사용하여 하위 클래스로의 다운캐스팅을 시도시에 optional value를 반환합니다. 그 결과 item as Moive의 결과는 Move? 타입, 즉 optional Movie이 됩니다.
library 배열안의 두개의 Song 인스탄스에 해당 내용을 적용하여 Movie로 다운캐스팅을 할경우 실패한다. 이것에 대처하기 위해, 위의 예시에서는 결과로 나온 optional Movie값이 실제로 값을 가지고 있는지 체크하기 위한(이 경우는 다운캐스팅이 성공했는지 아닌지 찾는 과정이다) optional binding을 사용한다.
이 optional binding 은 "if let movie = is as? Moive"와 같이 적히며, 이는 다음과 같이 해석될 수 있다: "해당 아이템을 Movie로 생각하고 접근을 시도한다. 만일 해당 작업이 상공하면, 반환된 optional Movie값을 저장할 movie라고 불리는 새로운 임시 상수값을 설정한다.
만일 다운 캐스팅이 성공한다면, movie의 속성들을 가지고 director와 같은 Moive 인스탄스를 위한 설명을 출력하는데 사용할 수 있습니다.
비슷한 원리로 Song 인스턴스를 위한 체크를 하여, library에서 Song인스탄스를 찾기만 한다면, artist와 같은 적절한 설명을 출력할 수 있습니다.

>NOTE
변환(Casting)은 실제로 해당 인스턴스를 수정하거나 그 값을 바꾸는 것이 아닙니다. 근본적인 인스턴스는 처음상태 그대로 남아있습니다. 이것은 간단히 특별한 것이며, 캐스팅된 타입의 인스턴스로서 접근이 가능한 것입니다.

## Type Casting for Any and AnyObject

Swift는 특정한 타입을 가지지 않는 상태로 작업하기 위한 두가지의 특별한 타입을 제공합니다:

AnyObject 는 어떠한 클래스타입의 인스탄스라도 표현할 수 있습니다
Any 는 함수형의 타입을 제외하고는 어떠한 타입의 인스탄스라도 표현할 수 있습니다.

>NOTE
Any나 AnyObject는 오로지 당신이 명시적으로 behavior나 그들이 제공하는 능력들이 필요한 경우에만 사용합니다. 이는 항상 당신의 코드 속에서당신이 예상한 특정한 형태의 타입으로 작동하는 것이 더 낫습니다.

## AnyObject

Cocoa APIS를 이용하여 작업을 할때, 보통 AnyObject[] 타입의 배열를(any object 타입의 값을 가진 배열) 받는것이 일반적입니다. 이것은 Objctive-C가 명시적인 타입의 배열을 가지지 못하기 때문입니다. 그러나 당신이 종종 당신이 알고있는 API가 제공하는 array를 포함한 여러가지 정보를 포함한 오브젝트들의 타입에 대해서 자신이 있을 수 있다.
이러한 상황에서, 당신은 optional unwrapping이 필요하지 않은 경우에 한하여 배열의 각각의 아이템을 특정한 클래스의 타입으로 바꾸는 다운캐스팅을하기 위한 타입 변환 연산자 as로 강제로 변경한 형태를 사용할 수 있습니다.
```c
let someObjects: AnyObject[] = [
Movie(name: "2001: A Space Odyssey", director: "Stanley Kubrick"),
Movie(name: "Moon", director: "Duncan Jones"),
Movie(name: "Alien", director: "Ridley Scott")
]
```
이 배열은 오로지 Moive 인스턴스만 가지는 것을 이미 알고 있으므로, 당신은 다운캐스팅 및 타입 변환 연산자 'as'를 이용하여 non-optional Moive로 강제로 형태를 바꾸는 unwrap를 할 수 있습니다.
```c
for object in someObjects {
let movie = object as Movie
println("Movie: '\(movie.name)', dir. \(movie.director)")
}
// Movie: '2001: A Space Odyssey', dir. Stanley Kubrick
// Movie: 'Moon', dir. Duncan Jones
// Movie: 'Alien', dir. Ridley Scott
```
루프를 조금더 짧게 만들기 위해서, 각 아이템을 다운캐스팅하는 대신에 Movie[] someObjects 배열을 Movie[]타입으로 다운 캐스팅 할 수있습니다:
```c
for movie in someObjects as Movie[] {
println("Movie: '\(movie.name)', dir. \(movie.director)")
}
// Movie: '2001: A Space Odyssey', dir. Stanley Kubrick
// Movie: 'Moon', dir. Duncan Jones// Movie: 'Alien', dir. Ridley Scott
```

## Any

이곳에 non-class타입을 포함한 여러가지 다른 타입을 섞어서 작업하기 위한 Any를 사용한 예제가 있다. 이 예제는 Any타입의 값을 저장할 수 있는 thing이라고 불리는 한 배열을 생성한다.
```c
var things = Any[]()

things.append(0)
things.append(0.0)
things.append(42)
things.append(3.14159)
things.append("hello")
things.append((3.0, 5.0))
things.append(Movie(name: "Ghostbusters", director: "Ivan Reitman"))
```
thing배열은 두개의 int 값, 두개의 Double값, 하나의 String값, 하나의 (Double,Double)타입의 tople, 그리고 "Ghostbusters"의 name과 "Ivan Retiman"의 director속성을 가진 Moive를 한개 가지고 있다.
당신은 Any나 AnyObject로 알고있는 변수에서 특정한 타입의 상수나 변수 찾기 위한 스위치 구문의 case 항목에 `is`와 `as` 연산자를 사용할수 있습니다.
아래의 예제는 아이템들의 things 배열의 각 아이템을 반복하면서 스위치 문을 통해서 각각의 타입을 요청한다.
몇몇의 스위치문의 case항목에서 올바르게 맞는 값과 타입을 가지는 상수의 경우는 해당 값과 형태를 출력한다:
```c
for thing in things {
switch thing {
case 0 as Int:
println("zero as an Int")
case 0 as Double:
println("zero as a Double")
case let someInt as Int:
println("an integer value of \(someInt)") case let someDouble as Double where someDouble > 0:
println("a positive double value of \(someDouble)")
case is Double:
println("some other double value that I don't want to print")
case let someString as String:
println("a string value of \"\(someString)\"")
case let (x, y) as (Double, Double):
println("an (x, y) point at \(x), \(y)")


case let movie as Movie:
println("a movie called '\(movie.name)', dir. \(movie.director)")
default:
println("something else")
// zero as an Int
// zero as a Double
// an integer value of 42
// a positive double value of 3.14159
// a string value of "hello"
// an (x, y) point at 3.0, 5.0
// a movie called 'Ghostbusters', dir. Ivan Reitman
```

>NOTE
스위치문의 case항목들은 체크 및 특정한 타입으로의 변환을 위해서 as나 as?를 통해서 강제로 변경된 형태를 사용한다. 이런 체크는 스위치 문의 문맥안에 있는 이상 항상 안전하다.

chapter21
# 21 중첩 형식 (Nested Types(중첩 형식) )
> Translator : Alice Kim (mail@jua.kim)
번역에 대한 의견이 있을 때에는 메일이나 [Chapter21 - Discussion ](https://www.penflip.com/jjuakim/swift-korean/discussions/7)에 의견을 남겨주세요


열거형(Enumerations)은 종종 특정 클래스 또는 구조체(structure)의 기능을 지원하기 위해 만들어집니다. 마찬가지로, 복잡한 형태의 맥락에서 사용하기위한 유틸리티 클래스 또는 구조체를 정의하는데 유용합니다. 이를 위해 Swift는 중첩형식을 정의 할 수있습니다. 열거형과 클래스 및 그들이 지원하는 타입의 정의를 포함한 구조체를 중첩으로 지원함으로써 말이죠. (예를 들면, 구조체 안에 클래스를 정의하고 그 클래스 안에 다시 열거형을 넣을 수있다는 얘기)

다른 형식 안에 또 다른 형식을 중첩하기 위해서는, 지원하는 유형을 둘러싸고 있는 중괄호('{','}') 안에서 정의를 작성합니다. 이러한 유형은 필요로 하는 만큼 여러 수준으로 중첩 될 수 있습니다.

## Nested Types in Action
아래의 예제에서는 블랙잭 게임에서 사용되는 게임 카드를 모델로 하는 **BlackjackCard**구조체를 정의하고 있습니다. **BlakcJack** 구조체는 내부에 **Suit**와 **Rank** 라는 이름의 두개의 열거형 타입을 가지고 있습니다.

블랙잭 게임에서 에이스 카드는 1또는 11의 값을 가지고 있습니다. 이러한 요소는 **Values**라는 구조체에 의해 표현됩니다. **Values** 구조체는 **Rank** 열거형 내부에 중첩되어 있습니다.

```c
struct BlackjackCard {
// nested Suit enumeration
enum Suit: Character {
case Spades = "♠", Hearts = "♡", Diamonds = "♢", Clubs = "♣"
}

// nested Rank enumeration
enum Rank: Int {
case Two = 2, Three, Four, Five, Six, Seven, Eight, Nine, Ten
case Jack, Queen, King, Ace
struct Values {
let first: Int, second: Int?
}
var values: Values {
switch self {
case .Ace:
return Values(first: 1, second: 11)
case .Jack, .Queen, .King:
return Values(first: 10, second: nil)
default:
return Values(first: self.toRaw(), second: nil)
}
}
}

// BlackjackCard properties and methods
let rank: Rank, suit: Suit
var description: String {
var output = "suit is \(suit.toRaw()),"
output += " value is \(rank.values.first)"
if let second = rank.values.second {
output += " or \(second)"
}
return output
}
}
```

**Suit**열거형은 4가지 슈트(블랙잭에서 슈트란 카드에 있는 무늬를 말합니다.)들과 슈트의 그에 해당하는 **Character** 심볼 값을 함께 나타냅니다.

**Rank** 열거형은 13가지 카드의 랭크와 그에 해당하는 **Int** 값을 나타냅니다. (**Int**형의 숫자 값은 Jack, Queen, King, Ace 카드에는 사용되지 않습니다.)

위의 코드를 보면 알 수 있듯이, **Rank** 열거형은 **Values**라는 추가적인 구조체를 포함하는 중첩구조의 형태를 취하고 있습니다. 이 구조는 대부분의 카드는 하나의 값을 가지지만, 에이스 카드는 두가지 값을 갖는다는 사실을 캡슐화합니다.**Values** 구조체는 다음과 표현하는 두가지 속성을 정의하고 있습니다.
- **Int** 형의 **first**
- **Int?** 형 또는 **optional Int** 형의 **second**

**Rank**도 **Values**구조체의 인스턴스를 반환하는 계산된 **values**속성을 정의합니다. 이 계산된 속성은 카드의 순위를 고려하여 그 순위에 따라 적절한 값을 가지는 새로운 **Values**인스턴스를 초기화 합니다. 이러한 속성은 **Jack, Queen, King, Ace** 과 같은 특별한 값을 위해 사용합니다. 숫자카드의 경우에는 지정되어 있는 **Int** 값을 사용합니다.

**BlackjacCard** 구조체는 **rank**와 **suit**라는 두개의 속성을 가지고 있고, **description**이라는 계산된 속성도 정의하고 있습니다. 이 **description** 속성은 카드의 이름과 값에 대한 설명을 빌드하기 위해 **rank**와 **suit**에 저장된 값을 사용합니다.

**BalckjacCard**구조체는 커스텀 이니셜라이저를 가지고 있지 않으므로, 앞 챕터의 [구조체 타입을 위한 멤버 단위의 이니셜라이저(Memberwise Initializers for Structure Types)](Intialization 챕터 쪽 링크필요)에서 설명한대로 암시적인 멤버단위 이니셜라이저(memberwise intializer)를 가지고 있습니다.

```c
let theAceOfSpades = BlackjackCard(rank: .Ace, suit: .Spades)
println("theAceOfSpades: \(theAceOfSpades.description)")
// prints "theAceOfSpades: suit is ♠, value is 1 or 11
```

**Rank**와 **Suit**가 **BlackjacCard**안에 중첩되어 있다고 해도 그들의 타입은 문맥으로 부터 추론될 수 았가 때문에 이 인스턴스의 초기화는 자신의 맴버 이름(.Ace와 .Spades)으로 열거형 멤버를 참조할 수 있습니다. 위의 예에서는 **description**속성이 올바르게 Space Ace 카드가 1 또는 11의 값을 가지고 있는지 확인합니다.

## 중첩 형식을 참조하기 (Referring to Nested Types)
자신이 정의된 문맥 외부에서 중첩형식을 사용하려면, 자기를 포함하고 있는(중첩하고 있는)형식의 이름을 그 이름앞에 붙입니다.

```c
let heartsSymbol = BlackjackCard.Suit.Hearts.toRaw()
// heartsSymbol is "♡"
```

위의 예를 보면, 그들의 이름은 자연스럽게 그들이 정의된 문맥에 의해 규정되기 때문에 **Suit, Rank, Values**의 이름이 의도적으로 짧게 할 수 있습니다.
chapter22
# 22 확장 (Extensions)
> Translator : 이름 (메일주소)


Write here...
chapter23
# 23 프로토콜

# 23
(Protocols)
> Translator : 이름 (메일주소)

A protocol defines a blueprint of methods, properties, and other requirements that suit a
particular task or piece of functionality. The protocol doesn’t actually provide an
implementation for any of these requirements—it only describes what an implementation
will look like. The protocol can then be adopted by a class, structure, or enumeration to
provide an actual implementation of those requirements. Any type that satisfies the
requirements of a protocol is said to conform to that protocol.
프로토콜은 특정 작업이나 기능에 부합하는 메소드, 속성, 그리고 다른 요구사항들에 대한 청사진과 같습니다. 프로토콜에는 이런 요구사항들에 대한 어떤 구현도 포함하지 않고, 다만 구현된 모습이 어떨지 윤곽만 드러납니다. 그러면 클래스, 구조체나 열거형에서 프로토콜을 따라 요구사항들을 실제로 구현하게 됩니다. 프로토콜의 요구사항을 만족하는 형(`type`)이라면 그 프로토콜에 들어맞다(conform)라고 하죠.

Protocols can require that conforming types have specific instance properties, instance
methods, type methods, operators, and subscripts.
Protocol Syntax
You define protocols in a very similar way to classes, structures, and enumerations:
protocol SomeProtocol {
// protocol definition goes here
}
Custom types state that they adopt a particular protocol by placing the protocol’s name
after the type’s name, separated by a colon, as part of their definition. Multiple protocols
can be listed, and are separated by commas:
struct SomeStructure: FirstProtocol, AnotherProtocol {
// structure definition goes here
}
If a class has a superclass, list the superclass name before any protocols it adopts,
followed by a comma:
class SomeClass: SomeSuperclass, FirstProtocol, AnotherProtocol {
// class definition goes here
}
Property Requirements
A protocol can require any conforming type to provide an instance property or type
property with a particular name and type. The protocol doesn’t specify whether the
property should be a stored property or a computed property—it only specifies the
required property name and type. The protocol also specifies whether each property must
be gettable or gettable and settable.
If a protocol requires a property to be gettable and settable, that property requirement
cannot be fulfilled by a constant stored property or a read-only computed property. If the
protocol only requires a property to be gettable, the requirement can be satisfied by any
kind of property, and it is valid for it also to be settable if this is useful for your own code.
Property requirements are always declared as variable properties, prefixed with the var
keyword. Gettable and settable properties are indicated by writing { get set } after their
type declaration, and gettable properties are indicated by writing { get }.
protocol SomeProtocol {
var mustBeSettable: Int { get set }
var doesNotNeedToBeSettable: Int { get }
}
Always prefix type property requirements with the class keyword when you define them in
a protocol. This is true even though type property requirements are prefixed with the static
keyword when implemented by a structure or enumeration:
protocol AnotherProtocol {
class var someTypeProperty: Int { get set }
}
Here’s an example of a protocol with a single instance property requirement:
protocol FullyNamed {
var fullName: String { get }
}
The FullyNamed protocol defines any kind of thing that has a fully-qualified name. It doesn’t
specify what kind of thing it must be—it only specifies that the thing must be able to
provide a full name for itself. It specifies this requirement by stating that any FullyNamed
type must have a gettable instance property called fullName, which is of type String.
Here’s an example of a simple structure that adopts and conforms to the FullyNamed
protocol:
struct Person: FullyNamed {
var fullName: String
}
let john = Person(fullName: "John Appleseed")
// john.fullName is "John Appleseed"
This example defines a structure called Person, which represents a specific named person.
It states that it adopts the FullyNamed protocol as part of the first line of its definition.
Each instance of Person has a single stored property called fullName, which is of type String.
This matches the single requirement of the FullyNamed protocol, and means that Person has
correctly conformed to the protocol. (Swift reports an error at compile-time if a protocol
requirement is not fulfilled.)
Here’s a more complex class, which also adopts and conforms to the FullyNamed protocol:
class Starship: FullyNamed {
var prefix: String?
var name: String
init(name: String, prefix: String? = nil) {
self.name = name
self.prefix = prefix
}
var fullName: String {
return (prefix ? prefix! + " " : "") + name
ncc1701 = Starship(name: "Enterprise", prefix: "USS")
ncc1701.fullName is "USS Enterprise"
This class implements the fullName property requirement as a computed read-only property
for a starship. Each Starship class instance stores a mandatory name and an optional prefix.
The fullName property uses the prefix value if it exists, and prepends it to the beginning of
name to create a full name for the starship.
Method Requirements
Protocols can require specific instance methods and type methods to be implemented by
conforming types. These methods are written as part of the protocol’s definition in exactly
the same way as for normal instance and type methods, but without curly braces or a
method body. Variadic parameters are allowed, subject to the same rules as for normal
methods.
N O T E
Protocols use the same syntax as normal methods, but are not allowed to specify default values for method
parameters.
As with type property requirements, you always prefix type method requirements with the
class keyword when they are defined in a protocol. This is true even though type method
requirements are prefixed with the static keyword when implemented by a structure or
enumeration:
protocol SomeProtocol {
class func someTypeMethod()
}
The following example defines a protocol with a single instance method requirement:
protocol RandomNumberGenerator {
func random() -> Double
}
This protocol, RandomNumberGenerator, requires any conforming type to have an instance
method called random, which returns a Double value whenever it is called. (Although it is not
specified as part of the protocol, it is assumed that this value will be a number between
0.0 and 1.0 inclusive.)
The RandomNumberGenerator protocol does not make any assumptions about how each random
number will be generated—it simply requires the generator to provide a standard way to
generate a new random number.
Here’s an implementation of a class that adopts and conforms to the RandomNumberGenerator
protocol. This class implements a pseudorandom number generator algorithm known as a
linear congruential generator:
class LinearCongruentialGenerator: RandomNumberGenerator {
var lastRandom = 42.0
let m = 139968.0
let a = 3877.0
let c = 29573.0
func random() -> Double {
lastRandom = ((lastRandom * a + c) % m)
return lastRandom / m
}
generator = LinearCongruentialGenerator()
("Here's a random number: \(generator.random())")
prints "Here's a random number: 0.37464991998171"
("And another one: \(generator.random())")
prints "And another one: 0.729023776863283"
Mutating Method Requirements
It is sometimes necessary for a method to modify (or mutate) the instance it belongs to.
For instance methods on value types (that is, structures and enumerations) you place the
mutating keyword before a method’s func keyword to indicate that the method is allowed to
modify the instance it belongs to and/or any properties of that instance. This process is
described in Modifying Value Types from Within Instance Methods.
If you define a protocol instance method requirement that is intended to mutate
instances of any type that adopts the protocol, mark the method with the mutating keyword
as part of the protocol’s definition. This enables structures and enumerations to adopt the
protocol and satisfy that method requirement.
N O T E
If you mark a protocol instance method requirement as mutating, you do not need to write the mutating
keyword when writing an implementation of that method for a class. The mutating keyword is only used by
structures and enumerations.
The example below defines a protocol called Togglable, which defines a single instance
method requirement called toggle. As its name suggests, the toggle method is intended to
toggle or invert the state of any conforming type, typically by modifying a property of that
type.
The toggle method is marked with the mutating keyword as part of the Togglable protocol
definition, to indicate that the method is expected to mutate the state of a conforming
instance when it is called:
protocol Togglable {
mutating func toggle()
}
If you implement the Togglable protocol for a structure or enumeration, that structure or
enumeration can conform to the protocol by providing an implementation of the toggle
method that is also marked as mutating.
The example below defines an enumeration called OnOffSwitch. This enumeration toggles
between two states, indicated by the enumeration cases On and Off. The enumeration’s
toggle implementation is marked as mutating, to match the Togglable protocol’s requirements:
enum OnOffSwitch: Togglable {
case Off, On
mutating func toggle() {
switch self {
case Off:
self = On
case On:
self = Off
}
lightSwitch = OnOffSwitch.Off
lightSwitch.toggle()
lightSwitch is now equal to .On
Protocols as Types
Protocols do not actually implement any functionality themselves. Nonetheless, any
protocol you create will become a fully-fledged type for use in your code.
Because it is a type, you can use a protocol in many places where other types are
allowed, including:
N O T E
Because protocols are types, begin their names with a capital letter (such as FullyNamed and
RandomNumberGenerator) to match the names of other types in Swift (such as Int, String, and Double).
Here’s an example of a protocol used as a type:
class Dice {
let sides: Int
let generator: RandomNumberGenerator
init(sides: Int, generator: RandomNumberGenerator) {
self.sides = sides
self.generator = generator
}
func roll() -> Int {
return Int(generator.random() * Double(sides)) + 1
This example defines a new class called Dice, which represents an n-sided dice for use in a
board game. Dice instances have an integer property called sides, which represents how
many sides they have, and a property called generator, which provides a random number
generator from which to create dice roll values.
As a parameter type or return type in a function, method, or initializer
As the type of a constant, variable, or property
As the type of items in an array, dictionary, or other container
The generator property is of type RandomNumberGenerator. Therefore, you can set it to an
instance of any type that adopts the RandomNumberGenerator protocol. Nothing else is required
of the instance you assign to this property, except that the instance must adopt the
RandomNumberGenerator protocol.
Dice also has an initializer, to set up its initial state. This initializer has a parameter called
generator, which is also of type RandomNumberGenerator. You can pass a value of any conforming
type in to this parameter when initializing a new Dice instance.
Dice provides one instance method, roll, which returns an integer value between 1 and the
number of sides on the dice. This method calls the generator’s random method to create a
new random number between 0.0 and 1.0, and uses this random number to create a dice
roll value within the correct range. Because generator is known to adopt RandomNumberGenerator,
it is guaranteed to have a random method to call.
Here’s how the Dice class can be used to create a six-sided dice with a
LinearCongruentialGenerator instance as its random number generator:
var d6 = Dice(sides: 6, generator: LinearCongruentialGenerator())
for _ in 1...5 {
println("Random dice roll is \(d6.roll())")
}
// Random dice roll is 3
// Random dice roll is 5
// Random dice roll is 4
// Random dice roll is 5
// Random dice roll is 4
Delegation
Delegation is a design pattern that enables a class or structure to hand off (or delegate)
some of its responsibilities to an instance of another type. This design pattern is
implemented by defining a protocol that encapsulates the delegated responsibilities, such
that a conforming type (known as a delegate) is guaranteed to provide the functionality
that has been delegated. Delegation can be used to respond to a particular action, or to
retrieve data from an external source without needing to know the underlying type of that
source.
The example below defines two protocols for use with dice-based board games:
protocol DiceGame {
var dice: Dice { get }
func play()
}
protocol DiceGameDelegate {
func gameDidStart(game: DiceGame)
func game(game: DiceGame, didStartNewTurnWithDiceRoll diceRoll: Int)
func gameDidEnd(game: DiceGame)
}
The DiceGame protocol is a protocol that can be adopted by any game that involves dice.
The DiceGameDelegate protocol can be adopted by any type to track the progress of a DiceGame.
Here’s a version of the Snakes and Ladders game originally introduced in Control Flow.
This version is adapted to use a Dice instance for its dice-rolls; to adopt the DiceGame
protocol; and to notify a DiceGameDelegate about its progress:
class SnakesAndLadders: DiceGame {
let finalSquare = 25
let dice = Dice(sides: 6, generator: LinearCongruentialGenerator())
var square = 0
var board: Int[]
init() {
board = Int[](count: finalSquare + 1, repeatedValue: 0)
board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02
board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08
var delegate: DiceGameDelegate?
func play() {
square = 0
delegate?.gameDidStart(self)
gameLoop: while square != finalSquare {
let diceRoll = dice.roll()
delegate?.game(self, didStartNewTurnWithDiceRoll: diceRoll)
switch square + diceRoll {
case finalSquare:
break gameLoop
case let newSquare where newSquare > finalSquare:
continue gameLoop
default:
square += diceRoll
square += board[square]
}
}
delegate?.gameDidEnd(self)
For a description of the Snakes and Ladders gameplay, see the Break section of the
Control Flow chapter.
This version of the game is wrapped up as a class called SnakesAndLadders, which adopts the
DiceGame protocol. It provides a gettable dice property and a play method in order to conform
to the protocol. (The dice property is declared as a constant property because it does not
need to change after initialization, and the protocol only requires that it is gettable.)
The Snakes and Ladders game board setup takes place within the class’s init() initializer.
All game logic is moved into the protocol’s play method, which uses the protocol’s required
dice property to provide its dice roll values.
Note that the delegate property is defined as an optional DiceGameDelegate, because a delegate
isn’t required in order to play the game. Because it is of an optional type, the delegate
property is automatically set to an initial value of nil. Thereafter, the game instantiator has
the option to set the property to a suitable delegate.
DiceGameDelegate provides three methods for tracking the progress of a game. These three
methods have been incorporated into the game logic within the play method above, and
are called when a new game starts, a new turn begins, or the game ends.
Because the delegate property is an optional DiceGameDelegate, the play method uses optional
chaining each time it calls a method on the delegate. If the delegate property is nil, these
delegate calls fail gracefully and without error. If the delegate property is non-nil, the
delegate methods are called, and are passed the SnakesAndLadders instance as a parameter.
This next example shows a class called DiceGameTracker, which adopts the DiceGameDelegate
protocol:
class DiceGameTracker: DiceGameDelegate {
var numberOfTurns = 0
func gameDidStart(game: DiceGame) {
numberOfTurns = 0
if game is SnakesAndLadders {
println("Started a new game of Snakes and Ladders")
}
println("The game is using a \(game.dice.sides)-sided dice")
}
func game(game: DiceGame, didStartNewTurnWithDiceRoll diceRoll: Int) {
++numberOfTurns
println("Rolled a \(diceRoll)")
func gameDidEnd(game: DiceGame) {
println("The game lasted for \(numberOfTurns) turns")
DiceGameTracker implements all three methods required by DiceGameDelegate. It uses these
methods to keep track of the number of turns a game has taken. It resets a numberOfTurns
property to zero when the game starts; increments it each time a new turn begins; and
prints out the total number of turns once the game has ended.
The implementation of gameDidStart shown above uses the game parameter to print some
introductory information about the game that is about to be played. The game parameter
has a type of DiceGame, not SnakesAndLadders, and so gameDidStart can access and use only
methods and properties that are implemented as part of the DiceGame protocol. However,
the method is still able to use type casting to query the type of the underlying instance.
In this example, it checks whether game is actually an instance of SnakesAndLadders behind the
scenes, and prints an appropriate message if so.
gameDidStart also accesses the dice property of the passed game parameter. Because game is
known to conform to the DiceGame protocol, it is guaranteed to have a dice property, and so
the gameDidStart method is able to access and print the dice’s sides property, regardless of
what kind of game is being played.
Here’s how DiceGameTracker looks in action:
let tracker = DiceGameTracker()
let game = SnakesAndLadders()
game.delegate = tracker
game.play()
// Started a new game of Snakes and Ladders
// The game is using a 6-sided dice
// Rolled a 3
// Rolled a 5
// Rolled a 4
Rolled a 5
The game lasted for 4 turns
Adding Protocol Conformance with an Extension
You can extend an existing type to adopt and conform to a new protocol, even if you do
not have access to the source code for the existing type. Extensions can add new
properties, methods, and subscripts to an existing type, and are therefore able to add any
requirements that a protocol may demand. For more about extensions, see Extensions.
N O T E
Existing instances of a type automatically adopt and conform to a protocol when that conformance is added to
the instance’s type in an extension.
For example, this protocol, called TextRepresentable, can be implemented by any type that
has a way to be represented as text. This might be a description of itself, or a text
version of its current state:
protocol TextRepresentable {
func asText() -> String
}
The Dice class from earlier can be extended to adopt and conform to TextRepresentable:
extension Dice: TextRepresentable {
func asText() -> String {
return "A \(sides)-sided dice"
}
}
This extension adopts the new protocol in exactly the same way as if Dice had provided it
in its original implementation. The protocol name is provided after the type name,
separated by a colon, and an implementation of all requirements of the protocol is
provided within the extension’s curly braces.
Any Dice instance can now be treated as TextRepresentable:
let d12 = Dice(sides: 12, generator: LinearCongruentialGenerator())
println(d12.asText())
// prints "A 12-sided dice"
Similarly, the SnakesAndLadders game class can be extended to adopt and conform to the
TextRepresentable protocol:
extension SnakesAndLadders: TextRepresentable {
func asText() -> String {
return "A game of Snakes and Ladders with \(finalSquare) squares"
}
}
println(game.asText())
// prints "A game of Snakes and Ladders with 25 squares"
Declaring Protocol Adoption with an Extension
If a type already conforms to all of the requirements of a protocol, but has not yet stated
that it adopts that protocol, you can make it adopt the protocol with an empty extension:
struct Hamster {
var name: String
func asText() -> String {
return "A hamster named \(name)"
}
}
extension Hamster: TextRepresentable {}
Instances of Hamster can now be used wherever TextRepresentable is the required type:
let simonTheHamster = Hamster(name: "Simon")
let somethingTextRepresentable: TextRepresentable = simonTheHamster
println(somethingTextRepresentable.asText())
// prints "A hamster named Simon"
N O T E
Types do not automatically adopt a protocol just by satisfying its requirements. They must always explicitly
declare their adoption of the protocol.
Collections of Protocol Types
A protocol can be used as the type to be stored in a collection such as an array or a
dictionary, as mentioned in Protocols as Types. This example creates an array of
TextRepresentable things:
let things: TextRepresentable[] = [game, d12, simonTheHamster]
It is now possible to iterate over the items in the array, and print each item’s textual
representation:
for thing in things {
println(thing.asText())
}
// A game of Snakes and Ladders with 25 squares
// A 12-sided dice
// A hamster named Simon
Note that the thing constant is of type TextRepresentable. It is not of type Dice, or DiceGame, or
Hamster, even if the actual instance behind the scenes is of one of those types.
Nonetheless, because it is of type TextRepresentable, and anything that is TextRepresentable is
known to have an asText method, it is safe to call thing.asText each time through the loop.
Protocol Inheritance
A protocol can inherit one or more other protocols and can add further requirements on
top of the requirements it inherits. The syntax for protocol inheritance is similar to the
syntax for class inheritance, but with the option to list multiple inherited protocols,
separated by commas:
protocol InheritingProtocol: SomeProtocol, AnotherProtocol {
// protocol definition goes here
}
Here’s an example of a protocol that inherits the TextRepresentable protocol from above:
protocol PrettyTextRepresentable: TextRepresentable {
func asPrettyText() -> String
}
This example defines a new protocol, PrettyTextRepresentable, which inherits from
TextRepresentable. Anything that adopts PrettyTextRepresentable must satisfy all of the
requirements enforced by TextRepresentable, plus the additional requirements enforced by
PrettyTextRepresentable. In this example, PrettyTextRepresentable adds a single requirement to
provide an instance method called asPrettyText that returns a String.
The SnakesAndLadders class can be extended to adopt and conform to PrettyTextRepresentable:
extension SnakesAndLadders: PrettyTextRepresentable {
func asPrettyText() -> String {
var output = asText() + ":¶
"
for index in 1...finalSquare {
switch board[index] {
case let ladder where ladder > 0:
output += "▲ "
case let snake where snake < 0:
output += "▼ "
default:
output += "○ "
}
}
return output
This extension states that it adopts the PrettyTextRepresentable protocol and provides an
implementation of the asPrettyText method for the SnakesAndLadders type. Anything that is
PrettyTextRepresentable must also be TextRepresentable, and so the asPrettyText implementation
starts by calling the asText method from the TextRepresentable protocol to begin an output
string. It appends a colon and a line break, and uses this as the start of its pretty text
representation. It then iterates through the array of board squares, and appends an emoji
representation for each square:
The method implementation can now be used to print a pretty text description of any
SnakesAndLadders instance:
println(game.asPrettyText())
// A game of Snakes and Ladders with 25 squares:
// ○ ○ ▲ ○ ○ ▲ ○ ○ ▲ ▲ ○ ○ ○ ▼ ○ ○ ○ ○ ▼ ○ ○ ▼ ○ ▼ ○
If the square’s value is greater than 0, it is the base of a ladder, and is
represented by ▲.
If the square’s value is less than 0, it is the head of a snake, and is represented by
▼.
Otherwise, the square’s value is 0, and it is a “free” square, represented by ○.
Protocol Composition
It can be useful to require a type to conform to multiple protocols at once. You can
combine multiple protocols into a single requirement with a protocol composition.
Protocol compositions have the form protocol. You can list as many
protocols within the pair of angle brackets (<>) as you need, separated by commas.
Here’s an example that combines two protocols called Named and Aged into a single
protocol composition requirement on a function parameter:
protocol Named {
var name: String { get }
}
protocol Aged {
var age: Int { get }
}
struct Person: Named, Aged {
var name: String
var age: Int
wishHappyBirthday(celebrator: protocol) {
println("Happy birthday \(celebrator.name) - you're \(celebrator.age)!")
birthdayPerson = Person(name: "Malcolm", age: 21)
wishHappyBirthday(birthdayPerson)
prints "Happy birthday Malcolm - you're 21!"
This example defines a protocol called Named, with a single requirement for a gettable String
property called name. It also defines a protocol called Aged, with a single requirement for a
gettable Int property called age. Both of these protocols are adopted by a structure called
Person.
The example also defines a function called wishHappyBirthday, which takes a single parameter
called celebrator. The type of this parameter is protocol, which means “any type
that conforms to both the Named and Aged protocols.” It doesn’t matter what specific type is
passed to the function, as long as it conforms to both of the required protocols.
The example then creates a new Person instance called birthdayPerson and passes this new
instance to the wishHappyBirthday function. Because Person conforms to both protocols, this is a
valid call, and the wishHappyBirthday function is able to print its birthday greeting.
N O T E
Protocol compositions do not define a new, permanent protocol type. Rather, they define a temporary local
protocol that has the combined requirements of all protocols in the composition.
Checking for Protocol Conformance
You can use the is and as operators described in Type Casting to check for protocol
conformance, and to cast to a specific protocol. Checking for and casting to a protocol
follows exactly the same syntax as checking for and casting to a type:
This example defines a protocol called HasArea, with a single property requirement of a
gettable Double property called area:
@objc protocol HasArea {
var area: Double { get }
}
N O T E
You can check for protocol conformance only if your protocol is marked with the @objc attribute, as seen for
the HasArea protocol above. This attribute indicates that the protocol should be exposed to Objective-C code
and is described in Using Swift with Cocoa and Objective-C. Even if you are not interoperating with Objective-C,
you need to mark your protocols with the @objc attribute if you want to be able to check for protocol
conformance.
Note also that @objc protocols can be adopted only by classes, and not by structures or enumerations. If you
mark your protocol as @objc in order to check for conformance, you will be able to apply that protocol only to
class types.
The is operator returns true if an instance conforms to a protocol and returns false if
it does not.
The as? version of the downcast operator returns an optional value of the
protocol’s type, and this value is nil if the instance does not conform to that
protocol.
The as version of the downcast operator forces the downcast to the protocol type
and triggers a runtime error if the downcast does not succeed.
Here are two classes, Circle and Country, both of which conform to the HasArea protocol:
class Circle: HasArea {
let pi = 3.1415927
var radius: Double
var area: Double { return pi * radius * radius }
init(radius: Double) { self.radius = radius }
}
class Country: HasArea {
var area: Double
init(area: Double) { self.area = area }
The Circle class implements the area property requirement as a computed property, based
on a stored radius property. The Country class implements the area requirement directly as a
stored property. Both classes correctly conform to the HasArea protocol.
Here’s a class called Animal, which does not conform to the HasArea protocol:
class Animal {
var legs: Int
init(legs: Int) { self.legs = legs }
}
The Circle, Country and Animal classes do not have a shared base class. Nonetheless, they are
all classes, and so instances of all three types can be used to initialize an array that
stores values of type AnyObject:
let objects: AnyObject[] = [
Circle(radius: 2.0),
Country(area: 243_610),
Animal(legs: 4)
]
The objects array is initialized with an array literal containing a Circle instance with a radius
of 2 units; a Country instance initialized with the surface area of the United Kingdom in
square kilometers; and an Animal instance with four legs.
The objects array can now be iterated, and each object in the array can be checked to see
if it conforms to the HasArea protocol:
for object in objects {
if let objectWithArea = object as? HasArea {
println("Area is \(objectWithArea.area)")
} else {
println("Something that doesn't have an area")
}
}
// Area is 12.5663708
// Area is 243610.0
Something that doesn't have an area
Whenever an object in the array conforms to the HasArea protocol, the optional value
returned by the as? operator is unwrapped with optional binding into a constant called
objectWithArea. The objectWithArea constant is known to be of type HasArea, and so its area
property can be accessed and printed in a type-safe way.
Note that the underlying objects are not changed by the casting process. They continue
to be a Circle, a Country and an Animal. However, at the point that they are stored in the
objectWithArea constant, they are only known to be of type HasArea, and so only their area
property can be accessed.
Optional Protocol Requirements
You can define optional requirements for protocols, These requirements do not have to
be implemented by types that conform to the protocol. Optional requirements are
prefixed by the @optional keyword as part of the protocol’s definition.
An optional protocol requirement can be called with optional chaining, to account for the
possibility that the requirement was not implemented by a type that conforms to the
protocol. For information on optional chaining, see Optional Chaining.
You check for an implementation of an optional requirement by writing a question mark
after the name of the requirement when it is called, such as someOptionalMethod?(someArgument).
Optional property requirements, and optional method requirements that return a value,
will always return an optional value of the appropriate type when they are accessed or
called, to reflect the fact that the optional requirement may not have been implemented.
N O T E
Optional protocol requirements can only be specified if your protocol is marked with the @objc attribute. Even if
you are not interoperating with Objective-C, you need to mark your protocols with the @objc attribute if you
want to specify optional requirements.
Note also that @objc protocols can be adopted only by classes, and not by structures or enumerations. If you
mark your protocol as @objc in order to specify optional requirements, you will only be able to apply that
protocol to class types.
The following example defines an integer-counting class called Counter, which uses an
external data source to provide its increment amount. This data source is defined by the
CounterDataSource protocol, which has two optional requirements:
@objc protocol CounterDataSource {
@optional func incrementForCount(count: Int) -> Int
@optional var fixedIncrement: Int { get }
}
The CounterDataSource protocol defines an optional method requirement called incrementForCount
and an optional property requirement called fixedIncrement. These requirements define two
different ways for data sources to provide an appropriate increment amount for a Counter
instance.
N O T E
Strictly speaking, you can write a custom class that conforms to CounterDataSource without implementing
either protocol requirement. They are both optional, after all. Although technically allowed, this wouldn’t make
for a very good data source.
The Counter class, defined below, has an optional dataSource property of type CounterDataSource?:
@objc class Counter {
var count = 0
var dataSource: CounterDataSource?
func increment() {
if let amount = dataSource?.incrementForCount?(count) {
count += amount
} else if let amount = dataSource?.fixedIncrement? {
count += amount
}
The Counter class stores its current value in a variable property called count. The Counter class
also defines a method called increment, which increments the count property every time the
method is called.
The increment method first tries to retrieve an increment amount by looking for an
implementation of the incrementForCount method on its data source. The increment method uses
optional chaining to try to call incrementForCount, and passes the current count value as the
method’s single argument.
Note two levels of optional chaining at play here. Firstly, it is possible that dataSource may
be nil, and so dataSource has a question mark after its name to indicate that incrementForCount
should only be called if dataSource is non-nil. Secondly, even if dataSource does exist, there is
no guarantee that it implements incrementForCount, because it is an optional requirement.
This is why incrementForCount is also written with a question mark after its name.
Because the call to incrementForCount can fail for either of these two reasons, the call returns
an optional Int value. This is true even though incrementForCount is defined as returning a nonoptional
Int value in the definition of CounterDataSource.
After calling incrementForCount, the optional Int that it returns is unwrapped into a constant
called amount, using optional binding. If the optional Int does contain a value—that is, if the
delegate and method both exist, and the method returned a value—the unwrapped amount
is added onto the stored count property, and incrementation is complete.
If it is not possible to retrieve a value from the incrementForCount method—either because
dataSource is nil, or because the data source does not implement incrementForCount—then the
increment method tries to retrieve a value from the data source’s fixedIncrement property
instead. The fixedIncrement property is also an optional requirement, and so its name is also
written using optional chaining with a question mark on the end, to indicate that the
attempt to access the property’s value can fail. As before, the returned value is an
optional Int value, even though fixedIncrement is defined as a non-optional Int property as
part of the CounterDataSource protocol definition.
Here’s a simple CounterDataSource implementation where the data source returns a constant
value of 3 every time it is queried. It does this by implementing the optional fixedIncrement
property requirement:
class ThreeSource: CounterDataSource {
let fixedIncrement = 3
}
You can use an instance of ThreeSource as the data source for a new Counter instance:
var counter = Counter()
counter.dataSource = ThreeSource()
for _ in 1...4 {
counter.increment()
println(counter.count)
}
// 3
// 6
// 9
The code above creates a new Counter instance; sets its data source to be a new ThreeSource
instance; and calls the counter’s increment method four times. As expected, the counter’s
count property increases by three each time increment is called.
Here’s a more complex data source called TowardsZeroSource, which makes a Counter instance
count up or down towards zero from its current count value:
class TowardsZeroSource: CounterDataSource {
func incrementForCount(count: Int) -> Int {
if count == 0 {
return 0
} else if count < 0 {
return 1
} else {
return -1
}
The TowardsZeroSource class implements the optional incrementForCount method from the
CounterDataSource protocol and uses the count argument value to work out which direction to
count in. If count is already zero, the method returns 0 to indicate that no further counting
should take place.
You can use an instance of TowardsZeroSource with the existing Counter instance to count from -
4 to zero. Once the counter reaches zero, no more counting takes place:
counter.count = -4
counter.dataSource = TowardsZeroSource()
for _ in 1...5 {
counter.increment()
println(counter.count)
}
// -3
// -2
// -1
chapter24
# 24 제네릭

Write here..
(Generics)
> Translator : 이름 (메일주소)

Generic code enables you to write flexible, reusable functions and types that can work with any type, subject to requirements that you define. You can write code that avoids duplication and expresses its intent in a clear, abstracted manner.

Generics are one of the most powerful features of Swift, and much of the Swift standard library is built with generic code. In fact, you’ve been using generics throughout this Language Guide, even if you didn’t realize it. For example, Swift’s `Array` and `Dictionary` types are both generic collections. You can create an array that holds `Int` values, or an array that holds `String` values, or indeed an array for any other type that can be created in Swift. Similarly, you can create a dictionary to store values of any specified type, and there are no limitations on what that type can be.


## The Problem That Generics Solve
Here’s a standard, non-generic function called `swapTwoInts`, which swaps two `Int` values:

```
func swapTwoInts(inout a: Int, inout b: Int) {
let temporaryA = a
a = b
b = temporaryA
}
```

This function makes use of in-out parameters to swap the values of `a` and `b`, as described in [In-Out Parameters](#).

The `swapTwoInts` function swaps the original value of `b` into `a`, and the original value of `a` into `b`. You can call this function to swap the values in two `Int` variables:

```
var someInt = 3
var anotherInt = 107
println("someInt is now \(someInt), and anotherInt is now \(anotherInt)")
// prints "someInt is now 107, and anotherInt is now 3"
```

The `swapTwoInts` function is useful, but it can only be used with `Int` values. If you want to swap two `String` values, or two `Double` values, you have to write more functions, such as the `swapTwoStrings` and `swapTwoDoubles` functions shown below:

```
func swapTwoStrings(inout a: String, inout b: String) {
let temporaryA = a
a = b
b = temporaryA
}

func swapTwoDoubles(inout a: Double, inout b: Double) {
let temporaryA = a
a = b
b = temporaryA
}
```

You may have noticed that the bodies of the `swapTwoInts`, `swapTwoStrings`, and `swapTwoDoubles` functions are identical. The only difference is the type of the values that they accept (`Int`, `String`, and `Double`).

It would be much more useful, and considerably more flexible, to write a single function that could swap two values of any type. This is the kind of problem that generic code can solve. (A generic version of these functions is defined below.)

> **NOTE**
> In all three functions, it is important that the types of `a` and `b` are defined to be the same as each other. If `a` and `b` were not of the same type, it would not be possible to swap their values. Swift is a type-safe language, and does not allow (for example) a variable of type `String` and a variable of type `Double` to swap values with each other. Attempting to do so would be reported as a compile-time error.

## Generic Functions
*Generic functions* can work with any type. Here’s a generic version of the `swapTwoInts` function from above, called `swapTwoValues`:
```
func swapTwoValues(inout a: T, inout b: T) {
let temporaryA = a
a = b
b = temporaryA
}
```

The body of the `swapTwoValues` function is identical to the body of the `swapTwoInts` function. However, the first line of `swapTwoValues` is slightly different from `swapTwoInts`. Here’s how the first lines compare:

```
func swapTwoInts(inout a: Int, inout b: Int)
func swapTwoValues(inout a: T, inout b: T)
```

The generic version of the function uses a placeholder type name (called `T`, in this case) instead of an actual type name (such as `Int`, `String`, or `Double`). The placeholder type name doesn’t say anything about what `T` must be, but it does say that both `a` and `b` must be of the same type `T`, whatever `T` represents. The actual type to use in place of `T` will be determined each time the `swapTwoValues` function is called.

The other difference is that the generic function’s name (`swapTwoValues`) is followed by the placeholder type name (`T`) inside angle brackets (``). The brackets tell Swift that `T` is a placeholder type name within the `swapTwoValues` function definition. Because `T` is a placeholder, Swift does not look for an actual type called `T`.

The `swapTwoValues` function can now be called in the same way as `swapTwoInts`, except that it can be passed two values of any type, as long as both of those values are of the same type as each other. Each time `swapTwoValues` is called, the type to use for `T` is inferred from the types of values passed to the function.

In the two examples below, `T` is inferred to be `Int` and `String` respectively:

```
var someInt = 3
var anotherInt = 107
swapTwoValues(&someInt, &anotherInt)
// someInt is now 107, and anotherInt is now 3

var someString = "hello"
var anotherString = "world"
swapTwoValues(&someString, &anotherString)
// someString is now "world", and anotherString is now "hello"
```

> **NOTE**
> The `swapTwoValues` function defined above is inspired by a generic function called `swap`, which is part of the Swift standard library, and is automatically made available for you to use in your apps. If you need the behavior of the `swapTwoValues` function in your own code, you can use Swift’s existing `swap` function rather than providing your own implementation.

## Type Parameters
In the `swapTwoValues` example above, the placeholder type `T` is an example of a type parameter. Type parameters specify and name a placeholder type, and are written immediately after the function’s name, between a pair of matching angle brackets (such as ``).

Once specified, a type parameter can be used to define the type of a function’s parameters (such as the `a` and `b` parameters of the `swapTwoValues` function); or as the function’s return type; or as a type annotation within the body of the function. In each case, the placeholder type represented by the type parameter is replaced with an actual type whenever the function is called. (In the `swapTwoValues` example above, `T` was replaced with `Int` the first time the function was called, and was replaced with `String` the second time it was called.)

You can provide more than one type parameter by writing multiple type parameter names within the angle brackets, separated by commas.

## Naming Type Parameters
In simple cases where a generic function or generic type needs to refer to a single placeholder type (such as the `swapTwoValues` generic function above, or a generic collection that stores a single type, such as `Array`), it is traditional to use the single-character name `T` for the type parameter. However, you are can use any valid identifier as the type parameter name.

If you are defining more complex generic functions, or generic types with multiple parameters, it can be useful to provide more descriptive type parameter names. For example, Swift’s `Dictionary` type has two type parameters—one for its keys and one for its values. If you were writing `Dictionary` yourself, you might name these two type parameters `KeyType` and `ValueType` to remind you of their purpose as you use them within your generic code.

> **NOTE**
> Always give type parameters UpperCamelCase names (such as T and KeyType) to indicate that they are a placeholder for a type, not a value.

## Generic Types
In addition to generic functions, Swift enables you to define your own generic types. These are custom classes, structures, and enumerations that can work with any type, in a similar way to `Array` and `Dictionary`.

This section shows you how to write a generic collection type called `Stack`. A stack is an ordered set of values, similar to an array, but with a more restricted set of operations than Swift’s `Array` type. An array allows new items to be inserted and removed at any location in the array. A stack, however, allows new items to be appended only to the end of the collection (known as pushing a new value on to the stack). Similarly, a stack allows items to be removed only from the end of the collection (known as popping a value off the stack).

> **NOTE**
> The concept of a stack is used by the `UINavigationController` class to model the view controllers in its navigation hierarchy. You call the `UINavigationController` class `pushViewController:animated:` method to add (or push) a view controller on to the navigation stack, and its `popViewControllerAnimated:` method to remove (or pop) a view controller from the navigation stack. A stack is a useful collection model whenever you need a strict “last in, first out” approach to managing a collection.

The illustration below shows the push / pop behavior for a stack:

![p595-1.png](images/p595-1.png)

1. There are currently three values on the stack.
2. A fourth value is “pushed” on to the top of the stack.
3. The stack now holds four values, with the most recent one at the top.
4. The top item in the stack is removed, or “popped”.
5. After popping a value, the stack once again holds three values.

Here’s how to write a non-generic version of a stack, in this case for a stack of `Int` values:

```
struct IntStack {
var items = Int[]()
mutating func push(item: Int) {
items.append(item)
}
mutating func pop() -> Int {
return items.removeLast()
}
}
```

This structure uses an `Array` property called `items` to store the values in the stack. `Stack` provides two methods, `push` and `pop`, to push and pop values on and off the stack. These methods are marked as `mutating`, because they need to modify (or mutate) the structure’s `items` array.

The `IntStack` type shown above can only be used with `Int` values, however. It would be much more useful to define a generic `Stack` class, that can manage a stack of any type of value.

Here’s a generic version of the same code:

```
struct Stack {
var items = T[]()
mutating func push(item: T) {
items.append(item)
}
mutating func pop() -> T {
return items.removeLast()
}
}
```

Note how the generic version of `Stack` is essentially the same as the non-generic version, but with a placeholder type parameter called `T` instead of an actual type of `Int`. This type parameter is written within a pair of angle brackets (``) immediately after the structure’s name.

`T` defines a placeholder name for “some type `T`” to be provided later on. This future type can be referred to as “`T`” anywhere within the structure’s definition. In this case, `T` is used as a placeholder in three places:

- To create a property called `items`, which is initialized with an empty array of values of type `T`
- To specify that the `push` method has a single parameter called `item`, which must be of type `T`
- To specify that the value returned by the `pop` method will be a value of type `T`

You create instances of `Stack` in a similar way to `Array` and `Dictionary`, by writing the actual type to be used for this specific stack within angle brackets after the type name when creating a new instance with initializer syntax:

```
var stackOfStrings = Stack()
stackOfStrings.push("uno")
stackOfStrings.push("dos")
stackOfStrings.push("tres")
stackOfStrings.push("cuatro")
// the stack now contains 4 strings
```

Here’s how `stackOfStrings` looks after pushing these four values on to the stack:

![p599-1.png](images/p599-1.png)

Popping a value from the stack returns and removes the top value, `"cuatro"`:

```
let fromTheTop = stackOfStrings.pop()
// fromTheTop is equal to "cuatro", and the stack now contains 3 strings
```

Here’s how the stack looks after popping its top value:

![p599-2.png](images/p599-2.png)

Because it is a generic type, `Stack` can be used to create a stack of any valid type in Swift, in a similar manner to `Array` and `Dictionary`.

## Type Constraints
The `swapTwoValues` function and the `Stack` type can work with any type. However, it is sometimes useful to enforce certain type constraints on the types that can be used with generic functions and generic types. Type constraints specify that a type parameter must inherit from a specific class, or conform to a particular protocol or protocol composition.

For example, Swift’s `Dictionary` type places a limitation on the types that can be used as keys for a dictionary. As described in [Dictionaries](#), the type of a dictionary’s keys must be hashable. That is, it must provide a way to make itself uniquely representable. `Dictionary` needs its keys to be hashable so that it can check whether it already contains a value for a particular key. Without this requirement, `Dictionary` could not tell whether it should insert or replace a value for a particular key, nor would it be able to find a value for a given key that is already in the dictionary.

This requirement is enforced by a type constraint on the key type for `Dictionary`, which specifies that the key type must conform to the `Hashable` protocol, a special protocol defined in the Swift standard library. All of Swift’s basic types (such as `String`, `Int`, `Double`, and `Bool`) are hashable by default.

You can define your own type constraints when creating custom generic types, and these constraints provide much of the power of generic programming. Abstract concepts like `Hashable` characterize types in terms of their conceptual characteristics, rather than their explicit type.

### Type Constraint Syntax
You write type constraints by placing a single class or protocol constraint after a type parameter’s name, separated by a colon, as part of the type parameter list. The basic syntax for type constraints on a generic function is shown below (although the syntax is the same for generic types):

```
func someFunction(someT: T, someU: U) {
// function body goes here
}
```

The hypothetical function above has two type parameters.

The first type parameter, `T`, has a type constraint that requires `T` to be a subclass of `SomeClass`. The second type parameter, `U`, has a type constraint that requires `U` to conform to the protocol `SomeProtocol`.

### Type Constraints in Action
Here’s a non-generic function called `findStringIndex`, which is given a `String` value to find and an array of `String` values within which to find it. The `findStringIndex` function returns an optional `Int` value, which will be the index of the first matching string in the array if it is found, or `nil` if the string cannot be found:

```
func findStringIndex(array: String[], valueToFind: String) -> Int? {
for (index, value) in enumerate(array) {
if value == valueToFind {
return index
}
}
return nil
}
```

The `findStringIndex` function can be used to find a string value in an array of strings:

```
let strings = ["cat", "dog", "llama", "parakeet", "terrapin"]
if let foundIndex = findStringIndex(strings, "llama") {
println("The index of llama is \(foundIndex)")
}
// prints "The index of llama is 2"
```

The principle of finding the index of a value in an array isn’t useful only for strings, however. You can write the same functionality as a generic function called `findIndex`, by replacing any mention of strings with values of some type `T` instead.

Here’s how you might expect a generic version of `findStringIndex`, called `findIndex`, to be written. Note that the return type of this function is still `Int?`, because the function returns an optional index number, not an optional value from the array. Be warned, though—this function does not compile, for reasons explained after the example:

```
func findIndex(array: T[], valueToFind: T) -> Int? {
for (index, value) in enumerate(array) {
if value == valueToFind {
return index
}
}
return nil
}
```

This function does not compile as written above. The problem lies with the equality check, `“if value == valueToFind”`. Not every type in Swift can be compared with the equal to operator (`==`). If you create your own class or structure to represent a complex data model, for example, then the meaning of “equal to” for that class or structure is not something that Swift can guess for you. Because of this, it is not possible to guarantee that this code will work for every possible type `T`, and an appropriate error is reported when you try to compile the code.

All is not lost, however. The Swift standard library defines a protocol called `Equatable`, which requires any conforming type to implement the equal to operator (`==`) and the not equal to operator (`!=`) to compare any two values of that type. All of Swift’s standard types automatically support the `Equatable` protocol.

Any type that is `Equatable` can be used safely with the `findIndex` function, because it is guaranteed to support the equal to operator. To express this fact, you write a type constraint of `Equatable` as part of the type parameter’s definition when you define the function:

```
func findIndex(array: T[], valueToFind: T) -> Int? {
for (index, value) in enumerate(array) {
if value == valueToFind {
return index
}
}
return nil
}
```

The single type parameter for `findIndex` is written as `T: Equatable`, which means “any type `T` that conforms to the `Equatable` protocol.”

The `findIndex` function now compiles successfully and can be used with any type that is `Equatable`, such as `Double` or `String`:

```
let doubleIndex = findIndex([3.14159, 0.1, 0.25], 9.3)
// doubleIndex is an optional Int with no value, because 9.3 is not in the array
let stringIndex = findIndex(["Mike", "Malcolm", "Andrea"], "Andrea")
// stringIndex is an optional Int containing a value of 2
```

## Associated Types
When defining a protocol, it is sometimes useful to declare one or more associated types as part of the protocol’s definition. An associated type gives a placeholder name (or alias) to a type that is used as part of the protocol. The actual type to use for that associated type is not specified until the protocol is adopted. Associated types are specified with the `typealias` keyword.


### Associated Types in Action
Here’s an example of a protocol called `Container`, which declares an associated type called `ItemType`:

```
protocol Container {
typealias ItemType
mutating func append(item: ItemType)
var count: Int { get }
subscript(i: Int) -> ItemType { get }
}
```

The `Container` protocol defines three required capabilities that any container must provide:

- It must be possible to add a new item to the container with an `append` method.
- It must be possible to access a count of the items in the container through a `count` property that returns an `Int` value.
- It must be possible to retrieve each item in the container with a subscript that takes an `Int` index value.

This protocol doesn’t specify how the items in the container should be stored or what type they are allowed to be. The protocol only specifies the three bits of functionality that any type must provide in order to be considered a `Container`. A conforming type can provide additional functionality, as long as it satisfies these three requirements.

Any type that conforms to the `Container` protocol must be able to specify the type of values it stores. Specifically, it must ensure that only items of the right type are added to the container, and it must be clear about the type of the items returned by its subscript.

To define these requirements, the `Container` protocol needs a way to refer to the type of the elements that a container will hold, without knowing what that type is for a specific container. The `Container` protocol needs to specify that any value passed to the `append` method must have the same type as the container’s element type, and that the value returned by the container’s subscript will be of the same type as the container’s element type.

To achieve this, the `Container` protocol declares an associated type called `ItemType`, written as `typealias ItemType`. The protocol does not define what `ItemType` is an alias for—that information is left for any conforming type to provide. Nonetheless, the `ItemType` alias provides a way to refer to the type of the items in a `Container`, and to define a type for use with the `append` method and subscript, to ensure that the expected behavior of any `Container` is enforced.

Here’s a version of the non-generic `IntStack` type from earlier, adapted to conform to the `Container` protocol:

```
“struct IntStack: Container {
// original IntStack implementation
var items = Int[]()
mutating func push(item: Int) {
items.append(item)
}
mutating func pop() -> Int {
return items.removeLast()
}
// conformance to the Container protocol
typealias ItemType = Int
mutating func append(item: Int) {
self.push(item)
}
var count: Int {
return items.count
}
subscript(i: Int) -> Int {
return items[i]
}
}
```

The `IntStack` type implements all three of the `Container` protocol’s requirements, and in each case wraps part of the `IntStack` type’s existing functionality to satisfy these requirements.

Moreover, `IntStack` specifies that for this implementation of `Container`, the appropriate `ItemType` to use is a type of `Int`. The definition of `typealias ItemType = Int` turns the abstract type of `ItemType` into a concrete type of `Int` for this implementation of the `Container` protocol.

Thanks to Swift’s type inference, you don’t actually need to declare a concrete `ItemType` of `Int` as part of the definition of `IntStack`. Because `IntStack` conforms to all of the requirements of the `Container` protocol, Swift can infer the appropriate `ItemType` to use, simply by looking at the type of the `append` method’s `item` parameter and the return type of the subscript. Indeed, if you delete the `typealias ItemType = Int` line from the code above, everything still works, because it is clear what type should be used for `ItemType`.

You can also make the generic `Stack` type conform to the `Container` protocol:

```
struct Stack: Container {
// original Stack implementation
var items = T[]()
mutating func push(item: T) {
items.append(item)
}
mutating func pop() -> T {
return items.removeLast()
}
// conformance to the Container protocol
mutating func append(item: T) {
self.push(item)
}
var count: Int {
return items.count
}
subscript(i: Int) -> T {
return items[i]
}
}
```

This time, the placeholder type parameter `T` is used as the type of the `append` method’s `item` parameter and the return type of the subscript. Swift can therefore infer that `T` is the appropriate type to use as the `ItemType` for this particular container.

### Extending an Existing Type to Specify an Associated Type
You can extend an existing type to add conformance to a protocol, as described in [Adding Protocol Conformance with an Extension](#). This includes a protocol with an associated type.

Swift’s `Array` type already provides an `append` method, a `count` property, and a subscript with an `Int` index to retrieve its elements. These three capabilities match the requirements of the `Container` protocol. This means that you can extend `Array` to conform to the `Container` protocol simply by declaring that `Array` adopts the protocol. You do this with an empty extension, as described in [Declaring Protocol Adoption with an Extension](#):

```
extension Array: Container {}
```

Array’s existing `append` method and subscript enable Swift to infer the appropriate type to use for `ItemType`, just as for the generic `Stack` type above. After defining this extension, you can use any `Array` as a `Container`.

## Where Clauses
Type constraints, as described in [Type Constraints](#), enable you to define requirements on the type parameters associated with a generic function or type.

It can also be useful to define requirements for associated types. You do this by defining where clauses as part of a type parameter list. A `where` clause enables you to require that an associated type conforms to a certain protocol, and/or that certain type parameters and associated types be the same. You write a where clause by placing the where keyword immediately after the list of type parameters, followed by one or more constraints for associated types, and/or one or more equality relationships between types and associated types.

The example below defines a generic function called `allItemsMatch`, which checks to see if two `Container` instances contain the same items in the same order. The function returns a Boolean value of `true` if all items match and a value of `false` if they do not.

The two containers to be checked do not have to be the same type of container (although they can be), but they do have to hold the same type of items. This requirement is expressed through a combination of type constraints and where clauses:

```
func allItemsMatch<
C1: Container, C2: Container
where C1.ItemType == C2.ItemType, C1.ItemType: Equatable>
(someContainer: C1, anotherContainer: C2) -> Bool {

// check that both containers contain the same number of items
if someContainer.count != anotherContainer.count {
return false
}

// check each pair of items to see if they are equivalent
for i in 0..someContainer.count {
if someContainer[i] != anotherContainer[i] {
return false
}
}

// all items match, so return true
return true

}
```

This function takes two arguments called `someContainer` and `anotherContainer`. The `someContainer` argument is of type `C1`, and the `anotherContainer` argument is of type `C2`. Both `C1` and `C2` are placeholder type parameters for two container types to be determined when the function is called.

The function’s type parameter list places the following requirements on the two type parameters:

- `C1` must conform to the `Container` protocol (written as `C1: Container`).
- `C2` must also conform to the `Container` protocol (written as `C2: Container`).
- The `ItemType` for `C1` must be the same as the `ItemType` for `C2` (written as `C1.ItemType == C2.ItemType`).
- The `ItemType` for `C1` must conform to the `Equatable` protocol (written as `C1.ItemType: Equatable`).

The third and fourth requirements are defined as part of a `where` clause, and are written after the where keyword as part of the function’s type parameter list.

These requirements mean:

- `someContainer` is a container of type `C1`.
- `anotherContainer` is a container of type `C2`.
- `someContainer` and `anotherContainer` contain the same type of items.
- The items in `someContainer` can be checked with the not equal operator (`!=`) to see if they are different from each other.

The third and fourth requirements combine to mean that the items in `anotherContainer` can also be checked with the `!=` operator, because they are exactly the same type as the items in `someContainer`.

These requirements enable the `allItemsMatch` function to compare the two containers, even if they are of a different container type.

The `allItemsMatch` function starts by checking that both containers contain the same number of items. If they contain a different number of items, there is no way that they can match, and the function returns `false`.

After making this check, the function iterates over all of the items in `someContainer` with a `for-in` loop and the half-closed range operator (`..`). For each item, the function checks whether the item from `someContainer` is not equal to the corresponding item in `anotherContainer`. If the two items are not equal, then the two containers do not match, and the function returns `false`.

If the loop finishes without finding a mismatch, the two containers match, and the function returns `true`.

Here’s how the `allItemsMatch` function looks in action:

```
var stackOfStrings = Stack()
stackOfStrings.push("uno")
stackOfStrings.push("dos")
stackOfStrings.push("tres")

var arrayOfStrings = ["uno", "dos", "tres"]

if allItemsMatch(stackOfStrings, arrayOfStrings) {
println("All items match.")
} else {
println("Not all items match.")
}
// prints "All items match."
```

The example above creates a `Stack` instance to store `String` values, and pushes three strings onto the stack. The example also creates an `Array` instance initialized with an array literal containing the same three strings as the stack. Even though the stack and the array are of a different type, they both conform to the `Container` protocol, and both contain the same type of values. You can therefore call the `allItemsMatch` function with these two containers as its arguments. In the example above, the `allItemsMatch` function correctly reports that all of the items in the two containers match
.
chapter25
# 25 고급 연산자 (Advanced Operators)
> Translator : 심상진 (dyanos@gmail.com)


기본 연산자 항목에서 설명했던 연산자들에 더하여, Swift는 훨씬 다양한 방법으로 값을 다루는 몇개의 고급 연산자들을 제공합니다. 이들은 당신이 C와 Objective-C에서 부터 친근하게 여겼던 비트를 다루는 연산자들 모두를 포함합니다.

C에서의 산술 연산자들과는 다르게, Swift에서의 산술 연산자들은 기본적으로 넘침(Overflow)이 일어나지 않습니다. 넘치는 동작(Overflow behavior)은 오류로써 잡히고 보고됩니다. 넘치는 동작을 허용하기 위해서, 넘침을 기본으로 하는 산술 연산들 중에 Swift의 두번째 집합을 사용해야 합니다. 예를 들어, 넘침 덧셈(overflow addition, &+)이 그러한 집합에 속합니다. 모든 넘침 연산자들은 엠퍼샌드(ampersand, &)를 가지고 시작합니다.

당신이 당신 소유의 구조체들과 클래스, 그리고 열거자들을 선언할때, 이들 커스텀 타입들에 대해서 표준 Swift 연산자들의 독자적인 구현들(own implementations)을 제공하는데 유용할 수 있습니다. Swift는 이들 연산자들의 맞춤형(tailored) 구현들을 제공하고 그들의 행동이 당신이 만든 각각의 타입에 대해서 무엇을 해야할지를 정확하게 결정하기 쉽게 만듭니다. (역자 주, operator overload)

당신은 연산자들을 재정의하는데 아무런 제한이 없습니다. Swift는 당신에게 당신 자신의 맞춤형 중간(infix), 전위(prefix), 후위(postfix) 그리고 할당 연산자들을 정의하는데 자유를 줍니다. 그리고 그것들의 우선순위와 결합순위 역시 자유롭게 정의가 가능합니다. 이들 연산자들은 마치 이미 선언된 연산자들 처럼 당신의 코드 안에 사용되고 적용될 수 있고, 당신은 당신이 정의한 맞춤형 연산자들을 지원하도록 이미 존재하는 타입들조차 확장할 수 있습니다.

**비트 연산자들**

비트 연산자들은 당신에게 하나의 데이터 구조체 안에 있는 개개의 가공되지 않은 데이터 비트들(raw data bits)을 다루는 것을 허용합니다. 그들은 종종 그래픽 프로그래밍과 디바이스 드라이버 프로그래밍(device driver creation)과 같은 저수준 프로그래밍에 사용됩니다. 또한 비트 연산자들은 당신이 외부의 입력들(external source)로부터 오는 가공되지 않은 데이터(raw data)를 가지고 작업할때 유용합니다. 예를 들어, 커스텀 프로토콜을 이용한 통신에서 데이터의 부호화(encoding)와 복호화(decoding)과 같은 것들이 그것입니다.

Swift는 C에서 발견되는 모든 비트 연산자들을 지원합니다. 이는 아래에서 좀더 자세히 설명드리겠습니다.

**비트 NOT 연산자**

비트 NOT 연산자(~)는 다음과 같이 숫자의 모든 비트들을 뒤집습니다.(invert)



비트 NOT 연산자는 전위연산자입니다. 그리고 공백없이, 연산하는 값 바로 앞에 나타납니다.

1: let initialBits: UInt8 = 0b00001111
2: let invertedBits = ~initialBits // equals 11110000

UInt8 정수들은 8개의 비트를 가지며, 0에서부터 255까지의 임의의 값을 저장할 수 있습니다. 이 예는 UInt8 정수 변수를, 최초의 4개 비트는 0으로, 나머지 4개비트는 1로 설정한, 이진 값 00001111을 가지도록 초기화합니다. 이것은 십진수 15와 동일한 것입니다.

다음 줄에서, 비트 NOT 연산자는 invertedBits라 불리우는 새로운 상수를 생성하는데 사용합니다. 이것은 initialBits와 동일하지만 모든 비트들이 뒤집어져 있습니다. 다시말해, 이때 initialBit의 비트들중에 0은 1이되고, 1은 0이 됩니다. "그러므로" invertedBits의 값은 11110000이 됩니다. 이것은 부호없는 십진수 240과 동일합니다.

**비트 AND 연산자**

비트 AND 연산자(&)는 두 숫자의 비트들을 결합합니다. 비트들이 다음과 같이 양쪽 입력 숫자들에서 1과 같아야만 비트들이 1로 설정되는 새로운 숫자을 돌려받습니다.(""""좀더 명확하게 이해되도록 수정해야할 필요가 있음"""")



아래의 예에서, firstSixBits변수와 lastSixBits양쪽의 값들은 4개의 중간 비트가 1로 되어있습니다. 비트 AND 연산자는 그들을 부호없는 십진수 60과 동일한 숫자인 00111100로 만들도록 조합합니다.

1: let firstSixBits: UInt8 = 0b11111100
2: let lastSixBits: UInt8 = 0b00111111
3: let middleFourBits = firstSixBits & lastSixBits // equals 00111100

**비트 OR 연산자**

비트 OR 연산자(|)는 두 수의 비트들을 비교합니다. 연산자는 만일 다음처럼 입력 수들 중에 어떤 하나가 비트 1이면, 비트가 1로 설정된 새로운 수를 돌려줍니다.



아래의 예제에서, someBits와 moreBits의 값은 1로 설정된 다른 비트들을 가집니다. 비트 OR 연산자는 그들을 부호없는 십진수 256와 동일한 숫자인 11111110으로 만들어지도록 조합합니다.

1:let someBits: UInt8 = 0b10110010
2:let moreBits: UInt8 = 0b01011110
3:let combinedbits = someBits | moreBits // equals 11111110”

**비트 XOR 연산자**

비트 XOR 연산자 또는 배타적(exclusive) OR 연산자 (^)는 두 수의 비트들을 비교합니다. 연산자는 다음과 같이 입력 비트들이 다르면 1로 같으면 0으로 설정되어진 새로운 수를 돌려받습니다.



아래 예에서, firstBits와 otherBits 각각의 값들은 하나의 위치에서 1로 설정된 하지만 다른 변수에서는 그렇지 않은 비트를 가집니다. 비트 XOR 연산자는 그것들의 출력 값에서 이들 비트들의 양쪽을 1로 설정합니다. firstBits와 otherBits에서 모든 다른 비트들은 같으며, 이것은 다음과 같이 출력 값에서 0으로 나타납니다.

1:let firstBits: UInt8 = 0b00010100
2:let otherBits: UInt8 = 0b00000101
3:let outputBits = firstBits ^ otherBits // equals 00010001

**비트 왼쪽 및 오른쪽 이동(shift) 연산자들**

비트 왼쪽 이동 연산자(<<)와 비트 오른쪽 이동 연산자(>>)는 수에서 아래 정의된 규칙에 따라서, 특정 수의 위치(a certain number of places)로 모든 비트들을 왼쪽 또는 오른쪽으로 이동시킵니다.

비트 왼쪽 그리고 오른쪽 이동은 2의 인수로 정수에 곱한 것과 나눈 것의 효과를 가집니다. 왼쪽으로 한 자리만큼 정수의 비트들을 이동하는 것은 값을 두배로 하는 것과 같은 효과를 나타냅니다. 마찬가지로 오른쪽으로 이동하는 것은 2로 나누는 것과 동일한 효과를 가집니다.

**부호없는 정수들에 대한 이동 방법**

부호없는 정수의 비트 이동은 다음처럼 합니다.

1. 존재하는 비트들은 요청된 수의 위치로(the requested number of places) 왼쪽 또는 오른쪽으로 이동되어 집니다.
2. 정수 공간의 크기를 넘어 이동된 비트들은 버려집니다.
3. 원래의 비트들이 이동되고 남은 자리에 0이 삽입됩니다.

이 접근은 논리적 이동(또는 옮김)으로써 알려져 있습니다.

아래의 그림은 11111111<<1의 결과를 보여줍니다.(여기서는 왼쪽으로 1만큼 이동하는 것을 말합니다.) 그리고 11111111>>1(이것은 오른쪽으로 1만큼 이동하는 것을 말합니다.) 여기서 파란색 비트들은 이동된 비트들을 말하며, 회색 비트들은 버려진 것을 말합니다. 그리고 오랜지색의 0은 삽입된 것을 말합니다.

<>

여기서는 Swift 코드 안에서 어떻게 비트 이동을 하는지를 다음의 실제 코드로 보여줍니다.

1:let shiftBits: UInt8 = 4 // 00000100 in binary
2:shiftBits << 1 // 00001000
3:shiftBits << 2 // 00010000
4:shiftBits << 5 // 10000000
5:shiftBits << 6 // 00000000
6:shiftBits >> 2 // 00000001

당신은 다음과 같이 다른 데이터 타입들안에 있는 값들을 부호화하기 위해서 그리고 복호화하기 위해서 비트 이동을 사용할 수 있습니다.

1:let pink: UInt32 = 0xCC6699
2:let redComponent = (pink & 0xFF0000) >> 16 // redComponent is 0xCC, or 204
3:let greenComponent = (pink & 0x00FF00) >> 8 // greenComponent is 0x66, or 102
4:let blueComponent = pink & 0x0000FF // blueComponent is 0x99, or 153

이 예제는 핑크색에 대한 Cascading Style Sheets 색 값을 저장하기 위해 pink로 불리우는 UInt32 타입의 상수를 사용합니다. CSS 컬러 값 #CC6699는 Swift의 16진수 표현으로 0xCC6699가 됩니다. 이 색깔은 비트 AND 연산자(&)와 비트 오른쪽 이동 연산자(>>)를 사용하여 빨간색 (CC), 녹색(66), 파란색 (99) 요소들로 나누어서 나타낼 수 있습니다.

빨간색 요소는 숫자 0xCC6699와 0xFF0000사이에 비트 AND 연산을 수행하므로써 얻어집니다. 0xFF0000에서, 6699를 무시되게 하기 위해서 그리고 결과에서 0xCC0000를 남기기 위해서, 0은 효과적으로 0xCC6699의 두번째와 세번째 바이트를 가려줍니다.(mask)

그때 이 수는 오른쪽으로 16칸 이동(>>16)합니다. 16진수에서의 두자리는 2진수의 8비트와 같습니다, 그래서 오른쪽으로 16칸짜리 이동은 0xCC0000를 0x0000CC로 변환할 것 입니다. 이것은 10진수 204인 0xCC와 같습니다.

비슷하게, 녹색 요소는 출력으로써 0x006600을 주는 0xCC6699와 0x00FF00사이에 비트 AND 연산을 수행하므로써 얻어집니다. 이 출력은 오른쪽으로 8칸 이동되어 지고, 10진수로 102에 해당하는 0x66의 값을 줍니다.

마지막으로, 파란색 요소는 출력으로 0x000099를 주는 0xCC6699와 0x0000FF사이의 비트 AND 연산을 수행하므로써 얻어집니다. 여기서는 오른쪽으로의 이동이 필요없습니다. 이미 0x000099는 10진수로 153에 해당하는 0x99와 동일하기 때문입니다.

부호있는 정수의 이동 모습(behavior)

이동은 부호있는 정수를 할때 부호없는 정수때보다 더 복잡합니다. 이는 부호있는 정수를 이진수로 표현하는 방식때문입니다. (아래 예들은 간단함을 위해 8비트 부호있는 정수들을 기본으로 하여 진행됩니다. 그러나 어떠한 크기의 부호있는 정수에도 앞으로 나올 원칙을 적용할 수 있습니다.)

부호있는 정수들은 (부호 비트로 알려진) 그들의 첫번째 비트를 그 정수가 양의 정수인지 음의 정수인지를 타나내는데 사용합니다. 부호비트가 0이면 양수를, 부호비트가 1이면 음수를 의미합니다.

값 비트로 알려진 남아 있는 비트들은 실제 값을 저장합니다. 양의 정수는 정확하게 부호없는 정수에 대해서 하는 것과 같이 정확하게 같은 방법인 0부터 위쪽으로 계산하는 방법(counting upwards from 0)으로 저장합니다. 여기서는 어떻게 Int8안에서 숫자 4를 표현하는지 보여줍니다.



부호 비트가 0(즉, 양수)이고, 7개의 값 비트들은 단지 이진 표현으로 쓰여진 숫자 4를 의미합니다.

그렇지만 음수는 다르게 저장됩니다. 2의 n승에서 그들의 절대값을 빼므로써 저장됩니다. 이때 n은 값 비트의 수를 의미합니다. 8비트 수는 7개의 값 비트를 가집니다. 그래서 이것은 2의 7승 또는 128을 의미합니다.

여기서는 어떻게 Int8에서 -4를 표현하는지 보여줍니다.



이번에는, 부호 비트가 1(즉, 음수)이고, 7개의 비트는 이진값으로 (128 - 4인) 124를 가집니다.



음수에 대한 부호화 방법은 2의 보수 표현현으로써 알려져 있습니다. 이것은 이상한 방법처럼 보이지만, 이러한 방법은 몇가지 이득을 가집니다.

첫번째 당신은 다음과 같이 (부호 비트를 포함하는) 모든 8개의 비트들에 대해서 표준 이진 덧셈을 하고, 8비트에 적합하지 않은 어떤것도 버릴필요없이 간단하게 -1을 -4에 더할 수 있습니다.



두번째, 2의 보수 표현은 당신에게 양수에서와 같이 음수의 비트들을 왼쪽 또는 오른쪽으로 이동시키고, 여전히 왼쪽 이동에 대해서 그들을 배가하거나 오른쪽 이동으로 반분되어지도록 합니다. 이것을 이루기 위해서, 부호있는 정수를 오른쪽으로 이동시킬때 다음의 추가적인 규칙들이 적용됩니다.

당신이 오른쪽으로 부호있는 정수를 이동시킬때, 부호없는 정수에서와 같은 규칙들을 적용하면 됩니다만 부호와 함께 왼쪽에 있는 임의의 빈 비트들을 0과는 다른 것으로 채워야 합니다.



이러한 행동은 부호있는 정수들이 오른쪽으로 이동후에도 같은 부호를 가지는 것을 확실히 하기 위해서 입니다. 그리고 이러한 행동은 산술 이동이라고 알려져 있습니다.

양수와 음수가 저장되는 특별한 방식 때문에, 그들 중에 하나를 오른쪽으로 이동하는 것은 그들을 0으로 이동합니다. 이러한 이동동안 부호 비트를 같게 유지하는 것은 음수를 그들의 값을 0으로 옮기는 동안에도 음수로 남아있게 한다는 것을 의미합니다.

넘침 연산자들

만일 당신이 값을 유지할 수 없는 정수 상수 또는 변수에 하나의 숫자를 넣기를 시도한다면, 기본적으로 Swift는 유효하지 않은 값이 생성되기를 허락하기 보다는 오류를 보고 합니다. 이 행동은 당신이 너무 큰거나 너무 작은 숫자들을 가지고 작업할때 추가적인 안전함(extra safety)을 당신에게 제공합니다.

예를 들어, Int16 정수 타입은 -32768부터 32767까지의 임의의 부호있는 정수를 가지고 있을 수 있습니다. UInt16 상수 또는 변수에 이 범위를 벗어나는 숫를 설정하려고 노력하는 것은 오류를 일으킵니다.

1:“var potentialOverflow = Int16.max
2:// potentialOverflow equals 32767, which is the largest value an Int16 can hold
3:potentialOverflow += 1
4:// this causes an error”

값이 너무 크거나 너무 작을때 다루는 오류를 제공하는 것은 경계값 조건에 대해서 코딩할때 훨씬 더 많은 유연성을 당신에게 줍니다.

그렇지만, 당신이 가능한 비트들의 수를 일부를 줄이기 위해서 넘침 조건을 특별히 원할때, 당신은 오류를 일으키는 것보다 다음의 행동으로 이를 수행할 수 있습니다. Swift는 정수 계산에 대해서 넘침 동작을 수행할 수 있는 다섯가지의 넘침 연산자들을 제공합니다. 이들 연산자들 모두는 앰퍼센트(&)를 가지고 시작합니다.

Overflow addition (&+)
Overflow subtraction (&-)
Overflow multiplication (&*)
Overflow division (&/)
Overflow remainder (&%)”

값 넘침

여기서는 넘침 덧셈 연산자(&+)를 사용하여, 부호없는 값이 넘침이 허용될때 무슨일이 일어나는지에 대한 예를 보여줍니다.

1:“var willOverflow = UInt8.max
2:// willOverflow equals 255, which is the largest value a UInt8 can hold
3:willOverflow = willOverflow &+ 1
4:// willOverflow is now equal to 0

변수 willOverflow는 UInt8이 가질 수 있는 최대 값(즉, 255 또는 이진수로 11111111)으로 초기화되어 있습니다. 그때 넘침 덧셈 연산자(&+)를 사용하여 1을 증가시킵니다. 이것은 그것들의 이진 표현을 UInt8의 크기를 넘도록 밀어내는데, 이것은 아래 그림에서 보여지듯이 범위를 넘어서서 넘침을 발생시킵니다. 넘침 덧셈 이후로 UInt8의 범위안에 남아있는 값은 00000000 또는 0입니다.



값 언더플로

숫자들은 또한 그들 타입의 최대 범위안에서 맞기에는 너무 작게 될 수 도 있습니다. 여기에 예제가 있습니다.

UInt8가 유지할 수 있는 가장 작은 수는 0(즉, 8비트 이진 형태에서는 00000000이 됩니다.)입니다. 만일 당신이 넘침 뺄셈 연산자를 사용하여 00000000으로부터 1을 뺀다면, 그 수는 이진수 11111111 또는 십진수 255으로 꺼꾸로 넘칠 것 입니다.



다음은 Swift코드 에서 어떻게 보이는 지를 나타냅니다.

1:var willUnderflow = UInt8.min
2:// willUnderflow는 UInt8이 유지할 수 있는 가장 작은 값인 0이 됩니다.
3:willUnderflow = willUnderflow &- 1
4:// 현재 willUnderflow는 255와 동일합니다.

유사한 언터플로는 부호있는 정수에서 발생됩니다. 부호있는 정수들에 대한 모든 뺄셈은 직접적인 이진 뺄셈으로써 수행됩니다. 이는 밸셈을 하고있는 숫자의 부분으로써 포함되어 있는 부호비트도 함께이며, 비트 왼쪽 그리고 오른쪽 연산자들에서 설명한 것과 같습니다. Int8인 가질 수 있는 가장 작은 값은 -128입니다. -128은 이진수로 10000000로 나타납니다. 넘침 연산자를 가지고 이 이진 수로부터 1을 빼는 것은 01111111의 이진 수를 줍니다. 이것은 부호비트를 뒤집고 양수 127을 줍니다. 이는 Int8이 가질 수 있는 가장 큰 양의 수입니다.



다음은 Swift코드에서의 표현입니다.

1:var signedUnderflow = Int8.min
2:// signedUnderflow는 -128과 같습니다. 이는 Int8이 가질 수 있는 가장 작은 값입니다.
3:signedUnderflow = signedUnderflow &- 1
4:// signedUnderflow는 지금 127과 같습니다.

위에 설명된 넘침과 언터플로의 행동의 마지막 결과는 부호있는 그리고 부호없는 정수 양쪽에 대해서, 항상 넘침이 가장 크게 유효한 정수 값으로 부터 가장 작은 것으로 반복되며, 언더플로는 가장 작은 값으로부터 가장 큰 값으로 반복됩니다.

0으로 나누기

0으로 숫자를 나는 것(i/0) 또는 0으로 나머지를 계산하기(i%0)를 시도하는 것은 오류를 발생시킵니다.

1:let x = 1
2:let y = x / 0

chapter26
# 26 언어 레퍼런스에 대하여 (About the Language Reference)
> Translator : 이름 (메일주소)
chapter27
# 27 언어 구조 (Lexcial Structure)
> Translator : 이름 (메일주소)
chapter28
# 28 타입 (Types)
> Translator : 이름 (메일주소)
chapter29
# 29 표현 (Expressions)
> Translator : 이름 (메일주소)
chapter3
# 03 기초 다지기 (The Basics)
> Translator : 이름 (메일주소)


Write here...
chapter30
# 30 스테이트먼트 (Statements)
> Translator : 이름 (메일주소)
chapter31
# 31 선언 (Declarations)
> Translator : 이름 (메일주소)
chapter32
# 32 속성 (Attributes)
> Translator : 이름 (메일주소)
chapter33
# 33 패턴 (Patterns)
> Translator : 이름 (메일주소)
chapter34
# 34 제너릭 매개변수와 인자 (Generic Parameters and Arguments)
> Translator : 이름 (메일주소)
chapter35
# 35 문법 요약(Summary of the Grammar)
> Translator : 이름 (메일주소)
chapter4
# 04 기본 연산자

Write here...
(Basic Operators)
> Translator : 해탈 (kimqqyun@gmail.com)

연산자는 값을 확인 변경 합치기 위해 사용하는 특수 기호나 문구입니다. 예를 들어 더하기 연산자(`+`)는 두 숫자를 더합니다. (`let i = 1 + 2` 과 같이)
더 복잡한 예는 논리 AND 연산자 (`&&`) 포함입니다. (`enteredDoorCode && passedRetinaScan`)그리고 증가 연산자인 `++i`는 `i`의 값 `1`을 증가시키는 축약 연산자입니다.

Swift 는 대부분의 표준 C 연산자를 지원하며 일반적인 코딩 오류를 제거하는 몇가지 기능을 항샹 시켰습니다. 할당연산자 (`=`)나 항등 연산자(`==`)를 사용할때 실수를 방지하기 위해 값을 반환하지 않습니다.
산술연산자(`+` ,` -` ,`*`,`/` ,`%` 등)가 오버플로우를 감지하고 그들을 저장하는 유형의 허용된 값의 범위보다 크거나 작아 숫자로 작업할때 예기치 않은 결과를 방지 할 수 있습니다.
당신은 오버 플로우 연산자에 설명된대로 Swift의 오버플로우 연산자를 사용하여 오버플로 값을 선택할수 있습니다. 이것은 Overflow Operaters 에 설명되어 있습니다. // 링크

C 와 달리, Swift는 부동 소수점 숫자에 나머지 (`%`) 계산을 수행 할 수 있습니다. Swift는 또한 2개의 범위 연산자를 제공합니다. (`A..B`) 그리고 (`A...B`) 이며 값의 범위를 표현하기 위한 연산자이고 이것은 C 에서 찾을 수 없습니다.

이 장에서는 Swift의 일반적인 연산자를 설명합니다. 고급 연산자는 고급 연산자(Advanced Operator) 장에 있습니다, 그리고 사용자 정의 연산자를 정의하고 사용자 정의 형식에 대한 표준 연산자를 구현하는 방법에 대해 설명합니다.

## 용어 (Teminology)
연산자는 단항, 이진, 그리고 삼항이 있습니다.

- 단항 연산자는 단일 대상에서 작동합니다. (예 `-a`) 단항 전위 연산자를 바로 앞에 나타내고, (예 `!b`) 단항 후위 연산자는 타겟이후에 즉시 나타납니다. (예 `i++`)
- 이항 연산자는 두개의 대상에 작동하며 그들의 두 대상 사이에 나타납니다. 왜냐하면 중위연산자입니다. (예 `2 + 3`)
- 삼항 연산자는 세 가지 대상에 작동합니다. C 처럼 , Swift는 하나의 삼항연산자, 삼항 조건 연산자가 (`a ? b : c`)

연산자에 영향을 주는 값은 피연산자 입니다. 식 `1 + 2` 는 이항 연산자와 두 피연산자의 값은 `1`과 `2`입니다.

## 할당 연산자
할당 연산자는 `(a = b)` 초기화 하거나 `b` 의 값을 `a` 에 할당하는것이다.
```
let b = 100
var a = 5
a = b
// a 는 이제 10 과 같다.
```

만약 오른쪽이 같은 여러 값을 가진 튜플의 경우, 그 요소는 한번에 여러개의 상수 또는 변수로 분해 될수 있다.
```
let (x, y) = (1, 2)
// x 는 1 과 같다 그리고 y 는 2 와 같다.
```

C 와 Objective-C의 대입 연산자와는 달리, Swift의 대입 연산자 자체가 값을 반환하지 않습니다. 다음 구문은 유효하지 않습니다.
```
if x = y {
// x = y가 값을 반환하지 않기 때문에 이것은 유효하지 않다,
}
```

이 기능은 실수로 (`==`) 연산자를 사용하여 막는것은 (`=`)를 대신 사용하는것을 방지하기 떄문입니다. `if x = y` 가 유효하지 않게 함으로써 Swift 코드에서 이러한 종류의 오류를 방지하는데 도움이 됩니다.

## 산술 연산자
Swift 는 4가지의 산술연산자가 모든 숫자 타입을 지원합니다.

- 덧셈 (`+`)
- 뺼셈 (`-`)
- 곱셈 (`*`)
- 나눗셈 (`/`)

```
1 + 2 // 3 과 같다
5 - 3 // 2 와 같다
2 * 3 // 6 과 같다
10.0 / 2.5 // 4.0 과 같다
```
C 및 Objective-C의 산술 연산자와는 달리 Swift 산술 연산자는 값이 기본적으로 오버플로우하는것을 허용하지 않는다. Swift 오버플로우 연산자를 사용하여 값 오버플로 동작을 선택할 수있습니다. Overflow Operators를 참조하십시오. // 링크

또한 덧셈 연산자는 String 문자열을 지원한다.
```
"hello, " + "world" // "hello, world" 와 같다
```

두 개의 `Character` 값이거나 하나는 `Character` 값 그리고 하나는 `String` 값일때 두 개를 함께 더해서 새로운 `String` 값을 만들 수 있습니다.

```
‘let dog: Character = "🐶🐶
let cow: Character = "🐮"
let dogCow = dog + cow
// dogCow is equal to "🐶🐮"
```
이것에 대해선 Strings and Characters 또한 참조 바란다. // 링크

## 나머지 연산자
나머지 연산자는 (`a % b`) `b` 의 많은 배수가 `a`에 맞게 곱해지며 그리고 남아 있는 값을 반환합니다. (이는 나머지 라고 불립니다.)

> NOTE

> 나머지 연산자는 (%) 또한 모듈로 연산으로 다른 언어에 알려져있다. 그러나 Swift에서의 동작은 음수를 의미한다. 엄격히 말하면, 모듈로 연산보다는 나머지 연산이다.

여기에 나머지 연산의 동작이 어떻게 되는지 있다. ` 9 % 4 ` 을 계산해보면, 당신은 첫번째로 `4`들을 `9`에 맞게 맞출것이다.
![remainderinteger_2x.png](images/remainderinteger_2x.png)


당신은 `4`들을 9에 맞추었고 그리고 나머지는 `1`이다. (오렌지 색깔을 보라)

Swift에서는 이렇게 쓰여진다

9 % 4 // 1과 같다

a % b 의 답을 측정해보면, % 계산 연산자는 나머지 출력과 = 연산자를 반한단다.

`a = (b x 배수) + 나머지`

`배수`가 `a` 내부의 맞는 가장 큰 수일 경우다.

9 와 4를 대입 할경우

` 9 = (4 × 2) + 1 `

a 의 값이 음수 일때도 같은 메소드가 지원되며 나머지 값이 음수가 나온다.

`-9 % 4 // -1과 같다`

-9 와 4 를 넣으면 다음 과 같은 식이 나온다.

`-9 = (4 × -2) + -1`

나머지 값이 `-1`이 주어진다.

`b`의 부호는 `b`의 음의 값이 무시됩니다. 이것은 `a % b` 와 `a % -b`는 항상 같은 대답을 주고 있다는 것을 의미한다.

## 부동 소수점 나머지 연산
C 와 Objective-C의 나머지 연산과는 달리, Swift의 나머지 연산은 부동 소수점 연산 또한 지원합니다.

`8 % 2.5 // 2.5와 같음`
예를 들어 8을 2.5로 나누었을때 3과 같다 나머지는 0.5와 같다. 그리고 나머지 연산이 반환하는 값은 Double 타입의 0.5이다.
![remainderfloat_2x.png](images/remainderfloat_2x.png)


## 증가연산자와 감소 연산자
C와 같이, Swift는 증가 연산자(`++`)와 감소 연산자(`--`)를 제공한다. 이것은 숫자 변수 `1`를 증가시키거나 감소시키는 축약형이다. 정수형과 부동소수점형을 연산자와 같이 사용 가능하다.
```
var i = 0
++i // i 는 이제 1과 같다
```

만약 `++i` 호출마다 `i`의 값은 `1` 씩 증가된다. 기본적으로 `++i` 는 `i = i + 1` 의 약어이다. 마찬가지로 `--i`를 `i = i - 1` 의 약어로 사용할 수 있습니다.

`++` 와 `--` 기호는 전위연산자 또는 후위연산자로 사용이 가능합니다. `++i` 와 `++i`는 둘다` i`의 값을` 1` 증가시키는 방법입니다. 비슷하게, `--i` 와 `i--`는 `i`의 값을 `1` 감소시키는 방법입니다.

이러한 수정연산자는 i 와 그리고 반환값 까지 변화시킵니다. 만약 i 에 저장된 값을 증가 또는 감소 할 경우, 반환값을 무시 할 수있습니다. 그러나 반환된 값을 사용할 경우, 당신은 다음과 같은 규칙에 따라 접두사 또는 연산자의 후위버전을 사용하는지 여부에 따라 달라집니다.

- 만약 변수 앞에 쓰여질 경우, 값이 증가한 후에 반환된다.
- 반약 변수 뒤에 쓰여질 경우, 값이 반환된 뒤에 증가된다.

예제 코드 (For example:)
```
var a = 0
let b = ++a
// a 그리고 b는 지금 a 둘다 1과 같다.
let c = a++
// a 는 지금 2, 그러나 c는 이전의 값인 1이 이미 설정되어있다.
```

위의 예제코드에서 `let b = ++a` 는 `a`를 반환하기 전에 `a`를 증가시킨다. 이 방법은 a 와 b 하나의 새로운 값이 동등한 이유이다.

그러나, `let c = a++` 는 `a`를 반환한 후에 `a`를 증가시킨다. 이 뜻은 `c`가 없은 값은 예전의 값인 `1`이며 `a`에게는 업데이트 된 `2`와 같다.

당신은 i++의 특정동작을 필요로 하지 않는한, 이것은 당신이 ++i 나 --i를 사용하는것이 좋습니다. 왜냐하면 그것은 모든 경우에 `i`를 수정하고 결과를 반환하는 예상된 동작을 가지기 때문입니다.

##단항 마이너스 연산자
숫자 값의 부호는 접두어 -를 사용하여 전환할수 있다. 이것은 단항 마이너스 연산자로 알려진것이다.

```
let three = 3
let minusThree = -three // minusThree equal -3
let plusThree = -minusThree // plus equal 3, or "minus minus three"
```
단항 마이너스 연산자는 공백없이 작동하는 값 바로 앞에 추가 됩니다.

##단항 플러스 연산자
단항 플러스 연산자(+)는 간단하게 변경하지 않고, 값을 반환합니다.

```
let minusSix = -6
let alsoMinusSix = +minusSix // alsoMinusSix equals -6
```

플러스 연산자가 있음에도 불구하고 실제로 아무것도 하지 않지만, 당신은 또한 단항 마이너스 연산자를 사용하는 경우 양수에 대한 코드대칭에 사용할 수 있습니다.

## 복합 할당 연산자
C와 같이 Swift는 다른 작업에 할당(=)을 결합하는 복합 할당 연산자를 제공합니다. 한 예를 들어 덧셈 할당 연산자입니다 (+=):
```
var a = 1
a += 2
// a 는 3과 같다
```

표현식 `a += 2` 는 `a = a + 2` 의 축약형이다. 효과적으로 한 연산자가 가산 및 할당이 동시에 작업과 결합이 된다.

>NOTE
>
> 복합 할당 연산자는 값을 반환하지 않는다. 당신은 `let b = a += 2` 이러한 코드를 작성할수 없다. 예를 들어 이러한 코드는 위의 증가 및 감소 연산자와는 다릅니다.

복합 할당 연산자의 전체 목록은 Expressions 에서 찾을 수 있습니다. // 링크

## 비교 연산자
Swift는 C의 정식 비교연산자를 지원합니다.

- 같음 연산자 (`a == b`)
- 같지 않음 연산자 (`a != b`)
- 보다 큰 (`a > b`)
- 보다 작은(`a < b`)
- 보다 크거나 같은 (`a >= b`)
- 보다 작거나 같은 (`a <= b`)

>NOTE
>
>Swift는 또한 두 개체 참조가 동일한 인스턴스 객체를 참조하고 있는지 여부를 테스트 하는 연산자를 지원합니다. (`===` 와 `!==`) 자세한 내용은 Classes and Structures를 참조하십시오 // 링크

비교 연산자의 각 문장이 참인지 여부를 나타내는 `Bool` 값을 반환합니다 :

```
1 == 1 // 참
2 != 1 // 참
2 > 1 // 참
1 < 2 // 참
1 >= 1 // 참
2 <= 1 // 거짓

```

비교 연산자는 종종 if문 같은 조건문에 사용된다 :

```
let name == "world"
if name == "world" {
println("hello, world")
} else {
println("I'm sorry \(name), but I don't recognize you")
}
```
`if`에 대한 더 많은 정보는 Control Flow를 참조하기 바란다. // 링크

## 삼항 조건 연산자
삼항 조건 연산자는 특별한 연산자와 세개의 파트로 이루어져있습니다.
양식은 이러합니다. (`question ? answer1 : answer2`)
이 `question`이 참인지 거짓인지에 따라 두 식중 하나를 평가하기 위한 축약어입니다. 만약 `question` 이 참이면 `answer1`을 계산하고 값을 반환합니다; 그렇지 않으면 `answer2`를 계산하고 값을 반환합니다.

삼항 조건 연산자는 아래의 코드에 대한 속기입니다.

```
if question {
answer1
} else {
answer2
}
```
이것은 테이블 행의 픽셀 높이를 계산하는 예제입니다. 행의 헤더가 있다면 컨텐츠의 높이가 50 픽셀이상이고 행의 헤더가 없다면 20픽셀 보다 큰것입니다.:

```
let contentHeight = 40
let hasHeader = true
let rowHeight = contentHeight + (hasHeader ? 50 : 20)
// rowHeight 는 90과 같다
```

위의 예제코드는 아래 코드의 속기입니다.
```
let contentHeight = 40
let hasHeader = true
var rowHeight = contentHeight
if hasHeader {
rowHeight = rowHeight + 50
} else {
rowHeight = rowHeight + 20
}

```

첫번째 예제의 삼항 조건 연산자의 사용은 `rowheight`에 단 한줄의 코드에 올바른 값으로 설정될 수 있음을 의미합니다. 이것은 두 번째 예제코드보다 간결하고 그 값이 `if` 문 내에서 수정될 필요가 없기 떄문에 이것은 `rowheight`가 변수가 될 필요성이 없어집니다.

삼항 조건 연산자는 두 식의 어떤 결정을 고려하는것을 위해 효율적인 속기를 제공합니다. 그러나 삼항 조건 연산자는 주의해서 다뤄야 합니다. 남용하면 그 간결함은 읽기 어려운 코드로 이어질 수 있습니다. 하나의 복합 문에 삼항 조건 연산자와 다중 인스턴스를 결합하는것을 피하세요.

## 범위 연산자
Swift는 두 개의 범위연산자를 지원하며 이 축약어는 값의 범위를 표현합니다.

### 폐쇄 범위 연산자
폐쇄 범위 연산자(`a...b`)는 `a`에서 `b` 까지의 범위를 정의합니다. 그리고 `a`와 `b`의 값을 포함합니다.

폐쇄 범위 연산자는 `for-in` 루프와 같이 사용하고자 하는 값 범위에서 반복할때 폐쇄 범위 연산자는 유용합니다.

```
for index in 1...5 {
println("\(index) time 5 is \(index * 5)")
}
// 1번쨰 반복 5 is 5
// 2번쨰 반복 5 is 10
// 3번쨰 반복 5 is 15
// 4번쨰 반복 5 is 20
// 5번쨰 반복 5 is 25
```
`for-in` 루프에 대해서는 Control Flow 항목을 참조하시오 // 링크

### 반 폐쇄 범위 연산자
반 폐쇄 범위 연산자 (`a..b`)는 a 에서 b 로 실행되는 범위를 정의하지만 b가 포함되어 있지 않습니다. 그것은 최종값이 아니며 처음 값을 포함하고 있기 때문에 반폐쇄라고 합니다.

반 폐쇄 범위는 특히 0을 기반으로한 목록 또는 배열로 작업할때 유용합니다. 그것은 리스트의 길이(포함안되는)까지 계산하는데 유용합니다.
```
let names = ["Anna", "Alex", "Brian", "Jack"]
let count = name.count
for i in 0.count {
println("Person \(i + 1) is called \(names[i]")
}
// Person 1 is called Anna
// Person 2 is called Alex
// Person 3 is called Brian
// Person 4 is called Jack
```
배열에는 4개의 항목이 포함되어있습니다. 하지만 반 폐쇄 범위기 때문에 `0..count` 는 단지 3까지만 카운트 합니다. (배열의 마지막 항목의 인덱스)
arrays에 대해 더 참조하고 싶다면 Arrays 항목 를 참조하시오 // 링크

## 논리 연산자
논리 연산자는 `true`와 `false` 불리언 논리 값을 수정하거나 결합합니다. Swift는 C 기반 언어의 세 가지 표준 논리 연산자를 지원합니다.

- NOT (!a)
- AND (a && b)
- OR (a || b)

##논리 NOT 연산자
논리 NOT 연산자(`!a`)는 불리언 값인 `true` 값을 반전시키고 `false` 값은 `true` 가 된다.

논리 NOT 연산자는 전위 연산자입니다. 값 앞에 연산을 공백없이 즉시 표현 할 수 있습니다. 이것은 "`not` a"로 바로 읽을 수 있으며 다음의 예제에서 볼 수 있습니다.

```
let allowedEntry = false
if !allowedEnrty {
println("ACCESS DENIED")
}
// prints "ACCESS DENIED"
```
`if !allowedEntry` 는 "if not allowed entry" 로 읽을 수 있습니다.
즉 `allowedEntry`이 false인 경우 라인 이후의 `not allowed entry` 가 `true`인 경우에 해당할 경우로 실행됩니다.
이 예제에서와 같이 불리언 상수와 변수 이름의 주의 깊은 선택은 이중 부정 또는 혼란한 논리구문을 피하면서 읽기 쉽고 간결한 코드를 유지하는데 도움이 될 수 있습니다.

## 논리 AND 연산자

논리 AND 연산자(`a && b`)의 overall expression은 두 값이 모두 `true`이어야 `true`가 됩니다.

반대로 두 값이 `false` 이면 overall expression 또한 `false` 입니다. 사실 첫번째 값이 `false` 인 경우 두번째 값이 evaluated 되지 않습니다. 그것을 가능할수 없기 떄문에 overall expression이 `true`와 같게 됩니다. 이는 short-circuit evaluation 로 불린다.

이 예제에서는 두 개의 `Bool`값을 고려하여 만약 두 값이 `true` 에만 액세스 할 수 있습니다.

```
let enteredDoorCode = true
let passedRetinaScan = false
if enteredDoorCode && passedRetinaScan {
println("Welcome!")
} else {
println("ACCEss DENIED")
}
// prints "ACCESS DENIED"
```
## 논리 OR 연산자
논리 OR 연산자(`a || b`)는 인접한 파이프 문자로 만든 중위연산자 입니다. overall expression 이 `true`가 될 때 까지 두 개의 값 중 하나만이 참이어야 하는 논리식을 만드는데 사용합니다.

위의 논리 AND 연산자처럼 논리 OR 연산자는 식을 고려할떄 short-circuit evaluation을 사용합니다. 논리 OR식의 좌측에 `true`가 해당하는 경우는 overall expression 식의 결과를 변경 할수 있기 때문에 우측은 계산되지 않는다.

아래의 예제에서 첫 번째 `Bool` 값(`hasDoorKey`)은 `false`이지만 두 번째 값(`knowsOverridePassword`)는 `true`이다. 하나의 값 이`true`이기 떄문에 overall expression은 `true`로 평가하고 액세스가 허용됩니다.

```
let hasDoorKey = false
let knowOverridePassword = true
if hasDoorKey || knowOverridePassword {
println("Welcome!")
} else {
println("ACCESS DENIED")
}
// prints "Welcome!"
```
## 복합 논리 연산자

당신은 여러 논리 연산자를 결합하여 복합 논리 연산자를 만들 수 있습니다.
```
if enteredDoorCode && passedRetinaScan || hasDoorKey || knowOverridePassword {
println("Welcome!")
} else {
println("ACCESS DENIED")
}
// prints "Welcome!"
```
이 예제는 && 및 || 연산자를 여러개 사용하려 긴 복합 표현식을 만들었습니다. 그러나 && 와 || 연산자는 여전히 두 개의 값에 대해 작동하므로 이는 실제로 서로 세개가 연결된 작은 표현입니다.
이것은 이렇게 읽을 수 있습니다:

만약 우리가 문의 코드를 입력하고 망막 검사를 통과한경우; 우리가 유효한 도어 키가 있는 경우이거나 긴급 재정의 암호를 알고있는 경우 다음 액세스 할 수 있습니다.

`enteredDoorCode` 와 `passedRetinaScan` 그리고 `hasDoorKey` 의 값에 기초하여 처음 작은 표현식은 `false`이다. 그러나 긴급 재정의 암호가 `true`로 알려져있다 ,그래서 전체 복합 표현식은 여전히 `true`로 평가됩니다.

## 괄호 명시
괄호가 엄격히 필요하지 않은경우, 읽기 복잡한 표현의 의도록 쉽게 만들수 있는 경우에 괄호가 포함되는것이 유용한 경우가 종종 있다.

위의 door access 예제 코드에서 그것의 의도를 명시적으로 확인하기 위해 복합 표현식의 첫번째 부분을 괄호를 추가하는데에 유용합니다.

```
if (enteredDoorCode && passedRetinaScan) || hasDoorKey || knowOverridePassword {
println("Welcome!")
} else {
println("ACCESS DENIED")
}
// prints "Welcome!"
```
괄호는 처음 두 값을 전체 논리에서 별도의 가능한 상태의 일부로 분명히 간주되게 만듭니다. 복합식의 출력이 변하지는 않지만 전체적인 목적이 독자에게 명확해집니다. 가독성은 항상 간결함을 선호합니다; 괄호의 사용은 당신의 의도를 확실히 파악하는데 도움이 됩니다.

chapter5
# 05 문자열과 문자 (Strings and Characters)
> Translator : 이름 (메일주소)


Write here...
chapter6
# 06 컬렉션 타입 (Collection Types)
> Translator : 이름 (메일주소)


Write here...
chapter7
# 07 제어문 (Control Flow)

조건문(conditionals)을 만들 때에는 `if`와 `switch`를 사용하세요. 그리고 순환문(루프문, loops)을 만들 때에는 `for-in`나 `for`, `while`, `do-while`을 사용하세요. 조건이나 순환문 변수(loop variable)를 감싸주는 괄호 ( )는 옵션입니다. 본문을 감싸는 { }는 필수입니다.

```
let individual Scores = [75, 43, 103, 87, 12]
var teamScore = 0
for score in individualScores {
if score > 50 {
teamScore += 3
} else {
teamScore += 1
}
}
Score
```

'if'문 안에서, 조건을 나타내는 부분은 부울 식(참 거짓, Boolean expression)이어야 합니다. 즉, 다음과 같이 쓰면 에러가 납니다.

```
if score {...}
```

조건부를 이렇게 score라고만 써주면, 에러가 나지, 프로그램이 알아서 score를 0과 비교해주지 않습니다.

조건부에서 쓴 변수가 값을 가지지 않을 수도 있는 경우에는 `if`하고 `let`을 같이 쓸 수 있습니다.

이러한 값들은 **선택적(optional)**이라고 합니다. 선택적인 값은, 값을 가질 수도 있고, 값을 안 가질 수도 있습니다. 값을 안 가지는 경우에는 `nil`값을 가집니다.

어떤 값이 선택적이라고 표시하려면 값의 형(type) 뒤에다가 물음표 `?`를 붙여 줍니다.

```
var optionalString: String? = "Hello"
optionalString == nil
var optionalName: String? = "John Appleseed"
var greeting = "Hello! "

if let name = optionalName {
greeting = "Hello, \(name)"
}
```

> 실험해 보세요 - optionalName을 nil로 바꿔보세요. 어떤 인사말이 나오나요? optionalName의 값이 nil인 경우에 다른 인사말을 보여주는 else절을 추가해 보세요.

옵션 값이 nil인 경우에, 조건부는 거짓(false)이 되고, {} 안에 있는 코드는 실행되지 않습니다. 옵션 값이 nil이 아닌 경우에는, 선택값이 unwrapped되고 let 뒷 부분에서 상수에 할당됩니다. 이렇게 되면 코드 블럭 내에서 unwrapped value가 available한 상태가 됩니다.

`switch` 명령어는 모든 종류의 데이터를 지원하며 아주 다양한 종류의 비교 연산을 지원합니다 - 정수형 데이터에 국한되지 않으며, 등가인지 확인하는 연산에 국한되지 않습니다.

```
let vegetable = "red pepper"

switch vegetable {
case "celery":
let vegetableComment = "Add some raisins and make ants on a log. "
case "cucumber", "watercress":
let vegetableComment = "That would make a good tea sandwich. "
case let x where x. hasSuffi x("pepper"):
let vegetableComment = "Is it a spicy \(x)?"
default:
vegetableComment = "Everything tastes good in soup. "
```

> 실험해 보세요 - 디폴트 경우(default case)를 제거해 보세요. 어떤 에러가 나오나요?

프로그램은 `switch`안에 있는 경우 중, 조건에 해당하는 case안에 있는 코드를 실행한 후, `switch` 문에서 빠져나옵니다. 실행된 case 다음에 나오는 case 안에 있는 코드는 실행되지 않습니다. 따라서 각 case 안에 있는 코드의 마지막 부분에 break 문을 써줄 필요가 없습니다.

딕셔너리(dictionary) 안에 있는 각 항목(item)에 대해서 이터레이트(iterate)할 때는, `for-in`을 사용합니다. 이 때 각 키-값 쌍(key-value pair)에 대해서 이름 쌍을 사용합니다.

```
let interestingNumbers = [
"Prime": [2, 3, 5, 7, 11, 13],
"Fibonacci ": [1, 1, 2, 3, 5, 8],
"Square": [1, 4, 9, 16, 25],
]

var largest = 0
for (kind, numbers) in interestingNumbers {
for number in numbers {
if number > largest {
largest = number
}
```

> 실험해 보세요 - 변수를 하나 더 추가해서, 가장 최근에 가장 큰 수는 무엇이었는지, 그 수는 어떤 종류였는지 추적하세요.

조건이 변하기 전까지는 코드 블럭(block of code)을 반복하고 싶다면 `while`을 사용하세요. 루프가 적어도 한 번은 반드시 실행되도록 하려면, 조건부를 끝부분에 쓰면 됩니다.

```
var n = 2
while n < 100 {
n = n * 2
}
n

var m = 2
do {
m = m * 2
} while m < 100
m
```

루프 안에서 인덱스(index)를 사용해도 됩니다. 사용하는 방법으로는 `..`(마침표 두 개)를 사용해서 인덱스의 범위를 설정하는 방법도 있고, 초기화/조건부/증가시키는 부분을 작성하는 방법도 있습니다. 두 종류 모두 하는 작업은 같습니다:

```
var firstForLoop = 0
for i in 0..3 {
firstForLoop += i
}
firstForLoop
```

```
var secondForLoop = 0
for var i = 0; i < 3; ++i {
secondForLoop += 1
}
SecondForLoop
```

최댓값을 안 쓰고 범위를 만들 때에는 `..`(마침표 두 개)를 사용하고, 최댓값과 최솟값을 모두 사용해서 범위를 만들 때에는 `...`(마침표 세 개)를 사용합니다.
흐름 제어 (Control Flow)
> Translator : 김나솔(nasol.kim@gmail.com)

Swift 언어에서는 C언어 같은 프로그래밍 언어에서 제공하는 것과 비슷한 제어문 관련 constructs를 제공합니다. 이러한 constructs에는 `for`나 `while`이 있으며, 이러한 키워드는 어떤 과제(task)를 여러 번 수행합니다. `if`와 `switch`문은 특정 조건이 충족되는지에 따라서 분기시켜서 코드 블럭을 실행시킵니다. 또한 `break`나 `continue` 같은 구문은 실행의 흐름을 코드 상의 다른 곳으로 이동시킵니다.

C언어에서는 `for`-조건부-증가(increment) 순환문(loop) 이런 방식을 전통적으로 사용하는데, Swfit에서는 `for-in` 순환문(loop)이라는 것이 있어서 배열이나 사전(dictionaries), ranges, 문자열(strings)등 sequence에 대해서iteration하기가 쉽습니다.

C언어의 `switch`문과 비교했을 때, Swift의 `switch`문은 훨씬 더 강력합니다. Swift에서는 `switch`문이 "fall through" 하지 않습니다(역자주: fall through란, switch문에서 한 case에 대해서 처리하고 난 후 다음 case로 넘어가는 것). C언어에서는 실수로 `break`문을 써주지 않아서 에러가 생기는 경우가 있는데 Swift에서는 fall through 하지 않기 때문에 이런 에러를 방지할 수 있습니다. `swich`내의 case에 대해서 여러 종류의 pattern-maching을 사용할 수 있습니다. 수의 범위 match, 투플 match, casts to a specific type. `switch case`에서 match된 값을 임시 상수나 변수에 binding할 수도 있습니다. 이렇게 binding해두면 case의 본문(body) 내에서 이 상수나 변수를 사용할 수 있습니다. 또한 매칭 조건(matching condition)이 복잡한 경우에는, 각 case에 대해서 where절(where clause)을 사용해서 표현할 수 있습니다.

## `For` 순환문(For Loops)

`for` 순환문(for loop) 사용하면 코드 블럭을 특정 횟수 만큼 수행할 수 있습니다. Swift에는 두 종류의 for 순환문이 있습니다:

* `for-in` : 어떤 범위나 sequence, collection, progression에 대해서, 이 안에 있는 각 항목(item)에 대해서 코드(a set of statement)를 실행합니다.

* `for-condition-increment` : 특정 조건부가 참이 될 때까지 코드를 실행합니다. 보통 루프를 한 번 도는 것이 끝날 때마다 counter를 1씩 증가시킵니다.

## `For-In`

여러 항목이 들어 있는 컬렉션(collection)이나, 어떤 범위, 배열 안에 들어 있는 항목(item)에 대해서, 또는 문자열에 들어 있는 각 문자에 대해서 iteration을 할 때 `for-in` loop를 사용합니다.

다음의 예는 구구단의 5단에서 처음 몇 개를 출력해 줍니다:
```
for index in 1...5 { println("\(index) times 5 is \(index * 5)")
}
// 1 times 5 is 5
// 2 times 5 is 10
// 3 times 5 is 15
// 4 times 5 is 20
// 5 times 5 is 25
```

위 예에서는 범위가 1부터 5까지로 정해져 있고(closed range of numbers), 이 범위에 대해서 컬렉션(collection)안에 들어 있는 각 항목(item)에 대해 이터레이션을 돌고 있습니다. 단, 1...5라고 표현했을 때, ...(closed range operator)를 보면 알 수 있듯이, 이 범위에는 1과 5가 포함됩니다. 인덱스(index)의 값은 범위 내의 첫번째 수, 즉 1이 되며, 루프 내에 있는 구문이 실행됩니다. 위 예에서 루프 안에는 구문이 하나만 있습니다. 인덱스의 현재 값에 대해서 5단의 첫번째를 출력해주는 것입니다. 이 구문이 실행된 다음에 인덱스의 값은 범위 내의 두번째 값, 즉 2가 되도록 업데이트 됩니다. 그리고 printLn 함수가 다시 호출됩니다. 이 작업은 인덱스가 범위의 끝에 이를 때까지 계속됩니다.

위 예에서 인덱스는 상수(constant)이며, 이 상수의 값은 루프를 돌 때마다, 초반에 자동으로 값이 지정됩니다. 따라서 이 상수를 사용하기 전에 선언할 필요가 없습니다. 루프를 선언할 때 포함시키기만 해도 암묵적으로 선언한 셈이 됩니다. 즉 let 선언 키워드(declaration keyword)를 써줄 필요가 없습니다.

>NOTE - 인덱스 상수는 루프의 스코프(scope)안에서만 존재합니다. 루프문이 끝난 다음에 이 인덱스의 값을 확인하고 싶거나, 이 값을 상수가 아니라 변수로 사용하고 싶으면, 루프 안에서 변수로 직접 선언해 주어야 합니다.


범위 내에 있는 값이 필요 없다면, 변수명 대신에 언더바(`_`, underscore)를 써주면 됩니다:

```
let base = 3
let power = 10
var answer = 1
for _ in 1...power {
answer *= base
}
println("\(base) to the power of \(power) is \(answer)")
println("\(base)를 \(power)번 곱한 것은 \(answer)이다")

// prints "3 to the power of 10 is 59049"
// prints “3의 10승은 59049입니다.”
```

위 예는 어떤 수의 몇 승을 계산해 줍니다(이 예에서는 3의 10승을 계산했습니다). 시작하는 값은 1인데(이는 3의 0승입니다), 이 시작하는 값에 다시 3을 곱해줍니다. 이 때 0에서 시작해서 9에서 끝나는 half-closed loop를 사용하였습니다. 이 계산을 수행할 때, 루프를 도는 동안 counter의 값은 필요 없습니다. 정확한 횟수만큼 루프를 도는 것만이 중요합니다. 밑줄(`_`, underscore)은 위 예에서 루프 변수 자리에 쓰였는데요, 그 결과 루프를 돌 때의 counter 현재값에 접근할 수 없게 됩니다.

배열 안에 들어 있는 항목(item)에 대해서 이터레이션(iteration)을 할 때에, `for-in` 루프를 사용하세요.

```
let names = ["Anna", "Alex", "Brian", "Jack"]
for name in names {
println("Hello, \(name)!")
}
// Hello, Anna!
// Hello, Alex !
// Hello, Brian!
// Hello, Jack!
```


딕셔너리(dictionary)에 대해서도 이터레이션(iteration)을 해서 키-값 쌍(key-value pairs)에 접근할 수 있습니다. 딕셔너리에 대해서 이터레이션을 하면, 딕셔너리의 각 항목이 (key, value) 투플의 형태로 반환됩니다. 그리고 이 키-값 쌍은 쪼개어져서 두 개의 상수의 값으로 들어갑니다. 이 값은 `for-in` 루프 내의 본문(body)내에서 사용할 수 있습니다. 아래의 예에서 딕셔너리의 **키**는 animalName이라는 상수에, 딕셔너리의 **값**은 legCount라는 상수에 값으로 들어갑니다:

```
let numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
for (animalName, legCount) in numberOfLegs {
println("\(animalName)s have \(legCount) legs")
}
// spiders have 8 legs
// ants have 6 legs
// cats have 4 legs
```
딕셔너리 안에 있는 항목이 이터레이션 될 때, 딕셔너리 안에 들어 있는 순서대로 되지는 않습니다. 딕셔너리 안에 들어 있는 데이터는 원래 정의상 순서가 없으며, 이터레이션을 돌 때에도, 어느 항목에 대해서 돌지 확신할 수 없습니다. 배열과 딕셔너리에 대해서 더 자세히 보시려면 컬렉션 형(Collection Types) 장을 참조하세요.


이 이터레이션 되는 순서는 고정되어 있지 않습니다. 딕셔너리 안에 들어 있는 순서대로
배열과 딕셔너리 외에도, 문자열 내의 각 문자에 대해 이터레이션을 돌 때, `for-in` 루프를 사용할 수 있습니다:

```
for character in "Hello" {
println(character)
}
// H
// e
// l
// l
// o
```

## For-조건부-증가부 (For-Condition-Increment )

Swift는 `for-in`루프 말고도 C언어에서 쓰는, 조건부와 증가부가 들어 있는 `for` 루프를 지원합니다:

```
for var index = 0; index < 3; ++index {
println("index is \(index)")
}
// index is 0 // index is 1 // index is 2
```
다음은 이번에 다루는 루프 형식을 일반화해서 나타낸 것입니다.

```
for initialization ; condition ; increment {
statements
}
```

루프의 정의부는 세 부분으로 구성되는데, C언어에서처럼 각 부분을 세미콜론`;`으로 구분하고 있습니다. C언어와는 다르게 Swift에서는 "초기화;조건부;증가부" 부분을 괄호로 감싸주지 않아도 됩니다.

다음은 루프가 실행되는 단계를 나타냅니다:

1. 처음 루프에 들어가면, 초기화 표현식(initialization expression)이 검토되고 루프를 도는 데 필요한 변수나 상수의 값을 지정합니다.
2. 조건 표현식(condition expression)을 검토합니다. 조건부가 거짓(false)이면, 루프는 종료하고, 코드 실행(code execution)은 루프를 닫는 중괄호(})다음 부분에서 계속됩니다. 조건부가 참(true)이면, 코드 실행은 루프를 여는 괄호({) 안에서 구문들을 실행합니다.
3. 모든 구문이 실행된 후에는 증가부 표현식(increment expression)이 검토됩니다. 검토 결과 카운터의 값이 증가할 수도 있고 감소할 수도 있습니다. 또는 초기화되었던 변수의 값이 실행된 구문의 결과값에 근거하여 새로운 값으로 대체될 수도 있습니다. 증가부 부분이 검토된 후, 코드 실행은 2단계로 돌아가며, 조건 표현식이 다시 검토됩니다.

위에서 설명한 루프문의 형식(format)과 코드 실행 절차를 개요로 나타내면 다음과 같습니다:
```
initialization
while condition {
statements
increment
}
```
초기화 부분에서 선언된 상수와 변수(예를 들면 var index=0)는 `for` 루프 스코프 내에서만 사용할 수 있습니다. 루프가 끝난 후에도 index의 마지막 값에 접근할 수 있으려면, 루프 스코프가 시작하는 지점 이전에 index를 선언해주어야 합니다 (즉 루프 스코프의 바깥에서 선언해 주어야 합니다):

```
var index : Int // <= 이 부분에서 선언해 주어야..
for index = 0; index < 3; ++index {
println("index is \(index)")
}
// index is 0
// index is 1
// index is 2
println("The loop statements were executed \(index) times")
// prints "The loop statements were executed 3 times"
```

위 예에서 한 가지 주의할 점이 있습니다. 루프가 끝났을 때 index의 마지막 값은 2가 아니라 3입니다. 마지막으로 증가부(increment)가 실행되었을 때, index의 값은 3이 됩니다. index가 3이 되니, index < 3 조건부 false가 되서 루프가 끝난 것입니다.




chapter8
# 08 함수 (Functions)
> Translator : 이름 (메일주소)

함수는 특정 일을 수행하는 자기 완결성(Self-contained)을 가진 코드들의 집합입니다. 당신은 함수의 이름을 지으면서 이 함수가 무엇을 하는지 식별하게 할 수 있습니다. 그리고 그 이름으로 함수를 "호출(Call)"하여 필요할때 함수의 일을 수행하게 만들 수 있습니다.
스위프트(Swift)의 함수 문법은 파라메터가 없는 C스타일의 함수에서부터 지역 파라메터와 파라메터 이름 각각에 대한 외부 파라메터를 가지고 있는 복잡한 오브젝티브-C 스타일의 함수까지 전부 표현할 수 있습니다. 파라메터는 기본 값을 가질수 있어 단순한 함수 호출에 쓰일수 있습니다. 또한 In-out 파라메터로서 변수를 넘겨 변수가 함수의 실행후에 파라메터가 변경되게 할 수도 있습니다.
파라메터 타입과 반환(Return) 타입으로 이루어진 모든 스위프트의 함수들은 타입을 가집니다. 스위프트에 있는 다른 타입들과 마찬가지로, 함수의 타입들을 사용할 수 있습니다. 즉 함수를 다른 함수에 파라메터로서 넘겨주거나 함수를 다른 함수에서 반환받을 수 있습니다. 함수들은 유용한 기능 캡슐화를 위해 중첩된 함수안의 범위 내에서 쓰여질수도 있습니다.

## 함수 정의와 호출
함수를 정의할때 함수의 입력(파라메터)을 하나 이상의 이름이 있고 타입이 정해진 값으로 할 수 있습니다. 또한 값의 타입은 함수의 실행이 끝났을때 함수가 되돌려줄 수 있습니다 (반환 타입).
모든 함수는 함수명을 가지고 있으며, 함수명은 함수가 하는일을 설명해줍니다. 함수를 사용하기위해서 함수를 함수의 이름을 사용하여 "호출"하고 함수의 파라메터 타입들과 일치하는 입력 값들(아규먼트Arguments)을 넘겨줍니다. 함수의 입력값은 함수의 파라메터리스트와 언제나 일치해야합니다.
아래의 함수 예제 이름은 `greetingForPerson`입니다. 함수가 행하는 일이 바로 그것(사람에게 환영인사Greeting for person)이기 때문입니다. 입력으로 사람의 이름을 받아서 그 사람에 대한 환영 인사를 반환합니다. 이를 달성하기 위해 파라메터를 하나 정의하고 - `personName`이라는 `String` 값 - 반환 타입을 `String`으로 합니다. 그렇게 그 사람에 대한 인사를 포함하는 것입니다.

```
func sayHello(personName: String) -> String {
let greeting = "Hello, " + personName + "!"
return greeting
}
```
이 모든 정보들은 func 키워드 접두어를 쓰는 함수의 정의안에 포함이 되게도비니다. 함수의 반환 타입은 화살표(하이픈과 우측 꺽괄호) `->`를 사용하여 화살표 오른쪽에 표시합니다.
함수 정의는 함수가 무엇을 하는지, 무엇을 파라메터로 받는지 완료되었을때 무엇을 반환하는지 설명합니다. 함수 정의는 함수가 코드안에서 호출될때 명확하고 애매함이 없는 방법으로 사용될수 있게합니다:

```
println(sayHello("Anna"))
// prints "Hello, Anna!"
println(sayHello("Brian"))
// prints "Hello, Brian!"
```
`sayHello` 함수를 괄호안에 `String` 타입의 인수를 넣어서 호출합니다. 예를들면 `sayHello("Anna")` 처럼 말이죠. `sayHello`가 `String`타입을 반환하기에 `sayHello`함수는 println로 싸여서 호출될 수 있습니다. 이렇게 함으로서 println함수가 sayHello함수의 반환값을 위에 보이는 것처럼 출력할 수 있습니다.
`sayHello`함수의 몸체는 `greeting`이라는 새 `String` 상수를 선언하는 것으로 시작합니다. 그리고 `greeting`을 `personName`에 대한 단순한 환영인사로 설정합니다. 이 환영 인사는 `return`키워드를 통해 함수의 밖으로 되돌려지게 됩니다. `return greeting`이 실행 되면 함수의 실행은 끝나게되고, `greeting`의 현재 값을 돌려주게됩니다.
`sayHello` 함수를 다른 입력값으로 여러번 호출할 수 있습니다. 위의 예제는 입력값이 "Anna", "Brian" 일때를 각각 보여주고 있습니다. 함수는 사람(입력값)에 맞게끔 환영인사를 각각의 경우에 맞추어 돌려줍니다.
함수 몸체를 단순화하기 위해서는, 메시지의 생성과 반환을 한줄로 합치면 됩니다:
```
func sayHelloAgain(personName: String) -> String {
return "Helloagain, " + personName + "!"
}
println(sayHelloAgain("Anna"))
// prints "Helloagain, Anna!
```
## 함수 파라메터와 반환값
스위프트에서 함수 파라메터와 반환값은 극도로 유연합니다. 이름없는 파라메터를 사용하는 단순한 기능성 함수에서부터 명시적 파라메터 이름(expressive parameter names)과 다른 파라메터 옵션을 가진 복잡한 함수에 이르기까지 무엇이든 정의할수 있습니다.

## 파라메터 복수 입력
함수는 괄호 안에서 콤마로 구분되는 복수의 입력 파라메터를 가질수 있습니다.
이 함수는 반개영역(half-open range)의 시작과 끝의 인덱스를 받아 얼마나 많은 요소(elements)들이 영역안에 있는지 계산합니다:

func halfOpenRangeLength(start: Int, end: Int) -> Int {
return end - start
}
println(halfOpenRangeLength(1, 10))
// prints "9"

## 파라메터가 없는 함수
함수에 입력 파라메터를 정의할 필요는 없습니다. 밑의 예제는 입력 파라메터가 없는 함수입니다. 이 함수는 호출될때마다 언제나 같은 메시지를 반환합니다.

func sayHelloWorld() -> String {
return "hello, world"
}
println(sayHelloWorld())
// prints "hello, world"

함수 정의는 아무런 파라메터를 받지 않는다고 해도 함수 이름뒤에 여전히 괄호를 포함해야 합니다. 함수가 호출될 때도 함수 이름뒤에 빈 괄호 한쌍이 따라와야합니다.

## 반환값이 없는 함수
함수에 반환 타입을 정의할 필요는 없습니다. 밑의 예제는 `sayHello`의 `waveGoodbye`라 불리는 버전입니다. 값을 반환하지 않고 자신만의 `String`값을 출력합니다.

func sayGoodbye(personName: String) {
println("Goodbye, ` \(personName)! ")
}
sayGoodbye("Dave")
// prints "Goodbye, Dave!"

반환값을 필요로 하지 않기 때문에 함수 정의는 반환 화살표(return arrow)나 반환 타입을 포함하지 않습니다.

> N O T E
엄밀히 말하자면, `sayGoodbye` 함수는 반환값이 정의되어있지 않아도 여전히 반환값을 가집니다. 반환값이 정의되어있지 않은 함수는 `Void`타입의 특수값을 반환합니다. '()'로 쓰여질수 있는 단순한 빈 튜플(Tuple)이며, 사실상 요소를 갖고있지 않은 튜플입니다.

함수가 호출되었을때 함수의 반환값은 무시될수 있다.
```
func printAndCount(stringToPrint: String) -> Int {
println(stringToPrint)
return countElements(stringToPrint)
}
func printWithoutCounting(stringToPrint: String) {
printAndCount(stringToPrint)
}
printAndCount("hello, world")
// prints "hello, world" and returns a value of 12
printWithoutCounting("hello, world")
// prints "hello, world" but does not return a value
```
첫번째 함수인 `printAndCount`는 문자열을 출력하고 출력한 문자열의 캐릭터 갯수를 세서 Int 타입으로 반환합니다. 두번째 함수인 `printWithoutCounting`은 첫번째 함수를 호출합니다. 하지만 반환값은 무시합니다. 두번째 함수가 호출되면 메시지는 첫번째 함수에 의해 여전히 출력되지만, 첫번째 함수의 반환값은 사용되지 않습니다.

> N O T E
반환값은 무시될수 있습니다. 하지만 함수는 언제나 값을 반환할것입니다. 반환 타입이 정의된 함수는 값을 반환하지 않은채로 함수가 실행 될수 없습니다. 그렇게 하려고 시도할 경우 컴파일 에러를 낼 것입니다.

## 여러개의 반환값을 가지는 함수
튜플 타입은 하나의 합성된 반환값으로서 함수의 반환에 사용될 수 있습니다.
아래의 예제는 `count`라는 함수의 정의입니다. 이 함수는 아메리칸 영어에서 사용되는 표준 모음과 자음을 기반으로 모음과 자음 그리고 다른 문자들을 문자열안에서 셉니다.
```
func count(string: String) -> (vowels: Int, consonants: Int, others: Int) {
var vowels = 0, consonants = 0, others = 0
for character in string {
switch String(character).lowercaseString {
case "a", "e", "i ", "o", "u":
++vowels
case "b", "c", "d", "f", "g", "h", "j", "k", "l ", "m",
"n", "p", "q", "r", "s", "t", "v", "w ", "x", "y", "z":
++consonants
default:
++others
}
}
return (vowels, consonants, others)
}
```
이 count 함수를 이용함으로서 임의의 문자열의 문자 갯수를 셀수 있습니다. 그리고 세 개의 이름있는 Int 값으로 구성된 튜플로 그 값을 받아옵니다.
```
let total = count("some arbitrary string! ")
println("\(total.vowels) vowels and \(total.consonants) consonants")
// prints "6 vowels and 13 consonants"
```
튜플의 멤버들은 함수 내에서 반환할때 이름을 지을 필요가 없습니다. 함수 정의시에 함수의 반환 타입에 이미 명시가 되어있기 때문입니다.

## 함수 파라메터 이름
위의 모든 함수들은 함수 자신의 파라메터로 파라메터 이름을 정의하고 있다.
```
func someFunction(parameterName: Int) {
// function body goes here, and can use parameterName
// to refer to the argument value for that parameter
}
```
하지만 그러한 파라메터 이름들은 오직 함수 자신의 몸체(Body) 안에서만 사용될 수 있습니다. 또한 함수를 호출할때는 사용할 수 없습니다. 그러한 종류의 파라메터 이름은 지역 파라메터 이름(local parameter names)이라고 합니다. 오직 함수의 내부(Body)에서만 사용할 수 있기 때문입니다.

## 외부 파라메터 이름(External Parameter Names)
때때로 각각의 파라메터의 이름을 함수를 호출할때 지어주는 것이 유용할때가 있습니다. 함수에게 어떤 인수가 어떤 목적인지 지시하기 위해서죠.
만약 당신이 만든 함수를 사용하려는 사용자에게 파라메터 이름을 제공하고 싶다면, 지역 파라메터 이름과 외부 파라메터 이름을 정의하면 됩니다. 외부 파라메터 이름은 지역 파라메터 이름 바로 앞에 공백으로 구분해서 작성합니다.
```
func someFunction(external ParameterName localParameterName: Int) {
// function body goes here, and can use local ParameterName
// to refer to the argument value for that parameter
}
```
> N O T E
만약 외부 파라메터 이름이 파라메터에 대해 제공된다면, 외부 파라메터 이름은 언제나 함수 호출시에 사용되어야 합니다.

예를 들어 다음과 같은 함수가 있다고 합시다. 이 함수는 두 문자열 사이에 `joiner` 문자열을 삽입해 연결하는 함수입니다.

func join(s1: String, s2: String, joiner: String) -> String {
return s1 + joiner + s2
}

이 함수를 호출할때 함수로 전달되는 세 문자열의 목적이 불분명합니다.

join("hello", "world", ", ")
// returns "hello, world"

문자열 값들의 목적을 명확하게 하기 위해, 외부 파라메터를 join함수의 각각의 파라메터에 정의합니다.

```
func join(string s1: String, toString s2: String, withJoiner joiner: String) -> String {
return s1 + joiner + s2
}
```

이 버전의 join 함수에서는 첫번째 파라메터의 외부 이름은 `string`이며 지역 이름은 `s1`이다. 두번째 파라메터는 외부 이름으로 `toString`을 쓰고 지역 이름은 `s2`이다. 그리고 세번째 파라메터는 외부 이름으로 `withJoiner`를 쓰고 지역 이름은 `joiner`이다.
이제 외부 파라메터 이름을 사용하여 함수를 호출할때 명확하고 애매하지 않은 방법으로 호출할 수 있게 되었다.

join(string: "hello", toString: "world", withJoiner: ", ")
// returns "hello, world"

외부 파라메터 이름의 사용은 이 두번째 join함수를 명시적이며 말이 되는(sentence-like) 방법으로 사용자들이 호출할 수 있게 합니다. 함수 몸체는 여전히 가독성이 좋고 명확한 의도를 가진채 말이죠. (whi le sti l l providing a function body that is readable and clear in intent.)

>N O T E
누군가가 당신의 코드를 처음 보았을때 명확하지 않을 수 있다면 외부 파라메터 이름을 쓰는것을 언제나 고려하십시오. 만약 함수가 호출될때 각각의 파라메터들의 목적이 명확하고 모호하지 않다면 외부 파라메터 이름을 정할 필요는 없습니다.

## 단축 외부 파라메터 이름
만약 함수의 외부 파라메터 이름을 제공하려 할때 이미 해당 파라메터의 내부 이름(local parameter name)이 이미 적절한 이름을 가지고 있다면, 똑같은 이름을 두번 쓸 필요가 없다. 대신 파라메터 이름을 한번 쓰고, 이름의 접두어로 해시 심볼(hash symbol) (`#`)을 붙인다. 이렇게 함으로서 스위프트는 해당 이름을 외부 파라메터 이름과 지역 파라메터 이름으로 동시에 쓰게 될 것이다.
이 예제는 `containsCharacter` 함수를 정의하고 호출한다. 해당 함수는 두 입력 파라메터에 `#`을 붙여서 같은 이름으로 외부 파라메터 이름과 내부 파라메터 이름으로 쓰이게 하였다.
```
func containsCharacter(#string: String, #characterToFind: Character) -> Bool {
for character in string {
if character == characterToFind {
return true
}
}
return false
}
```
이 함수의 파라메터 이름 선정은 함수 몸체를 명확하고 가독성있게 하며 동시에 함수 호출에 모호함이 없게 하였다.
```
let containsAVee = containsCharacter(string: "aardvark", characterToFind: "v")
// containsAVee equals true, because "aardvark" contai ns a "v"
```
## 기본(default) 파라메터 값
함수 정의의 일부로서 파라메터의 기본 값을 지정해줄 수 있다. 기본값이 지정되어 있으면 함수를 호출할때 해당 파라메터를 생략할 수 있다.

>N O T E
기본값을 가지는 파라메터는 함수의 파라메터 리스트에서 마지막에 둔다. 이렇게 함으로써 함수 호출이 기본값을 가지지 않는 파라메터들이 언제나 같은 순서임을 보장할 수 있고, 매번 함수가 호출될 때마다 같은 함수가 호출되게 한다.

앞서 보인 `join`함수의 `joiner` 파라메터에 기본값을 부여한 버전이 있다.
```
func join(string s1: String, toString s2: String, withJoiner joiner: String = " ")
-> String {
return s1 + joiner + s2
}
```
만약 `join`함수의 `joiner` 문자열 값이 주어지면, 앞서 보았던 것처럼 해당 문자열 값이 두 문자열을 붙이는데 사용된다.
```
join(string: "hello", toString: "world", withJoiner: "-")
// returns "hello-world
```
하지만 아무런 값이 `joiner`에 주어지지 않는다면, 기본값인 공백 한칸 (`" "`)이 대신 사용된다.
```
join(string: "hello", toString: "world")
// returns "hello world"
```
## 기본값을 가지는 외부 파라메터 이름
대부분의 경우 외부 파라메터 이름에 기본값을 제공(외부 파라메터이기에 요구되기도 하는)하는 것은 유용하다. 그렇게 함으로써 함수가 호출될때 인수가 파라메터에 대해 가지는 목적이 명확해진다.
이 과정을 쉽게 하기위해, 외부 이름을 부여하지 않은 파라메터에 대해 스위프트는 자동 외부 이름을 기본값이 정의되어 있는 파라메터에 대해 제공한다. 자동 외부 이름은 지역 이름과 똑같다. 앞서 본 해시 심볼(`#`)을 사용한 것처럼.
여기에 `joiner` 문자열 값에 기본값을 부여하였지만, 파라메터 일체에 외부 파라메터 이름은 주지 않은 버전의 `join`함수가 있다.
```
func join(s1: String, s2: String, joiner: String = " ") -> String {
return s1 + joiner + s2
}
```
이 경우에 스위프트는 자동적으로 외부 파라메터 이름을 기본값이 있는 파라메터 `joiner`에 대해 부여한다. 그러므로 외부 이름은 반드시 함수가 호출 될 때에 제공되어야 하며, 파라메터의 목적을 명확하고 모호하지 않게 한다.
```
join("hello", "world", joiner: "-")
// returns "hello-world"
```
>N O T E
함수를 정의할때 명시적인 외부 이름을 쓰는 것 대신에 밑줄(`_`)을 씀으로써 이 동작을 수행하지 않게 할 수 있다. 하지만 기본값을 가진 파라메터에 적절한 외부 이름을 제공하는것은 언제나 바람직하다.

## Variadic Parameters
A variadi c parameter accepts zero or more values of a speci fied type. You use a variadi c
parameter to speci fy that the parameter can be passed a varying number of input values
when the function i s cal led. Wri te variadi c parameters by inserting three period
characters (. . .) after the parameter’s type name.
The values passed to a variadi c parameter are made avai lable wi thin the function’s body
as an array of the appropriate type. For example, a variadi c parameter wi th a name of
numbers and a type of Doubl e. . . i s made avai lable wi thin the function’s body as a constant
array cal led numbers of type Doubl e[].
The example below cal culates the ari thmeti c mean (al so known as the average) for a l i st
of numbers of any length:
func ari thmeti cMean(numbers: Doubl e. . . ) -> Doubl e {
var total : Doubl e = 0
for number i n numbers {
total += number
}
return total / Doubl e(numbers. count)
}
ari thmeti cMean(1, 2, 3, 4, 5)
// returns 3. 0, w hi ch i s the ari thmeti c mean of these fi ve numbers
meti cMean(3, 8, 19)
turns 10. 0, w hi ch i s the ari thmeti c mean of these three numbers
> N O T E
A functi on may have at most one vari adi c parameter, and i t must al w ays appear l ast i n the parameter l i st, to
avoi d ambi gui ty w hen cal l i ng the functi on w i th mul ti pl e parameters.
If your functi on has one or more parameters w i th a defaul t val ue, and al so has a vari adi c parameter, pl ace
the vari adi c parameter after al l the defaul ted parameters at the very end of the l i st.

## Constant and Variable Parameters
Function parameters are constants by defaul t. Trying to change the value of a function
parameter from wi thin the body of that function resul ts in a compi le-time error. Thi s
means that you can’t change the value of a parameter by mi stake.
However, sometimes i t i s useful for a function to have a variable copy of a parameter’s
value to work wi th. You can avoid defining a new variable yoursel f wi thin the function by
speci fying one or more parameters as variable parameters instead. Variable parameters
are avai lable as variables rather than as constants, and give a new modi fiable copy of the
parameter’s value for your function to work wi th.
Define variable parameters by prefixing the parameter name wi th the keyword var:
func al i gnRi ght(var stri ng: Stri ng, count: Int, pad: Character) -> Stri ng {
l et amountT oPad = count - countEl ements(stri ng)
for _ i n 1. . . amountT oPad {
stri ng = pad + stri ng
}
return stri ng
}
l et ori gi nal Stri ng = "hel l o"
l et paddedStri ng = al i gnRi ght(ori gi nal Stri ng, 10, "-")
addedStri ng i s equal to "- - - - -hel l o"
i gi nal Stri ng i s sti l l equal to "hel l o"
Thi s example defines a new function cal led al i gnRi ght, whi ch al igns an input string to the
right edge of a longer output string. Any space on the left i s fi l led wi th a speci fied
padding character. In thi s example, the string "hel l o" i s converted to the string "- - - - -hel l o".
The al i gnRi ght function defines the input parameter stri ng to be a variable parameter. Thi s
means that stri ng i s now avai lable as a local variable, ini tial i zed wi th the passed-in string
value, and can be manipulated wi thin the body of the function.
The function starts by working out how many characters need to be added to the left of
stri ng in order to right-al ign i t wi thin the overal l string. Thi s value i s stored in a local
constant cal led amountT oPad. The function then adds amountT oPad copies of the pad character
to the left of the exi sting string and returns the resul t. It uses the stri ng variable parameter
for al l i ts string manipulation.

>N O T E
T he changes you make to a vari abl e parameter do not persi st beyond the end of each cal l to the functi on,
and are not vi si bl e outsi de the functi on’s body. T he vari abl e parameter onl y exi sts for the l i feti me of that
functi on cal l .

## In-Out Parameters
Variable parameters, as described above, can only be changed wi thin the function i tsel f.
If you want a function to modi fy a parameter’s value, and you want those changes to
persi st after the function cal l has ended, define that parameter as an in-out parameter
instead.
You wri te an in-out parameter by placing the i nout keyword at the start of i ts parameter
defini tion. An in-out parameter has a value that i s passed in to the function, i s modi fied
by the function, and i s passed back out of the function to replace the original value.
You can only pass a variable as the argument for an in-out parameter. You cannot pass a
constant or a l i teral value as the argument, because constants and l i teral s cannot be
modi fied. You place an ampersand (&) di rectly before a variable’s name when you pass i t
as an argument to an inout parameter, to indi cate that i t can be modi fied by the function.
>N O T E
In-out parameters cannot have defaul t val ues, and vari adi c parameters cannot be marked as i nout. If you
mark a parameter as i nout, i t cannot al so be marked as var or l et.

Here’s an example of a function cal led sw apT w oInts, whi ch has two in-out integer
parameters cal led a and b:
func sw apT w oInts(i nout a: Int, i nout b: Int) {
l et temporaryA = a
a = b
b = temporaryA
}
The sw apT w oInts function simply swaps the value of b into a, and the value of a into b. The
function performs thi s swap by storing the value of a in a temporary constant cal led
temporaryA, assigning the value of b to a, and then assigning temporaryA to b.
You can cal l the sw apT w oInts function wi th two variables of type Int to swap thei r values.
Note that the names of someInt and anotherInt are prefixed wi th an ampersand when they
are passed to the sw apT w oInts function:
var someInt = 3
var anotherInt = 107
sw apT w oInts(&someInt, &anotherInt)
pri ntl n("someInt i s now \(someInt), and anotherInt i s now \(anotherInt)")
// pri nts "someInt i s now 107, and anotherInt i s now 3"
The example above shows that the original values of someInt and anotherInt are modi fied by
the sw apT w oInts function, even though they were original ly defined outside of the function.
>N O T E
In-out parameters are not the same as returni ng a val ue from a functi on. T he sw apT w oInts exampl e above
does not defi ne a return type or return a val ue, but i t sti l l modi fi es the val ues of someInt and anotherInt. Inout parameters are an al ternati ve w ay for a functi on to have an effect outsi de of the scope of i ts functi on
body.

## Function Types
Every function has a speci fi c function type, made up of the parameter types and the
return type of the function.
For example:
func addT w oInts(a: Int, b: Int) -> Int {
return a + b
}
func mul ti pl yT w oInts(a: Int, b: Int) -> Int {
return a * b
}
Thi s example defines two simple mathemati cal functions cal led addT w oInts and mul ti pl yT w oInts.
These functions each take two Int values, and return an Int value, whi ch i s the resul t of
performing an appropriate mathemati cal operation.
The type of both of these functions i s (Int, Int) -> Int. Thi s can be read as:
“A function type that has two parameters, both of type Int, and that returns a value of
type Int.”
Here’s another example, for a function wi th no parameters or return value:
func pri ntHel l oWorl d() {
pri ntl n("hel l o, w orl d")
}
The type of thi s function i s () -> (), or “a function that has no parameters, and returns Voi d.”
Functions that don’t speci fy a return value always return Voi d, whi ch i s equivalent to an
empty tuple in Swi ft, shown as ().
## Using Function Types
You use function types just l ike any other types in Swi ft. For example, you can define a
constant or variable to be of a function type and assign an appropriate function to that
variable:
var mathFuncti on: (Int, Int) -> Int = addT w oInts
Thi s can be read as:
“Define a variable cal led mathFuncti on, whi ch has a type of ‘a function that takes two Int
values, and returns an Int value.’ Set thi s new variable to refer to the function cal led
addT w oInts.”
The addT w oInts function has the same type as the mathFuncti on variable, and so thi s
assignment i s al lowed by Swi ft’s type-checker.
You can now cal l the assigned function wi th the name mathFuncti on:
pri ntl n("Resul t: \(mathFuncti on(2, 3))")
// pri nts "Resul t: 5"
A di fferent function wi th the same matching type can be assigned to the same variable, in
the same way as for non-function types:
mathFuncti on = mul ti pl yT w oInts
pri ntl n("Resul t: \(mathFuncti on(2, 3))")
// pri nts "Resul t: 6"
As wi th any other type, you can leave i t to Swi ft to infer the function type when you
assign a function to a constant or variable:
l et anotherMathFuncti on = addT w oInts
// anotherMathFuncti on i s i nferred to be of type (Int, Int) -> Int
## Function Types as Parameter Types
You can use a function type such as (Int, Int) -> Int as a parameter type for another
function. Thi s enables you to leave some aspects of a function’s implementation for the
function’s cal ler to provide when the function i s cal led.
Here’s an example to print the resul ts of the math functions from above:
func pri ntMathResul t(mathFuncti on: (Int, Int) -> Int, a: Int, b: Int) {
pri ntl n("Resul t: \(mathFuncti on(a, b))")
}
pri ntMathResul t(addT w oInts, 3, 5)
// pri nts "Resul t: 8"
Thi s example defines a function cal led pri ntMathResul t, whi ch has three parameters. The fi rst
parameter i s cal led mathFuncti on, and i s of type (Int, Int) -> Int. You can pass any function of
that type as the argument for thi s fi rst parameter. The second and thi rd parameters are
cal led a and b, and are both of type Int. These are used as the two input values for the
provided math function.
When pri ntMathResul t i s cal led, i t i s passed the addT w oInts function, and the integer values 3
and 5. It cal l s the provided function wi th the values 3 and 5, and prints the resul t of 8.
The role of pri ntMathResul t i s to print the resul t of a cal l to a math function of an appropriate
type. It doesn’t matter what that function’s implementation actual ly does—i t matters only
that the function i s of the correct type. Thi s enables pri ntMathResul t to hand off some of i ts
functional i ty to the cal ler of the function in a type-safe way.
## Function Types as Return Types
You can use a function type as the return type of another function. You do thi s by wri ting
a complete function type immediately after the return arrow (->) of the returning function.
The next example defines two simple functions cal led stepForw ard and stepBackw ard. The
stepForw ard function returns a value one more than i ts input value, and the stepBackw ard
function returns a value one less than i ts input value. Both functions have a type of (Int) ->
Int:
func stepForw ard(i nput: Int) -> Int {
return i nput + 1
}
func stepBackw ard(i nput: Int) -> Int {
return i nput - 1
}
Here’s a function cal led chooseStepFuncti on, whose return type i s “a function of type (Int) -> Int”.
chooseStepFuncti on returns the stepForw ard function or the stepBackw ard function based on a
Boolean parameter cal led backw ards:
func chooseStepFuncti on(backw ards: Bool ) -> (Int) -> Int {
return backw ards ? stepBackw ard : stepForw ard
}
You can now use chooseStepFuncti on to obtain a function that wi l l step in one di rection or the
other:
var currentVal ue = 3
l et moveNearerT oZero = chooseStepFuncti on(currentVal ue > 0)
// moveNearerT oZero now refers to the stepBackw ard() functi on
The preceding example works out whether a posi tive or negative step i s needed to move
a variable cal led currentVal ue progressively closer to zero. currentVal ue has an ini tial value of 3,
whi ch means that currentVal ue > 0 returns true, causing chooseStepFuncti on to return the
stepBackw ard function. A reference to the returned function i s stored in a constant cal led
moveNearerT oZero.
Now that moveNearerT oZero refers to the correct function, i t can be used to count to zero:
pri ntl n("Counti ng to zero:")
// Counti ng to zero:
w hi l e currentVal ue ! = 0 {
pri ntl n("\(currentVal ue). . . ")
currentVal ue = moveNearerT oZero(currentVal ue)
}
pri ntl n("zero! ")
// 3. . .
// 2. . .
. .
ero!
## Nested Functions
Al l of the functions you have encountered so far in thi s chapter have been examples of
global functions, whi ch are defined at a global scope. You can al so define functions inside
the bodies of other functions, known as nested functions.
Nested functions are hidden from the outside world by defaul t, but can sti l l be cal led and
used by thei r enclosing function. An enclosing function can al so return one of i ts nested
functions to al low the nested function to be used in another scope.
You can rewri te the chooseStepFuncti on example above to use and return nested functions:
func chooseStepFuncti on(backw ards: Bool ) -> (Int) -> Int {
func stepForw ard(i nput: Int) -> Int { return i nput + 1 }
func stepBackw ard(i nput: Int) -> Int { return i nput - 1 }
return backw ards ? stepBackw ard : stepForw ard
}
var currentVal ue = -4
l et moveNearerT oZero = chooseStepFuncti on(currentVal ue > 0)
// moveNearerT oZero now refers to the nested stepForw ard() functi on
w hi l e currentVal ue ! = 0 {
ri ntl n("\(currentVal ue). . . ")
urrentVal ue = moveNearerT oZero(currentVal ue)
("zero! ")
. . .
. . .
. . .
. . .
ero!
chapter9
# 09 클로저 (Closures)
> Translator : 이름 (메일주소)


Closures
Closures are sel f-contained blocks of functional i ty that can be passed around and used in
your code. Closures in Swi ft are simi lar to blocks in C and Objective-C and to lambdas in
other programming languages.
Closures can capture and store references to any constants and variables from the
context in whi ch they are defined. Thi s i s known as closing over those constants and
variables, hence the name “closures”. Swi ft handles al l of the memory management of
capturing for you.
N O T E
Don’t w orry i f you are not fami l i ar w i th the concept of “capturi ng”. It i s expl ai ned i n detai l bel ow i n Capturi ng
Val ues.
Global and nested functions, as introduced in Functions, are actual ly special cases of
closures. Closures take one of three forms:
Swi ft’s closure expressions have a clean, clear style, wi th optimi zations that encourage
brief, clutter-free syntax in common scenarios. These optimi zations include:
Closure Expressions
Global functions are closures that have a name and do not capture any values.
Nested functions are closures that have a name and can capture values from thei r
enclosing function.
Closure expressions are unnamed closures wri tten in a l ightweight syntax that can
capture values from thei r surrounding context.
Inferring parameter and return value types from context
Impl i ci t returns from single-expression closures
Shorthand argument names
Trai l ing closure syntax
Nested functions, as introduced in Nested Functions, are a convenient means of naming
and defining sel f-contained blocks of code as part of a larger function. However, i t i s
sometimes useful to wri te shorter versions of function-l ike constructs wi thout a ful l
declaration and name. Thi s i s parti cularly true when you work wi th functions that take
other functions as one or more of thei r arguments.
Closure expressions are a way to wri te inl ine closures in a brief, focused syntax. Closure
expressions provide several syntax optimi zations for wri ting closures in thei r simplest
form wi thout loss of clari ty or intent. The closure expression examples below i l lustrate
these optimi zations by refining a single example of the sort function over several
i terations, each of whi ch expresses the same functional i ty in a more succinct way.
The Sort Function
Swi ft’s standard l ibrary provides a function cal led sort, whi ch sorts an array of values of a
known type, based on the output of a sorting closure that you provide. Once i t completes
the sorting process, the sort function returns a new array of the same type and si ze as the
old one, wi th i ts elements in the correct sorted order.
The closure expression examples below use the sort function to sort an array of Stri ng
values in reverse alphabeti cal order. Here’s the ini tial array to be sorted:
l et names = ["Chri s", "Al ex", "Ew a", "Barry", "Dani el l a"]
The sort function takes two arguments:
Thi s example i s sorting an array of Stri ng values, and so the sorting closure needs to be a
function of type (Stri ng, Stri ng) -> Bool .
One way to provide the sorting closure i s to wri te a normal function of the correct type,
and to pass i t in as the sort function’s second parameter:
func backw ards(s1: Stri ng, s2: Stri ng) -> Bool {
return s1 > s2
}
An array of values of a known type.
A closure that takes two arguments of the same type as the array’s contents, and
returns a Bool value to say whether the fi rst value should appear before or after the
second value once the values are sorted. The sorting closure needs to return true i f
the fi rst value should appear before the second value, and fal se otherwi se.
var reversed = sort(names, backw ards)
// reversed i s equal to ["Ew a", "Dani el l a", "Chri s", "Barry", "Al ex"]
If the fi rst string (s1) i s greater than the second string (s2), the backw ards function wi l l return
true, indi cating that s1 should appear before s2 in the sorted array. For characters in
strings, “greater than” means “appears later in the alphabet than”. Thi s means that the
letter "B" i s “greater than” the letter "A", and the string "T om" i s greater than the string
"T i m". Thi s gives a reverse alphabeti cal sort, wi th "Barry" being placed before "Al ex", and so
on.
However, thi s i s a rather long-winded way to wri te what i s essential ly a single-expression
function (a > b). In thi s example, i t would be preferable to wri te the sorting closure inl ine,
using closure expression syntax.
Closure Expression Syntax
Closure expression syntax has the fol lowing general form:
{ ( parameters ) -> return type i n
statements
}
Closure expression syntax can use constant parameters, variable parameters, and i nout
parameters. Defaul t values cannot be provided. Variadi c parameters can be used i f you
name the variadi c parameter and place i t last in the parameter l i st. Tuples can al so be
used as parameter types and return types.
The example below shows a closure expression version of the backw ards function from
earl ier:
reversed = sort(names, { (s1: Stri ng, s2: Stri ng) -> Bool i n
return s1 > s2
})
Note that the declaration of parameters and return type for thi s inl ine closure i s identi cal
to the declaration from the backw ards function. In both cases, i t i s wri tten as (s1: Stri ng, s2:
Stri ng) -> Bool . However, for the inl ine closure expression, the parameters and return type
are wri tten inside the curly braces, not outside of them.
The start of the closure’s body i s introduced by the i n keyword. Thi s keyword indi cates
that the defini tion of the closure’s parameters and return type has fini shed, and the body
of the closure i s about to begin.
Because the body of the closure i s so short, i t can even be wri tten on a single l ine:
reversed = sort(names, { (s1: Stri ng, s2: Stri ng) -> Bool i n return s1 > s2 } )
Thi s i l lustrates that the overal l cal l to the sort function has remained the same. A pai r of
parentheses sti l l wrap the enti re set of arguments for the function. However, one of those
arguments i s now an inl ine closure.
Inferring Type From Context
Because the sorting closure i s passed as an argument to a function, Swi ft can infer the
types of i ts parameters and the type of the value i t returns from the type of the sort
function’s second parameter. Thi s parameter i s expecting a function of type (Stri ng, Stri ng) ->
Bool . Thi s means that the Stri ng, Stri ng, and Bool types do not need to be wri tten as part of the
closure expression’s defini tion. Because al l of the types can be inferred, the return arrow
(->) and the parentheses around the names of the parameters can al so be omi tted:
reversed = sort(names, { s1, s2 i n return s1 > s2 } )
It i s always possible to infer parameter types and return type when passing a closure to a
function as an inl ine closure expression. As a resul t, you rarely need to wri te an inl ine
closure in i ts ful lest form.
Nonetheless, you can make the types expl i ci t i f you wi sh, and doing so i s encouraged i f i t
avoids ambigui ty for readers of your code. In the case of the sort function, the purpose of
the closure i s clear from the fact that sorting i s taking place, and i t i s safe for a reader to
assume that the closure i s l ikely to be working wi th Stri ng values, because i t i s assi sting
wi th the sorting of an array of strings.
Implicit Returns from Single-Expression Closures
Single-expression closures can impl i ci tly return the resul t of thei r single expression by
omi tting the return keyword from thei r declaration, as in thi s version of the previous
example:
reversed = sort(names, { s1, s2 i n s1 > s2 } )
Here, the function type of the sort function’s second argument makes i t clear that a Bool
value must be returned by the closure. Because the closure’s body contains a single
expression (s1 > s2) that returns a Bool value, there i s no ambigui ty, and the return keyword
can be omi tted.
Shorthand Argument Names
Swi ft automati cal ly provides shorthand argument names to inl ine closures, whi ch can be
used to refer to the values of the closure’s arguments by the names $0, $1, $2, and so on.
If you use these shorthand argument names wi thin your closure expression, you can omi t
the closure’s argument l i st from i ts defini tion, and the number and type of the shorthand
argument names wi l l be inferred from the expected function type. The i n keyword can al so
be omi tted, because the closure expression i s made up enti rely of i ts body:
reversed = sort(names, { $0 > $1 } )
Here, $0 and $1 refer to the closure’s fi rst and second Stri ng arguments.
Operator Functions
There’s actual ly an even shorter way to wri te the closure expression above. Swi ft’s Stri ng
type defines i ts string-speci fi c implementation of the greater-than operator (>) as a
function that has two parameters of type Stri ng, and returns a value of type Bool . Thi s
exactly matches the function type needed for the sort function’s second parameter.
Therefore, you can simply pass in the greater-than operator, and Swi ft wi l l infer that you
want to use i ts string-speci fi c implementation:
reversed = sort(names, >)
For more about operator functions, see Operator Functions.
Trailing Closures
If you need to pass a closure expression to a function as the function’s final argument and
the closure expression i s long, i t can be useful to wri te i t as a trai l ing closure instead. A
trai l ing closure i s a closure expression that i s wri tten outside of (and after) the
parentheses of the function cal l i t supports:
func someFuncti onT hatT akesACl osure(cl osure: () -> ()) {
// functi on body goes here
}
// here's how you cal l thi s functi on w i thout usi ng a trai l i ng cl osure:
someFuncti onT hatT akesACl osure({
// cl osure's body goes here
})
ere's how you cal l thi s functi on w i th a trai l i ng cl osure i nstead:
eFuncti onT hatT akesACl osure() {
/ trai l i ng cl osure's body goes here
N O T E
If a cl osure expressi on i s provi ded as the functi on’s onl y argument and you provi de that expressi on as a
trai l i ng cl osure, you do not need to w ri te a pai r of parentheses () after the functi on’s name w hen you cal l the
functi on.
The string-sorting closure from the Closure Expression Syntax section above can be
wri tten outside of the sort function’s parentheses as a trai l ing closure:
reversed = sort(names) { $0 > $1 }
Trai l ing closures are most useful when the closure i s suffi ciently long that i t i s not
possible to wri te i t inl ine on a single l ine. As an example, Swi ft’s Array type has a map
method whi ch takes a closure expression as i ts single argument. The closure i s cal led
once for each i tem in the array, and returns an al ternative mapped value (possibly of
some other type) for that i tem. The nature of the mapping and the type of the returned
value i s left up to the closure to speci fy.
After applying the provided closure to each array element, the map method returns a new
array containing al l of the new mapped values, in the same order as thei r corresponding
values in the original array.
Here’s how you can use the map method wi th a trai l ing closure to convert an array of Int
values into an array of Stri ng values. The array [16, 58, 510] i s used to create the new array
["OneSi x", "Fi veEi ght", "Fi veOneZero"]:
l et di gi tNames = [
0: "Zero", 1: "One", 2: "T w o", 3: "T hree", 4: "Four",
5: "Fi ve", 6: "Si x", 7: "Seven", 8: "Ei ght", 9: "Ni ne"
]
l et numbers = [16, 58, 510]
The code above creates a di ctionary of mappings between the integer digi ts and Engl i shlanguage versions of thei r names. It al so defines an array of integers, ready to be
converted into strings.
You can now use the numbers array to create an array of Stri ng values, by passing a closure
expression to the array’s map method as a trai l ing closure. Note that the cal l to numbers.map
does not need to include any parentheses after map, because the map method has only
one parameter, and that parameter i s provided as a trai l ing closure:
l et stri ngs = numbers.map {
(var number) -> Stri ng i n
var output = ""
w hi l e number > 0 {
output = di gi tNames[number % 10]! + output
number /= 10
}
return output
}
ri ngs i s i nferred to be of type Stri ng[]
val ue i s ["OneSi x", "Fi veEi ght", "Fi veOneZero"]
The map function cal l s the closure expression once for each i tem in the array. You do not
need to speci fy the type of the closure’s input parameter, number, because the type can be
inferred from the values in the array to be mapped.
In thi s example, the closure’s number parameter i s defined as a variable parameter, as
described in Constant and Variable Parameters, so that the parameter’s value can be
modi fied wi thin the closure body, rather than declaring a new local variable and assigning
the passed number value to i t. The closure expression al so speci fies a return type of Stri ng,
to indi cate the type that wi l l be stored in the mapped output array.
The closure expression bui lds a string cal led output each time i t i s cal led. It cal culates the
last digi t of number by using the remainder operator (number % 10), and uses thi s digi t to
look up an appropriate string in the di gi tNames di ctionary.
N O T E
T he cal l to the di gi tNames di cti onary’s subscri pt i s fol l ow ed by an excl amati on mark (! ), because di cti onary
subscri pts return an opti onal val ue to i ndi cate that the di cti onary l ookup can fai l i f the key does not exi st. In
the exampl e above, i t i s guaranteed that number % 10 w i l l al w ays be a val i d subscri pt key for the di gi tNames
di cti onary, and so an excl amati on mark i s used to force-unw rap the Stri ng val ue stored i n the subscri pt’s
opti onal return val ue.
The string retrieved from the di gi tNames di ctionary i s added to the front of output, effectively
bui lding a string version of the number in reverse. (The expression number % 10 gives a
value of 6 for 16, 8 for 58, and 0 for 510.)
The number variable i s then divided by 10. Because i t i s an integer, i t i s rounded down
during the divi sion, so 16 becomes 1, 58 becomes 5, and 510 becomes 51.
The process i s repeated unti l number /= 10 i s equal to 0, at whi ch point the output string i s
returned by the closure, and i s added to the output array by the map function.
The use of trai l ing closure syntax in the example above neatly encapsulates the closure’s
functional i ty immediately after the function that closure supports, wi thout needing to
wrap the enti re closure wi thin the map function’s outer parentheses.
Capturing Values
A closure can capture constants and variables from the surrounding context in whi ch i t i s
defined. The closure can then refer to and modi fy the values of those constants and
variables from wi thin i ts body, even i f the original scope that defined the constants and
variables no longer exi sts.
The simplest form of a closure in Swi ft i s a nested function, wri tten wi thin the body of
another function. A nested function can capture any of i ts outer function’s arguments and
can al so capture any constants and variables defined wi thin the outer function.
Here’s an example of a function cal led makeIncrementor, whi ch contains a nested function
cal led i ncrementor. The nested i ncrementor function captures two values, runni ngT otal and amount,
from i ts surrounding context. After capturing these values, i ncrementor i s returned by
makeIncrementor as a closure that increments runni ngT otal by amount each time i t i s cal led.
func makeIncrementor(forIncrement amount: Int) -> () -> Int {
var runni ngT otal = 0
func i ncrementor() -> Int {
runni ngT otal += amount
return runni ngT otal
}
return i ncrementor
}
The return type of makeIncrementor i s () -> Int. Thi s means that i t returns a function, rather
than a simple value. The function i t returns has no parameters, and returns an Int value
each time i t i s cal led. To learn how functions can return other functions, see Function
Types as Return Types.
The makeIncrementor function defines an integer variable cal led runni ngT otal , to store the
current running total of the incrementor that wi l l be returned. Thi s variable i s ini tial i zed
wi th a value of 0.
The makeIncrementor function has a single Int parameter wi th an external name of forIncrement,
and a local name of amount. The argument value passed to thi s parameter speci fies how
much runni ngT otal should be incremented by each time the returned incrementor function i s
cal led.
makeIncrementor defines a nested function cal led i ncrementor, whi ch performs the actual
incrementing. Thi s function simply adds amount to runni ngT otal , and returns the resul t.
When considered in i solation, the nested i ncrementor function might seem unusual :
func i ncrementor() -> Int {
runni ngT otal += amount
return runni ngT otal
}
The i ncrementor function doesn’t have any parameters, and yet i t refers to runni ngT otal and
amount from wi thin i ts function body. It does thi s by capturing the exi sting values of
runni ngT otal and amount from i ts surrounding function and using them wi thin i ts own function
body.
Because i t does not modi fy amount, i ncrementor actual ly captures and stores a copy of the
value stored in amount. Thi s value i s stored along wi th the new i ncrementor function.
However, because i t modi fies the runni ngT otal variable each time i t i s cal led, i ncrementor
captures a reference to the current runni ngT otal variable, and not just a copy of i ts ini tial
value. Capturing a reference ensures sure that runni ngT otal does not di sappear when the cal l
to makeIncrementor ends, and ensures that runni ngT otal wi l l continue to be avai lable the next
time that the incrementor function i s cal led.
N O T E
Sw i ft determi nes w hat shoul d be captured by reference and w hat shoul d be copi ed by val ue. Y ou don’t need
to annotate amount or runni ngT otal to say that they can be used w i thi n the nested i ncrementor functi on.
Sw i ft al so handl es al l memory management i nvol ved i n di sposi ng of runni ngT otal w hen i t i s no l onger needed
by the i ncrementor functi on.
Here’s an example of makeIncrementor in action:
l et i ncrementByT en = makeIncrementor(forIncrement: 10)
Thi s example sets a constant cal led i ncrementByT en to refer to an incrementor function that
adds 10 to i ts runni ngT otal variable each time i t i s cal led. Cal l ing the function mul tiple times
shows thi s behavior in action:
i ncrementByT en()
// returns a val ue of 10
i ncrementByT en()
// returns a val ue of 20
i ncrementByT en()
// returns a val ue of 30
If you create another incrementor, i t wi l l have i ts own stored reference to a new,
separate runni ngT otal variable. In the example below, i ncrementBySeven captures a reference to
a new runni ngT otal variable, and thi s variable i s unconnected to the one captured by
i ncrementByT en:
l et i ncrementBySeven = makeIncrementor(forIncrement: 7)
i ncrementBySeven()
// returns a val ue of 7
i ncrementByT en()
// returns a val ue of 40
N O T E
If you assi gn a cl osure to a property of a cl ass i nstance, and the cl osure captures that i nstance by referri ng to
the i nstance or i ts members, you w i l l create a strong reference cycl e betw een the cl osure and the i nstance.
Sw i ft uses capture l i sts to break these strong reference cycl es. For more i nformati on, see Strong Reference
Cycl es for Cl osulosures Are Reference Types
In the example above, i ncrementBySeven and i ncrementByT en are constants, but the closures
these constants refer to are sti l l able to increment the runni ngT otal variables that they have
captured. Thi s i s because functions and closures are reference types.
Whenever you assign a function or a closure to a constant or a variable, you are actual ly
setting that constant or variable to be a reference to the function or closure. In the
example above, i t i s the choi ce of closure that i ncrementByT en refers to that i s constant, and
not the contents of the closure i tsel f.
Thi s al so means that i f you assign a closure to two di fferent constants or variables, both
of those constants or variables wi l l refer to the same closure:
l et al soIncrementByT en = i ncrementByT en
al soIncrementByT en()
// returns a val ue of 50
images/btnupdate
images/p595-1
images/p599-1
images/p599-2
images/remainderfloat_2x
images/remainderinteger_2x
translator
# Translator

업데이트 예정.