[Swift 4.0] The Basics

IOS/Swift 2017. 1. 13. 19:08

Introduction
: 스위프트는 우리에게 이미 익숙한 Int, Double, Float, Bool, String, Array, Set, Dictionary등의 타입을 제공하고, 조금은 생소한 Tuple, optional type이라는 개념을 제공한다.
Tuple은 값들의 grouping 이라는 개념으로 이해하면 된다. 여러개의 값 뭉치를 하나의 타입으로 만들 수 있다는 의미이다.
optional Type은 원어로 "there is a value, and it equals x" or "there isn't a value at all"로 표현한다. 자세한 의미는 나중에 알아보기로 하고, 중요한 점은 스위프트의 powerful한 feature들의 구현 중심에는 optional type이 존재한다는 것이다.
스위프트는 type-safe 언어이다. 이것은 우리가 앱개발 도중에 가능한한 빨리 에러를 발견하고 고칠수 있게 만들어준다.


Constants and Variables
: 말 그대로 Constants는 상수, 한번 값을 set하면 변경할 수 없다. Variable은 값을 set 했더라도 변경할 수 있다.

Declaring Constants and Variables
: 변수는 var, 상수는 let 키워드를 사용해서 선언한다.

let maximumNumberOfLoginAttempts = 10;
var currentLoginAttempt = 0;

Type Annotations
: 변수, 상수의 타입을 명시한다.

var welcomeMessage: String
var red, green, blue: Double

Naming Constants and Variables
: 변수, 상수는 거의 모든 문자를 담을 수 있다.(Unicode 문자들 포함)

Printing Constants and Variables
: 변수, 상수를 Print 할 수 있다.
: print(_: separator: terminator:)
: separator, terminator 파라미터는 default값을 가지고 있다. print() 호출시 생략한다면 terminator는 빈 문자열이 들어가고 terminator에는 line break가 들어간다.

let friendlyWelcome = "Bonjour!"
print("The Current value of friendlyWelcome is \(friendlyWelcome)")


Integers
: 스위프트는 singed, unsigned interger를 8, 16, 32, 64 bit 형태로 제공한다.
: UInt8, UInt16,  UInt32, UInt64, Int8, Int16, Int32, Int64

Int 
: 대부분의 경우에는 Integer의 특정크기를 지정해줄 필요가 없다. 그래서 보통 Int 자료형을 사용한다.
: Int는 32bit 플랫폼에서는 32bit, 64bit 플랫폼에서는 64bit크기를 갖는다.

UInt
: UInt도 Int와 마찬가지로 32bit 플랫폼에서는 32bit, 64bit 플랫폼에서는 64bit크기를 갖는다.

Floating-Point Numbers
- Double : 64비트 실수형 타입
- Float : 32비트 실수형 타입


Type Safety and Type Inference
: 스위프트는 type safe 언어이기 때문에 type check를 컴파일 타입에 실행한다. 그러나 모든 상수, 변수에 타입을 명시할 필요는 없다. 타입을 명시하지 않아도 컴파일러가 타입을 추론하기 때문이다.

let meaningOfLife = 42;
// meaningOfLife상수에 타입을 명시하지 않아도 컴파일러는 Int형 타입으로 추론하여 컴파일 한다.

let pi = 3.14159
// Double형으로 추론
let anotherPi = 3 + 0.14159
// Double형으로 추론, 3에 대한 명시적인 타입선언이 없기때문에 두 변수의 합에 대한 타입은 Double이 더 적절하다.


Numeric Literals

let decimalInteger = 17
let binaryInteger = 0b10001
let octalInteger = 0o21
let hexadecimalInteger = 0x11
// 위 내게 상수 모두 17을 뜻한다.

실수는 십진수, 또는 16진수로 표현할 수 있다. 십진수 실수는 exponent 값을 포함할 수 있으며, 16진수는 exponent값을 포함해야 한다.

십진수 exponent
- 1.25e2 : 1.25 * 10^2 -> 125.0
- 1.25e-2 : 1.25 * 10^-2 -> 0.0125

16진수 exponent
- 0xFp2 : 15 * 2^2 -> 60
- 0xFp-2 : 15 * 2^-2 -> 3.75
- 0xFp0 : 15 * 2^0 -> 15

Numeric literal은 가독성을 높이기 위한 포맷팅이 존재한다.
let paddedDouble = 000123.456
let oneMillion = 1_000_000
let justOverOneMillion = 1_000_000.000_000_1


Numeric Type Conversion
:코드에서 정수를 다룰때 특별한 경우를 제외하고는 Int 타입을 쓰기 바란다. 그 이유는 CPU가 정수 계산을 할 때 피연산자 들을 모두 Int형으로 변환한 후 계산하기 때문이다. 그리고 우리가 명시적인 약속으로 Int형을 Default 정수형 타입이라고 정해놓으면 불필요한 type casting이 줄어들게 될것이다. 

Integer Conversion

let twoThousand: UInt16 = 2000
let one: UInt8  = 1
let twoThousandAndOne = twoThousand + UInt16(one)

SomeType(ofInitialValue)은 SwiftType으로 type casting하는 가장 일반적인 방법이다.

Integer and Floating-Point Conversion
: 정수와 실수간의 type casting은 명시적으로 이루어져야 된다.

let three = 3
let pointOneFourOneFiveNine = 0.14159
let pi = Double(three) + pointOneFourOneFiveNine
// pi = 3.14159

let integerPi = Int(pi)
let minusValue = -3.9
let minusInt = Int(minusValue)
// integerPi = 3
// minusInt = -3


Type Aliases

typealias AudioSample = Uint16
var maxAmplitudeFound = AudioSample.min


Booleans

C의 Bool과 달리 0이 아닌값으로 Booleans 값을 대체할 수 없다.

let i = 1

if (i)
{


// 컴파일 에러 발생.


Tuples
: Tuple은 여러개의 값을 grouping한 자료형이다.
: 두개의 자료형이 같을 필요없다.

let http404Error = (404, "Not Found")
let (statusCode, statusMessage) = http404Error

print("The status code is \(statusCode)")
print(The status message is \(statusMessage)")
// Prints "The status code is 404"
// Prints "The status message is Not Found"

let (justTheStatusCode, _) = http404Error
print("The status code is \(justTheStatusCode)")
// Prints "The status code is 404"

print("The status code is \(http404Error.0)")
//Prints "The status code is 404"
print("The status message is \(http404Error.1)")
//Prints "The status message is Not Found"

let http200Status = (statusCode: 200, description: "OK")
print("The status code is \(http200Status.statusCode)")
print("The status message is \(http200Status.description)")
// Prints "The status code is 200"
// Prints "The status message is OK"


Optionals
: Optional은 상수, 변수의 상태라고 보면 된다. 두가지 상태 중 하나에 속해있는것인데, 하나는 값을 가지고 있고 그것은 unwrap할 수 있는 상태이고, 나머지 하나는 값이 없는상태이다.

: Optional은 C, C++에는 존재하지 않는 개념이다. 그나마 가까운 개념은 Objective-C의 nil이다. nil의 의미는 object의 invalid한 상태를 뜻한다. 그러나 nil은 object에만 적용되는 개념이다. Objective-C는 structure, basic C type, enum 타입 등이 invalid한 상태이면 NSNotFound 같은 special value를 return 한다. 이를 제대로 처리하기 위해서는 method 호출자가 NSNotFound와 같은 special value에 대해 대응이 가능한 상태여야 한다. 하지만 스위프트에서는 걱정할 필요 없다. Optional은 object뿐 아니라 다른 타입들 모두에게 적용되는 개념이기 때문이다.

let possibleNumber = "123"
let convertedNumber = Int(possibleNumber)

Int(String) 생성자에 넘겨지는 문자열이 "abc"였다면 Int형 타입으로 올바르게 변환이 되지 않을 것이다. 그래서 Int(String)은 항상 optional Int(Int?)를 반환한다. 이것이 뜻하는 바는 올바른 Int값이 들어있을 수도 있고, valid한 값을 안가지고 있을수도 있다는 것이다.

nil
: optional type 변수에 값이 없는상태를 표현하기 위해서 nil을 대입할 수 있다.
: optional type 변수 선언시 initial value를 대입하지 않으면 자동으로 nil이 대입된다.

* Objective-C의 nil과 스위프트의 nil은 다르다. Objective-C의 nil은 객체의 포인터 타입으로 포인터가 아무것도 가리키는 것이 없는 상태를 나타내는 것이고, 스위프트의 nil은 포인터 타입이 아니고 모든 객체에 적용되는 개념으로, 해당 변수가 값을 가지고 있지 않은 상태를 나타내는 것이다.

If Statements and Forced Unwrapping
: 스위프트에서는 If문을 optional type 변수가 nil인지 valid값을 가지고 있는지 판별하는 용도로 사용할 수 있다.

if convertedNumber != nil {
    print("convertedNumber contains some integer value")
}

위 if문 안으로 들어갔다는 것은 optional type 변수 convertedNumber가 valid한 값을 가지고 있다는 것이므로 해당 변수뒤에 "!"을 붙여서 optional이라는 껍질을 벗겨냄으로서 정상적으로 해당 변수를 사용할 수 있게 만든다. 이를 unwrap이라고 한다.

if convertedNumber != nil {
    print("convertedNumber has an integer value of \(convertedNumber!).")
}

* 사실 "!"을 사용하여 unwrap하는 것은 사용하지 않는것이 좋다. optional type이 nil인 상태에서 "!"으로 unwrap을 시도하려고 하면 runtime error가 발생한다. "!"을 사용해서 unwrap 한다는 것은 optional type 변수가 valid한 값을 가지고 있을거라고 확신한다는 것인데, 프로그래밍에 있어서 100프로 확신하는 것은 굉장히 위험한 발상이다.

Optional Binding
: Optional Biding이란, "!"으로 optional type 변수를 강제 unwrap 하지 않고 안전하게 optional type변수를 unwrap 하기위한 기법이다. 
: if, while 구문을 사용하여 Optional Binding할 수 있다.

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

possibleNumber가 올바르게 type casting이 된다면 Int(String)이 return 하는 Int?을 unwrapping하여 actualNumber 상수의 값을 대입한 후 if문에 진입하고, 그렇지 않으면 else문을 실행하게 된다.

단일 if문 안에 복수개의 optional binding과 Boolean condition 체크를 할 수 있다. 복수개의 optional binding들 중 어느 하나라도 nil을 가지고 있거나 Boolean condition이 어느 하나라도 false일 경우에는 if statement는 false가 된다. 

if let firstNumber = Int("4"), let secondNumber = Int("42"), firstNumber < secondNumber && secondNumber < 100 {
    print("\(firstNumber) < \(secondNumber) < 100")
}
// if문의 모든 조건을 만족하므로 if문에 진입.


Error Handling
: 다른 언어의 try, catch문을 통한 Error handling이랑 크게 다를바가 없다.
: error가 발생되면 현재 error가 발생한 scope 한단계 밖으로 error가 전파되고 handling 메서드를 찾지 못하면 계속 한단계 밖 scope로 전파된다. Top scope까지 전파되었는데 handling 메서드를 찾지 못하면 runtime error가 발생한다. 

func makeASandwich() throws {
    //....
}

do {
    try makeASandwich()
    eatASandwich()
} catch SandwichError.outOfCleanDishes {
    washDishes()
} catch SandwichError.missingIngredients(let ingredients) {
    buyGroceries(ingredients)
}

makeASandwich() 실행도중 SandwichError.outOfCleanDishes 에러가 발생하면 washDishes()를 실행시키고 SandwichError.missingIngredients 에러가 발생하면 buyGroceries(let ingredients)를 실행시킨다.


Assertions and Preconditions
: 코드 실행 중 특정 조건이 만족 안되면 더 이상 코드 실행을 할 수 없을 때가 있다. 이는 8~90프로 버그 상황인데 이 버그상황을 디버그 환경에서 조금 더 효율적으로 체크할 수 있는 방법이 있다. 
첫번째는 Assertions이고 두번째는 Preconditions이다. 사용방법은 비슷하고 해당 조건을 만족하지 못했을 경우 앱이 종료된다. 다만, 차이점이 하나 있다. Assertions은 debug 빌드일 경우에만 동작하고, precondition은 debug, production 빌드 둘다 동작한다.

* Assertions, precondition 모두 optimization 레벨 None 으로compile되면 작동되지 않는다.(이 Option은 app target이 Release configuration이면 자동으로 YES 세팅된다.) 다만, fatalError(_:file:line:)의 경우는 optimization 레벨의 상관없이 항상 동작한다.


Debugging with Assertions

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

위 코드가 debug 환경에서 실행중이라면 assert문에서 assert 에러 메시지가 출력되고 앱을 종료될 것이다. 에러 메시지는 생략할 수 있다. 

if age > 10 {
    print("You can ride the roller-coaster or the ferris wheel.")
} else if age > 0 {
    print("You can ride the ferris wheel.")
} else {
    assertionFailure("A person's age can't be less than zero.")
}

이 처럼 실패의 경우만 체크하기 위해  'assertionFailure'를 사용할 수 있다.

Enforcing Preconditions

// In the implementation of a subscript...
precondition(index > 0, "Index must be greater than zero.")

위 코드는 subscript 안에서의 사용예를 보인것이다. index가 0보다 작거나 같으면 앱이 종료될 것이다.


'IOS > Swift' 카테고리의 다른 글

[Swift 4.0] Functions  (0) 2017.04.01
[Swift 4.0] Control Flow  (0) 2017.04.01
[Swift 4.0] Collection Types  (0) 2017.02.03
[Swift 4.0] Strings and Characters  (0) 2017.01.22
[Swift 4.0] Basic Operators  (0) 2017.01.16
Posted by 홍성곤
,