momodudu.zip
#1 Swift 기본 문법 - Basics : constant, variables, Optionals 본문
평생 팔자에도 없던 swift 공부를 시작하게 되었는데...
c++ 개발만 8년차라 쉽게 터득하기가 어려워서, Apple Swift docs를 보면서 끄적이면서 공부 겸 정리하는 포스팅.
이제 다시 꾸준히 공부를 시작해야한다.
그냥 공부하면서 내가 모르겠는 부분만 개략적으로 적는거라, 정보성이나 전문성은 조금 떨어질수도 있다.
특히나 이 글은 기초적인 부분을 훑은거라서 자세한 설명보다는 그냥 훑는다는 느낌...
1. Constant and variables
constant는 말 그대로 상수, variable은 말 그대로 변수이다. 상수는 keyword let으로 선언하고 변수는 var로 선언한다.
Type 정의는 선언한 변수 및 상수 뒤에 명시적으로 적어놓을 수도 있고, 굳이 명시해놓지 않아도 초기값을 보고 컴파일러가 타입 추론을 해준다. 그래도 가독성을 위해서는 명시적으로 적어놓는게 좋을 것 같다.
var message:String = "hello world"
var message = "hello world"
hello world는 진심으로 8년만에 적어보는것 같다 (....)
2. Types
변수 및 상수로 선언 가능한 type은 기본적으로 c++과 비슷하다. Int, Float, Double, Bool, Character 등등 .. String도 제공한다.
몇가지 예제를 다뤄보면서 느낀건데, Java를 제대로 배워보지 않고 c/c++만 써본 나로서는 swift를 공부하면서 string을 쓰면서 나는 참 불편하게 살고 있었구나를 느꼈다(...)
그외에 추가적으로 tuple type도 제공한다. 여러개의 compound value set으록 구성할 수 있는 타입인데
예를들면 (Int, String) 형태의 tuple type을 정의할 수 있다. 그 외에도 ( Int, Int, Int ) 등 뭐 여러가지가 가능한듯 하다.
흥미로운점은 이 tuple 자체를 type으로 정의할 수 있다.
예를 들어, 어떤 item의 숫자와 이름을 같이 저장하고 싶다고 가정하면 tuple type은 (Int, String)이 될것이다.
이 (Int, String)의 tuple type자체는 함수의 파라미터나 리턴값처럼 실제 하나의 타입으로서 동작한다.
그래서 아래와 같은 assign 도 가능하다.
// tuple of (errorCode: Int, errorMessage: String)
let (statusCode, statusMessage) = (404, "Not Found")
3. Optional
사실 Swift 공부를 시작한지 지금 4일정도가 되었는데 제일 생소하고 어려웠던 개념이 이 Optional이다.
실제로 처음 swift를 시작하면 헷갈리는 부분이라고 한다. 요건 좀 중요한 부분이니 장황하게 Swift Language guide 예제를 들어가면서 설명해볼까 한다.
가이드에 따르면 Optional이란, 어떤 한 변수에 값이 있는지 없는지를 확인하기 위해 사용하는 일종의 "타입"이다.
즉, Optional을 사용하게 되면 두 가지 경우가 있을 수 있다. 값이 존재한다면 나는 이 Optional을 언래핑, 즉 풀어서 이 값을 사용할 수 있고, 값이 아예 존재하지 않을 수도 있다.
사실 처음 보면 잘 와닿지 않는데, 예제 몇개를 보면 이해할 수 있다.
Optional keyword는 ? 물음표를 사용한다.
var message:String = "hello world"
var message2:String? = "hello world"
var message3:String?
위 예시의 두번째 세번째 라인처럼 특정 타입(이는 swift에 정의된 Int, Double같은 primitive도 해당되고 사용자가 정의한 class도 가능하다) 키워드 뒤에 물음표를 붙이면, 이는 String의 Optional type이 된다.
String과 String?은 분명히 다른 타입이며, String? 자체도 하나의 타입으로서 동작한다!!
위 세가지 메세지가 담긴 변수를 print를 해보면 아래와 같은 결과물을 얻는다.
첫번째는 예상한대로 hello world가 출력되었고, 두번째줄은 hello world 값을 Optional이 감싼채로 출력되었다.
말 그대로 Optional은 String "hello world"를 감싸고 있는 type 이라고 정의할 수 있다. 이 자체가 하나의 타입인것이다.
만약 세번째줄 message3 변수 처럼, Optional로 선언이 되긴 했으나 아무런 값도 할당받지 않은 상태라면 nil, 즉 아무 값도 없는 상태를 출력한다.
처음 이 개념을 봤을때는 C++의 pointer를 떠올렸다. Pointer랑 비슷한거 같은데?
그렇지만 조금 공부해보니까 pointer와 optional은 완전히 별개이다. pointer는 일종의 어떤 할당된 값의 alias, 즉 별명이라고 볼 수 있지만
optional은 어떤 값을 감싸고 있는 기능이라고 보면 된다. 즉, Optional이 Message3처럼 nil을 리턴하게 되면 message3에는 "아무것도 없다(=absence)"를 의미하는 것이다.
예제를 하나 더 살펴보자.
let myNumber = "123"
let convertedNumber = Int(myNumber)
let myStr = "hello world"
let convertedNumber = Int(myStr)
첫번째 두번째 라인은 코드에서 유추할 수 있듯이 int로 된 string을 진짜 int type으로 캐스팅하는 구문이다. atoi같은 느낌...
Swift에서 이와 같은 type casting 함수를 지원해준다.
Int(_ :String)으로 정의되며, 이에 대한 리턴값은 "Int" 가 아닌 "Int?" 타입이다.
위에서 말했지만 비슷해보여도, ?이 있는지 아닌지에 따라 동작은 천차만별이다.
즉 convertedNumber는 :Int가 아닌 :Int?로 타입 추론이 된다. 진짜인지 출력해보면 알 수 있다.
let myNumber:String = "123"
let convertedNumber = Int(myNumber)
print(convertedNumber)
위 예시 코드처럼 작성하고, 이를 print하면
숫자 백이십삼을 감싸는 Optional로 출력된다. 밑에서 언급하겠지만, 이는 Int가 아닌 Int?이므로 Int처럼 사용하려면, 별도의 조치를 취해줘야 한다.
let myNumber = "123"
let convertedNumber = Int(myNumber)
let myStr = "hello world"
let convertedNumber = Int(myStr)
그렇다면, 위 예시에서 밑에 예제는 어떨까?
실제 숫자가 아닌 문자열을 Int로 캐스팅 해보려고 한다. 사실 c나 c++같으면 아스키 코드가 출력될거같은 냄새가 나지만ㅋㅋㅋ
let myNumber:String = "hello world"
let convertedNumber = Int(myNumber)
print(convertedNumber)
이렇게 123 대신 진짜 문자열을 넣어봤다.
놀랍게도 nil이 나온다. Int("hello world")를 수행하는 과정에서, hello world는 숫자가 아니므로 타입캐스팅에 실패하고,
어떤 숫자가 담긴 optional을 리턴하지 않고, 즉 아무것도 없는 빈 상태의 optional = nil을 리턴한다.
즉, convertedNumber: Int?는 Int값을 담을 수 있는 상자긴 한데, 어떠한 값도 담겨있지 않다는 것을 의미한다.
처음에 이 예제를 보고 이해하면서 진짜 나는 원시적으로 살았구나... c++도 좋은 언어고 굉장히 매력적이지만 java조차도 제대로 다뤄보지 않은 나한테는 진짜 충격적이었다.. 또 나만 몰랐지... 나빼고 다 편하게 코딩했지...
이제 이쯤 왔으면 Optional의 정의가 뭔지에 대해서는 감이 온다.
그럼 아까 위에서 언급했듯이,
let myNumber:String = "123"
let convertedNumber = Int(myNumber)
print(convertedNumber)
이 optional로 wrapping해버린 숫자 123을 어떻게 쓸 수 있는지에 대해 알아본다.
1) Forced Unwrapping
기본적으로 forced unwrapping이다. 이름에서 알 수 있듯이, 위에서처럼 123을 wrapping하고 있는 껍데기를 억지로 벗겨내는거라고 보면된다. 사용은 변수에 느낌표(!)를 붙이면 된다.
let myNumber:String = "123"
let convertedNumber = Int(myNumber)
print(convertedNumber)
print(convertedNumber!)
convertedNumber에 붙는 !의 의미는, convertedNumber가 있든 없든, 무조건 이 껍데기를 벗겨서 값을 꺼내겠다는 의미다.
설명에서도 알수있듯이 다소 위험부담이 있다. 위 케이스에서는 123이 붙어있는 옵셔널이었기때문에 그 껍데기를 벗겼을 때 123이 제대로 나왔지만,
아까 위에서 설명한 Optional이지만 nil이라면 ? 이는 컴파일 에러도 나지 않은채로 nil에 !를 써서 접근하게 되면 runtime error가 발생한다.
pointer와는 완전 다르다고 했지만, null pointer access랑 비슷한 느낌이라 보면 되겠다.
그래서 이 Forced unwrapping을 쓰고자 한다면, "반드시 value가 있다"고 개런티가 되는 값에만 사용해야 한다.
이런 위험 부담을 줄이고자 개발자 친화적인 swift는 좀 더 안전한 방법을 제공하는데, 그게 바로 Optional binding이라는 기능이다.
2) Optional Binding
이름은 어려워 보이지만 별거 없다. Optional type에 대해서 껍데기를 벗길건데, 껍데기를 벗겨서 아무것도 없으면 fallback 루틴으로 빠지고, 뭐가 있다면 그걸 사용하도록 하는 control flow다.
var myNumber:String = "123"
var convertedNumber = Int(myNumber)
if let number = convertedNumber{
/// Do somthing using number
print(number)
}else {
print("Nothing to do")
}
차근차근 해석해보면, if 구문 안에 let number = convertedNumber 라는 조건문이 걸려있는데, 이는 optional convertedNumber의 껍데기를 벗겨서 어떤 값이 있다면 그 값을 number에 넣고 true를 리턴하겠다. 라는 의미이다.
즉, 우리는 string "123"을 Optional(123) :Int?로 컨버팅을 했고, 이 123을 쓰려면 Optional 껍데기를 벗겨서 number에 저장을 하겠다. 라는 말이다.
그래서 123이라는 "Value"가 number에 저장이 되었고 우리는 이 값을 print하는 statement로 빠진다.
만약 myNumber가 아까처럼 nil을 리턴한 스트링이라면 어떨까?
var myNumber:String = "hello world"
var convertedNumber = Int(myNumber)
if let number = convertedNumber{
/// Do somthing using number
print(number)
}else {
print("Nothing to do")
}
hello world string을 Int?로 컨버팅 하려고 했지만 실패해서 nil이 assign되었고, 이 껍데기는 벗겨봤자 아무것도 없으니
else fallback statement로 빠지게 되는 것이다.
이처럼 if 조건문을 써서 안전하게 Optional 껍데기 내부 값을 가져다 쓰는게 바로 optional binding이다.
'ios > Swift' 카테고리의 다른 글
#6 Swift - Extension (0) | 2019.11.28 |
---|---|
#5 Swift - Optional chaining (0) | 2019.11.27 |
#4 Swift - Initialization (0) | 2019.11.26 |
#3 Swift - Properties (0) | 2019.11.26 |
#2 Swift - Functions and Closures (0) | 2019.11.25 |