Swift The Basics

The Basics

상수와 변수

상수는 한 번 선언하면 변경되지 않는 값, 변수는 계속 변경할 수 있는 값이다. 상수는 let으로 선언하며, 변수는 var로 선언한다. 변수명 뒤에는 콜론을 써서 타입 어노테이션을 붙일 수 있다.

var currentLoginAttempt: Int = 0

var문 하나에서 여러 개의 변수를 초기화 하는 것도 가능하다.

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

튜플을 도입하였으므로 파이썬의 튜플 언패킹과 비슷한 문법도 쓸 수 있다.

var (x, y, z) = (0.0, 0.0, 0.0)

출력

출력은 전역함수인 println을 쓴다. 문자열 내에서 표현식의 값을 합성하는 경우 문자열 내에 \()을 쓸 수 있다. 문자열 포맷팅 출력의 보다 진보한 방식이라 할 수 있다.(..라지만 파이썬의 포맷팅이 더 훌륭한 걸 ㅠㅠ)

주석

C의 주석과 동일한 문법을 쓴다. 단 다중 주석의 경우, 네스팅이 가능하다.

세미콜론

각 줄의 끝에 반드시 세미콜론이 올 필요는 없는데, 한 줄에 여러 명령을 붙여 쓰는 경우 가능은하다. 하지만 가독성을 해치므로 쓰지 말자.

파이썬에서도 동일한 방식으로 세미콜론을 쓸 수는 있다.

정수타입

정수타입의 기본은 Int 형인데 이는 아키텍쳐에 따라서 32비트 시스템에서는 4바이트 정수이며, 64비트 시스템에서는 8바이트 정수이다. 정수타입을 넘어서는 값을 저장할 때 오버플로우를 체크해서 에러를 내 준다.

let tooBig: Int8 = Int8.max + 1 // Error!!!

타입 알리어스

C의 typedef를 연상시킨다.

typealias AudioSample = UInt16

과 같이 특정한 타입에 다른 이름을 줄 수 있다. 이렇게 타입 별칭을 지정하면 원래 타입명 대신에 이 이름을 쓸 수 있다. (타입이 달라지는 것은 아니다. 단지 코드에서 구분지어 사용할 별칭임)

튜플

Objective-C에서는 없던 기능. 배열이 동일 타입의 값을 그룹지을 수 있는 반면, 튜플은 원소의 타입에 구애받지 않고 여러개의 값을 하나의 합성된 값으로 만들 수 있다.

let http404Error = (404, "Not Found")
let (statusCode, statusMessage) = http404Error
println("The status code is \(statusCode)")
println("The status message is \(statusMessage)")

만약 튜플의 값 중 일부가 필요할 때는

let (justTheStatusCode, _) = http404Error

과 같이 _를 써서 다른 값을 무시할 수도 있다.

이 문법 역시 하스켈에서 온 것이 아니던가?

혹은 튜플 자체의 인덱스 번호를 사용하여 값을 구할 수도 있다.

println("The status code is \(http404Error.0)")

심지어 튜플에서는 각 원소에 이름을 붙여 줄 수도 있다. (.문법으로 접근가능)

let http200Status = (statusCode: 200, description: "OK")
println("The status code is \(http200Status.statusCode)")

튜플은 특히 함수가 하나 이상의, 다른 타입의 값을 리턴할 때 특별히 유용하다. (별도의 클래스나 구조체를 만들 필요 없이 쓸 수 있다.) 다만 이는 일시적인 데이터 구조이므로 복잡하고 오랜 시간 동안 보존되어야 하는 데이터들이라면 튜플이 아닌 별도의 클래스나 구조체에 담아두는게 좋다.

선택적타입

문자열은 문자열 내에서 정수값을 추출해주는 toInt() 메소드가 있다. 이 메소드는 정수타입의 값을 리턴할 수도 있고, nil을 리턴할 수도 있다. (이 개념은 하스켈의 Maybe 타입과 비슷한 개념이다.) nil은 정수타입의 값이 아니므로 이 함수는 Int? 타입을 리턴한다고 본다. 이 타입의 변수나 상수는 값이 있으면 그 값이고 없으면 nil이다.

극히 예외적으로 선택적 타입의 경우 if 문의 조건식으로 평가받을 수 있다. (값이 없으면 false, 있으면 true)

선택적 바인딩의 경우, 다음과 같은 구문을 쓰는데… 많이 쓰이는 패턴이 될 수 있으니 참고 하자.

if let actualNumber = possibleNumber.toInt() {
    println("\(possibleNumber) has an integer value of \(actualNumber)")
} else {
    println("\(possibleNumber) could not be converted to an integer")
}

nil

선택적 타입에 대해 값이 없는 상태를 위한 특별한 값 nil이 있다. (내부적으로는 NULL POINTER가 아닐까?) nil은 선택적 타입이 아닌 상수와 변수에는 쓰일 수 없다. 만약 특정한 변수나 상수가 값이 없는 상태를 가져야하는 경우가 필요하다면 해당 타입의 선택적타입을 쓰도록한다.

선택적 타입의 변수를 선언하고 초기화하지 않으면 암시적으로 해당 변수는 nil로 초기화된다.

암시적인 선택적 타입의 형변환

선택적타입(optionals)의 값은 “값이 없는” 상태를 가리킬 수 있다. 이 값의 존재여부는 if문에서 해당 변수/상수를 평가하여 알 수 있고, 그 외에도 값이 있은 경우에 바인딩을 통해서 내부의 값에 접근할 수 있다. 프로그램의 구조상 이러한 선택적 타입이 처음부터 값을 가지도록 하는 것이 명확할 수는 있다. 이런 경우, 값을 체크하는 코드를 모두 제거해도 안전하게 동작하게 된다. (왜냐면 항상 값이 있다는 보장이 있으니까) 이렇게 늘 값이 있다고 보장하는 경우에는 망시적으로 값을 내놓는 선택적 타입을 정의할 수 있다. 이는 물음표 대신에 느낌표(!)를 타입뒤에 사용한다.

암시적인 형변환(즉 선택적 타입이 아닌 일반 타입으로의 형변환)은 초기 선언시에 초기 값을 정의하고 그 이후로도 계속해서 값이 존재한다는 보장이 있을 때 유용하다. 결국 선택적 타입을 일반타입처럼 다루게 되는데, 다음의 예는 일반 선택적 문자열 타입과, 암시적으로 형변환한 문자열 타입의 차이를 보여준다.

let possibleString: String? = "An optional string."
println(possibleString!) // 값에 접근하기 위해서 느낌표를 붙였다. 
// --> "An optional string."

let assumedString: String! = "An implicitly unwrapped optional string."
println(assumedString) // 느낌표가 필요없다. 

간단히 생각하면 선택적 타입의 변수가 자동적으로 내부의 값을 제공할 권한을 부여하는 것이라 생각하면 된다. 물론 느낌표를 붙인 타입은 기본적으로는 선택적타입이 맞으므로 아래와 같은 구문에도 적용이 가능하다. Xcode6 Beta5에서부터는 nil로 참/거짓 판단을 하지 않도록 변경됐다. 명시적으로 nil과 비교해야 한다.

// NOT WORKING
if assumedString {
    println(assumedString)
}
// ==>
if assumedString != nil {
    print(assumedString)
}

assumedString은 항상 값이 있는 문자열이므로 위 조건식은 늘 참이 될 것이다. 또한

if let definiteString = assumedString {
    println(assumedString)
}

과 같이 동일하게 쓸 수도 있따.

Assertion

파이썬에도 이 구문이 있다. 코드만 보자.

let age = -3
assert(age >=0, "A person's age cannot be less than zero.")

이 기능은 특정한 조건을 만족해야만 이후의 코드를 실행하도록 범위를 제한하는데, 반대로 컴파일러 입장에서는 이후의 코드의 assert 구문의 조건을 만족했음을 보장받는다. 따라서 배열의 인덱스가 적절한 범위 내에 있음을 보장한다거나 하는데 사용될 수 있다.