Swifter {Swift Developer}

메뉴

6. 제어문

[vc_row][vc_column][vc_column_text]Swift언어에서는 Objective-C언어에서도 사용하던 제어문을 그대로 사용합니다. 그렇기 떄문에 위화감없이 사용할 수 있지만, 다른 언어에서는 버그가 되기 쉬웠던 중복처리등이 간결한 방법이 제공되기도 하고, 일부 제어문은 보다 안전성과 편리성이 강화된 Swift언어만의 제어문도 있습니다. 그럼 이번 장에서는 각 제어문에 대해서 알아보도록 합시다.[/vc_column_text][vc_separator][vc_custom_heading text=”(1) 조건문” use_theme_fonts=”yes”][vc_column_text]조건문의 제어문은 if, switch, guard라는 3가지가 준비되어 있습니다. if 및 switch문은 다른 프로그래밍 언어에서도 사용하던 구문으로 if문은 진위여부를 판단하기 위해 사용하고 switch문은 조건식에 의한 패턴 매칭을 사용합니다. 그외 guard는 if문을 확장한 개념의 제어문으로 미리 리턴값을 컴파일러에 의해 강제로 사용하는 Swift언어만의 특징이 제공되는 제어문입니다.

If ~ else if ~ else

If문은 조건식에 일치하는지를 판단하고 처리할 것인지를 제어할 때 사용합니다. Swift언어의 if문 구조는 다음과 같습니다.[/vc_column_text][vc_column_text]If 조건식1 {

실행문1

} else if 조건식2 {

실행문2

} else {

실행문3

}[/vc_column_text][vc_column_text]위 if문 구조를 설명해보면 우선 조건식1을 판단하고 조건식1을 충족하면 실행문1을 실행하고 if문 처리를 완료합니다. 만약 조건식1을 충족하지 못하면 조건식2를 평가하고 조건식2가 충족되면 실행문2 처리가 싱행되고 종료됩니다. 그렇지만 이것도 충족하지 못하면 실행문3이 실행됩니다. 이미 많은 프로그래밍 언어에서 사용되고 있는 if문이기 때문에 이 조건문에 대한 로직은 개발을 경험해본 독자라면 쉽게 이해할 수 있다고 생각됩니다.

Else if문은 여러번 사용할 경우 이전 조건이 충족되지 않으면 다음 조건문이 평가됩니다. 어떤 조건에도 부합이 안되는 경우에는 else문을 처리하게 됩니다. 물론 else if와 else구문은 강제적으로 사용하는 것이 아니라 선택사항이고 Swift언어에서는 조건식을 둘러싸는 ( ~ )부분은 생략할 수 있지만 그 다음에 작성하는 { ~ }은 생략할 수 없다는 것을 기억하기 바랍니다.

 

조건식

if문의 조건식은 다음 조건 중 하나를 만족해야 합니다.

  • 논리값(Bool형)
  • BooleanType 프로토콜을 상속받은 형의 객체

조건식은 반드시 논리값으로 리턴해야 하며 암시적인 변환은 절대 안됩니다. 논리값이 아닌 값은 논리값으로 변환되지 않기 때문에 주의해야 합니다.

즉, 비교 연산자를 사용하거나 논리값을 리턴하는 함수를 이용하여 논리값을 리턴하는 조건식으로 사용해야 합니다.[/vc_column_text][vc_column_text]

[code lang=”swift”]

var x: Int = 0
if x != 0 {

}

[/code]

[예제 2-50] 비교연산자를 사용한 조건식

[/vc_column_text][vc_column_text]If문의 조건식에 사용할 수 있는 다른 한가지는 BooleanType 프로토콜을 상속한 객체로 프로토콜은 속성과 메소드등의 정의만을 작성한 구조라고 볼 수 있습니다. 즉 프로토콜을 상속한 형은 프로토콜에 정의되어 있는 속성과 메소드 내용을 구현해야 합니다. 이 부분에 대해서는 나중에 자세히 설명할 예정이기 때문에 이런것이 있다는 것만 알고 넘어가시기 바랍니다.

참고사항

protocol BooleanType {

public var boolValue: Bool { get }

}

BooleanType 프로토콜을 상속한 boolValue 속성을 구현한 것으로 조건식 논리값을 리턴하지 않아도 그 객체 자체로 조건식으로 확인합니다.[/vc_column_text][vc_column_text]

[code lang=”swift”]
class SampleClasss: BooleanType {
var x: Int = 0
var boolValue: Bool {
get {
return x != 0 // SampleClass의 다른속성i가 0이면 false, 1이면 true리턴
}
}
}

var obj = SampleClasss()
obj.x = 1

if (obj) {
print("참")
}

[/code]

[예제 2-51] BooleanType사용[/vc_column_text][vc_column_text]

Switch

Swift언어의 Switch문은 조건을 만족하는데 필요한 형의 다양성이 돋보입니다. Objective-C언어에서는 switch문의 조건문을 판단하는 값은 정수만 대상으로 하였습니다. 그러나, Swift언어에서는 리터럴이나 구조체, 열거형 클래스등을 switch문의 분기에 사용할 수 있습니다.

switch 값 {

case 값1:

실행문1

case 값2:

실행문2

default:

실행문3

}

Switch문의 값은 내부의 case문에서 지정된 값과 비교하여 여러 개의 case문이 있다면 순차적으로 비교하여 값이 값1과 비교하여 일치하면 실행문1이 실행되고 switch문은 종료됩니다. 만약 불일치하면 다음 값2와 비교하는 형태로 처리하고 모든 case문의 값들과 일치한 값이 없으면 default문으로 이동하여 실행문3을 실행하게 됩니다. 그리고 case문의 조건에 “,”(콤마)로 구분하여 여러 개의 조건을 넣을 수도 있고  case문이 실행되면 실행문장 범위는 다음 case문이 나오기 전까지입니다. 그렇기 때문에 다른 프로그래밍 언어를 알고 있는 분들이라면 가끔 실수하는 것이 case문 끝에 break문을 넣는 것인데 Swift언어에서는 생략합니다. 대신 case문 조건에 만족하지 않는 경우가 발생하면 default문이 실행되도록 하였기 때문에 생략할 수 없고 switch문 끝에 꼭 넣어야 합니다. 그리고 명시적으로 switch문을 벗어나도록 설계하고 싶을 경우 break문을 이용하여 처리할 수 있습니다. 만약, 값이 여러 개의 case문과 일치할 경우, 가장 우선 작성되어 있는 조건문이 실행됩니다.[/vc_column_text][vc_column_text]

[code lang=”swift”]
var no = 3

switch no {
case 1, 2, 3:
print("앞번호")
case 3, 4, 5:
print("중간번호")
case 6, 7, 8:
print("끝번호")
default:
print("일치한 값없음")
}

//결과: 앞번호
[/code]

[예제 2-52] 여러개의 case문에 조건이 맞는 경우[/vc_column_text][vc_column_text]

Switch문과 튜플 사용하기

튜플을 사용한 Switch문은 조건분기의 다양성을 만들어 줍니다. 튜플로 조건분기를 한다면, case문의 조건도 튜플에 선언된 여러가지 값에 따라 다양성이 생기게 됩니다.[/vc_column_text][vc_column_text]

[code lang=”swift”]
let person = ("남", 37)

switch person {
case (_, 0..<19):
print("미성년자")
case ("남", 19..<39):
print("성인남성")
case ("남", 39..<60):
print("중년남성")
case ("여", 19..<39):
print("성인여성")
case ("여", 39..<60):
print("중년여성")
default: break
} //결과: 성인남성
[/code]

[예제 2-53] 튜플 사용 예제[/vc_column_text][vc_column_text]튜플 매칭에서는 튜플의 각 요소에 비해 모든 조건이 일치하는 경우에만 실행됩니다. Case문에서 “,”(콤마)로 구분하여 여러개의 조건을 지정하는 것은 OR매칭이고 튜플매칭은 AND매칭으로 이해하면 쉽습니다. 조건지정에 와일드카드가 되는 문자 “_”를 지정해서 해당 튜플 요소가 어떤 조건에도 일치하도록 할 수 있습니다. 이 예제에서는 성별이 남성이고 나이가 20~39세 사이의 범위에 있는 “성인남성”을 출력하는 형태를 보여줍니다.[/vc_column_text][vc_column_text]

[code lang=”swift”]
var value = 9
switch (value % 3, value % 5) {
case (0, 0):
print("FizzBuzz")
case (0, _):
print("Fizz")
case (_, 0):
print("Buzz")
default:
print(value)
} // 결과: Fizz
[/code]

[예제 2-54] 튜플과 Switch문으로 구현한 FizzBuzz문제[/vc_column_text][vc_column_text]FizzBuzz문제는 “주어진 숫자가 3으로 나눌 경우에 Fizz,  5로 나눌 경우에 Buzz, 3과 5 모두로 나누어질 경우 FizzBuzz를 출력하는 로직입니다.  이 예제는 오래전부터 다양한 프로그래밍 언어에서 다양한 해석방법이 존재하지만, Swift언어에서는 switch문과 튜플로 해결할 수 있습니다.

첫번째 case문은 3과 5로 나눌 때 모두 0이 되면 실행되어 FizzBuzz가 출력됩니다. 다음 case문은 3만 나누어져 0일 때 실행되어 Fizz가 출력되고 다음은 5만 나누어져 0일때 실행되어 Buzz가 출력됩니다. 여기서 case문은 여러가지 조건일 경우, 첫번째 case문부터 순차적으로 우선시 되기 때문에 3과 5 모두 나누어져도 Fizz만이 출력되지 않습니다. 그리고 3과 5 모두 나눌 수 없는 경우에는 default로 원래 숫자값을 출력하도록 되어 있습니다.

 

값속박

Case문에서 조건값에 와일드카드 “_”대신에 변수를 선언하여 값이 있는 변수를 통해 실행문의 범위내에서 사용할 수 있는데 이것을 값속박이라고 말합니다.[/vc_column_text][vc_column_text]

[code lang=”swift”]
let pet = ("개", 3)

switch pet {
case ("개", let age):
print("(age)살 강아지")
case let (pettype, age):
print("(pettype) 입니다")
} // 결과: 3살 강아지
[/code]

[예제 2-55] 값속박 예제[/vc_column_text][vc_column_text]첫번째 case문에서 튜플의 두번째 나이값이 case내 변수 age에할당됩니다. 이후 실행문에서 age변수를 사용할 수 있습니다. 다음 case문부터 튜플의 값은 모두 값속박에서 할당됩니다.  이는 실행문에서 pet 변수를 사용하지 않아도 pet변수의 값을 얻을 수 있다는 것입니다.

 

Where

Case문에서 일치한 값만 지정하는 것을 떠나서, where문을 이용하면 보다 복잡한 조건을 지정할 경우에 사용합니다.  예로 수치나 범위에 일치하는 형태는 case문으로 가능하지만, “~이상”과 같은 추가조건이 있을 경우 where문을 사용합니다. Where문은 case문 처음에 값속박을 하고 그 다음 where문으로 처리후 리턴조건문을 지정합니다.[/vc_column_text][vc_column_text]

[code lang=”swift”]
let pet = ("개", 3)

switch pet {
case ("개", let age) where age > 7:
print("(age)살 노견")
case let (pettype, age):
print("(age)살 성견")
default: break
} // 결과: 3살 성견

[/code]

[예제 2-56] where문 예제[/vc_column_text][vc_column_text]

완전성 체크

Swift언어의 switch문에서는 조건에 주어진 조건에 대해서 일어날 수 있는 모든 값에 상관없이 조건을 설명해야 합니다. 이는 모든 case문이 일치하지 않는 경우에 default문이 필요로 합니다.

단, 일어날 수 있는 조건을 모두 포함하는 경우, default문은 생략이 가능합니다.  예로 열거형을 switch문에서 사용한다면 열거형 값의 모든 조건을 case문에 지정하면 default문은 필요가 없어집니다. 열거형에 대해서는 차후에 다시 설명합니다.[/vc_column_text][vc_column_text]

[code lang=”swift”]
enum Jean {
case Straight, Baggy, Bootscut, Skinny
}

// indigo, Blue Black, Deep Blue, Jet, Grey, White

let jean = Jean.Skinny

switch jean {
case .Straight, .Baggy:
print("Indigo")
case .Bootscut, .Skinny:
print("Jet")
}

[/code]

[예제 2-57] 완전성 체크[/vc_column_text][vc_column_text]위 예제에서 조건식 jean은 Jean형을 얻을 수 있고 모든 case문에서 체크하고 있어 default문을 생략할 수 있습니다. Switch문의 조건식이 튜플이 아닌 하나의 값인 경우 default문뿐만 아니라, “case _:”로 변경할 수 있습니다. 이것은 와일드카드가 하나의 값인 경우, case문으로 나머지 범위를 모두 포함합니다.[/vc_column_text][vc_column_text]

[code lang=”swift”]
let number = 3

switch number {
case 1…7:
print("포함")
case _:
print("미포함")
} // 결과: 포함
[/code]

[예제 2-58] case _: 예제[/vc_column_text][vc_column_text]참고로 switch문에서 사용하는 값속박은 guard 및 while, for-in문에서 사용이 가능합니다.

 

Guard

Guard문은 if문을 확장한 조건문입니다. 조건을 지정하고 그 조건을 충족시키지 못한 경우, 그 범위내에서 벗어나도록 강제화하는 경우에 사용합니다.

guard 조건식 else {

실행문

return

}

Guard문은 우선 조건식을 확인하고 결과가 참이면 guard문을 나와 다음 작업을 하는데 알맞습니다. 그러나 결과가 거짓이면 else 문을 실행합니다. 이때 만드시 return문을 입력하여 실행후 나오도록 구성해야 합니다. 이를 작성하지 않으면 컴파일 오류가 발생합니다.

Guard문을 사용시 미리 리턴하는 장점이외에 갑속박된 변수의 범위를 guard문 외부로 내보내는 것이 가능합니다.[/vc_column_text][vc_column_text]

[code lang=”swift”]
func MsgShow(msg: String?) {
guard let m1 = msg else { // msg가 nil이 아니면 m1에 값이 들어감
return // msg가 nil 일때
}
}
[/code]

[예제 2-59] guard예제[/vc_column_text][vc_custom_heading text=”(2) 반복문” use_theme_fonts=”yes”][vc_column_text]Swift언어의 반복문은 다른 프로그래밍 언어에서도 많이 사용하던 구문이 그대로 제공되고 있으며 “for-in”, “for”, “while”, “repeat-while”등이 제공되고 있고 repeat-while문은 do-while문과 기능이 동일합니다.

 

For-in

For-in문은 일반적으로 배열이나 집합, 사전등의 컬렉션 반복을 사용합니다.

 

컬렉션 for-in

배열 집합의 반복문을 알아봅시다. For 다음 배열과 집합에서 가져온 값을 입력한 변수를 놓고 in 다음 배열이나 집합을 지정합니다.[/vc_column_text][vc_column_text]

[code lang=”swift”]
let sido = ["서울시", "경기도", "강원도", "경상도", "전라도", "제주도"]
for si in sido {
print(si)
}

for si in Set(sido) {
print(si)
}

[/code]

[예제 2-60] for-in 예제[/vc_column_text][vc_column_text]For다음 let등의 변수형을 지정할 필요가 없습니다. 값속박등의 유사한 기술이 있지만 여기서 선언된 변수는 강제로 let으로 선언하였기 떄문에 반복해서 값을 넣을 수 없습니다. 반복문에서 변수를 변경하려면 변수명 앞에 var를 명시적으로 선언합니다.

For문 다음 선언한 변수형에 형추론으로 고정되며 sido배열은 String형 배열이기 때문에 si변수는 String형입니다.

반복시 인덱스번호가 필요하다면, enumerate메소드를 사용하여 인덱스 번호 및 요소의 튜플까지 검색할 수 있습니다. 튜플 배열의 경우 for 다음 선언에 튜플의 각 요소에 대한 변수를 지정하여 각각의 값을 할당할 수 있습니다.[/vc_column_text][vc_column_text]

[code lang=”swift”]
let sido = ["서울시", "경기도", "강원도", "경상도", "전라도", "제주도"]

for (index, si) in sido.enumerate() {
print("(index+1): (si)")
}

[/code]

[예제 2-61] enumerate함수 사용 예제[/vc_column_text][vc_column_text]
위 예제는 처음부터 요소(key, value) 튜플로 변경되고 형추론 변수형이 결정됩니다.

[code lang=”swift”]
let bugLegs = ["벌": 6, "나비": 6, "거미": 8]

for (bugName, bugLeg) in bugLegs {
print("(bugName)는 (bugLeg) 다리를 가지고 있습니다")
}

[/code]

[예제 2-62] 사전형 사용 예제[/vc_column_text][vc_column_text]만약, 반복시 key와 value중 하나만 이용하고 싶다면, 두개의 변수를 정의할 수 있고 반복시 사용하지 않는 변수 선언에 와일드카드 “_”를 이용할 수 있습니다.

 

범위지정 for-in

Swift언어에서 범위지정하는 형태는 Objective-C언와는 약간 다릅니다.[/vc_column_text][vc_column_text]

[code lang=”swift”]
for x in 1…20 {
print("(x)")
}

[/code]

[예제 2-63] 범위지정 예제

또한 범위를 역순으로 처리하고 싶은 경우에는 reverse메소드를 사용합니다.

[code lang=”swift”]
for x in (1…20).reverse() {
print("(x)")
}
[/code]

[예제 2-64] 범위지정 역순 예제

For-in문에서 범위를 지정하면 증가를 자동으로 1로 설정됩니다. 만약 좀더 복잡한 단위로 반복시키려면 stride메소드를 사용합니다.

[code lang=”swift”]
for x in 1.0.stride(through: 7.0, by: 0.2) {
print("(x)")
}
[/code]

[예제 2-65] stride 메소드 예제[/vc_column_text][vc_column_text]Stride 메소드로 범위 종료 및 증가를 지정하며 1.0에서 7.0의 범위에서 0.2씩 늘리면서 반복합니다. Through값이 넘어가면 반복은 종료됩니다.

 

For, while, repeat-while

Swift언어의 for-in문은 다양한 반복기능을 제공하지만 for, while, repeat-while문을 r생략할 수 없는 if문과 비슷합니다. 조건식은 불형을 리턴하는 표현식 및 BooleanType프로토콜을 상속하는 객체이어야 합니다.

첫번째로 for문을 살펴보면 실행 전에 초기화를 하고 조건식을 평가하는 구조가 필요할 경우 이용합니다.

for 초기화; 조건식; 증가 {

실행문

}

For문은 초기화한 값을 기준으로 조건식을 만족하면 처리가 실행되면서 증가시킵니다. 그리고 다시 조건식을 확인합니다. 조건식을 만족하지 못할 경우 반복문을 빠져나옵니다.

두번째 While문은 for문보다 간단하고 조건식을 만족하는 동안만 실행문을 반복하며 조건식을 만족하지 못하면 반복문을 빠져나옵니다.

while 조건식 {

실행문

}

세번째, repeat-while문에서는 처음 실행문을 한번을 실행한 후에 조건식을 평가하여 충족하면 실행문이 반복됩니다.

repeat {

실행문

} while 조건식

 

Continue, break

반복문을 사용할 때 continue와 break문을 사용할 수 있습니다.  Continue문은 반복을 중단하고 다시 반복을 실행하고  break문은 반복을 중단하고 해당 반복을 빠져나올 때 사용합니다.

 

[/vc_column_text][vc_column_text]

[code lang=”swift”]
let sido = ["서울시", "경기도", "강원도", "경상도", "전라도", "제주도"]

for (index, si) in sido.enumerate() {
print("(index+1) – (si)")
if index == 3 {
break;
}
} //결과는 경상도까지 출력

[/code]

[예제 2-65] break문 사용 예제[/vc_column_text][vc_column_text]라벨

반복문은 중첩도 가능하기 때문에  중첩된 break 및 continue문 실행은 가장 중싱부 실행문 반복을 위해 사용합니다. 다만, 여러 개의 중첩 반복을 사용하는 경우, 외부에 있는 break 및 continue문을 실행하기 애매한 경우가 발생합니다. 이런 경우를 대비하여 외부에 위치한 break 및 continue문을 실행하기 위해 반복문에 라벨을 지정해서 대상 반복문을 지정할 수 있습니다.

 

라벨명: for 조건식 in {

실행문

break 라벨명

}[/vc_column_text][vc_column_text]

[code lang=”swift”]
lblLoop: for number in 1…7 {
switch number {
case 3:
break lblLoop
default:
print(number)
}
}

[/code]

[예제 2-66] 라벨 사용[/vc_column_text][vc_column_text]예로 switch문에서 조건식에서 반복에서 벗어나게 하기 위해 반복문에 라벨(lblLoop)를 붙이고, switch문의 break에 라벨을 지정한 경우를 보여줍니다.[/vc_column_text][/vc_column][/vc_row][vc_row][vc_column][vc_empty_space height=”40px”][vc_separator][vc_btn title=”목차로 가기” color=”orange” align=”center” link=”url:%2Fswift-2-korean-book%2F|title:%EB%AA%A9%EC%B0%A8|”][/vc_column][/vc_row]

Facebook Comments

카테고리:   Swift Books

댓글

죄송하지만 댓글은 닫혀 있습니다.