이제 12일에 걸쳐서 기본기를 빠르게 공부해 봤습니다.
이제 3일 동안은 천천히, 좀 더 자세하게 복습해 보는 시간입니다
봤던 내용을 다시 보는 건 좀 지루할 수도 있지만
반복학습해야 더 유용하겠죠?
힘내봅시다!
모든 프로그램에는 데이터를 저장할 필요가 있어요
스위프트에서는 변수와 상수라는 두 가지 방법을 제시합니다.
변수는 저장된 값이 언제든 변경될 수 있고, 상수는 한번 값이 정해지면 바꿀 수 없습니다.
근데 이렇게 생각할 수도 있죠. 변수로 만든다음에 값을 변경하지 않으면 상수는 필요없는거 아니야? 라고요
변수와 상수로 나누어놓은 것의 장점 중 하나는 우리가 만약 실수를 한다면 Xcode에서 알려준다는 점입니다. "데이터를 상수로 만들고 절대 바꾸지 않을거야"라고 생각하고 코드를 작성했다고 가정해볼게요
나중에 10~20줄 뒤에서 값을 변경하려고 하면 Xcode는 앱 빌딩하기를 거부할거에요
또한 상수는 Xcode가 앱 빌딩하는 방식을 정하는데도 중요합니다.
Xcode가 특정 값이 변하지 않는다는걸 알면 최적화를 적용해서 코드가 더 빨리 작동하게 해줘요
스위프트에서 var
키워드로 변수를 만듭니다
var name = "Tim McGraw"
변수이기 때문에 언제나 원할때 값을 변경할 수 있어요.
하지만 var
키워드를 매번 쓸 필요는 없어요
처음 선언할 때만 작성하면됩니다
var name = "Time MacGraw"
name = "Romeo"
첫 번째 줄은 name
변수를 만들고 값을 할당해줍니다
두 번째 줄은 변수에 "Romeo"라는 값을 업데이트 해주구요
플레이그라운드에서 값의 변화를 확인해 볼 수 있습니다.
저 코드에서 변수가 아니라 상수를 쓰면 어떨까요?
일단 상수는 let
키워드를 사용해서 작성합니다
let name = "Tim MacGraw"
name = "Romeo"
여기서 문제가 생깁니다. Xcode가 에러를 표시할 건데요, 잘못된 부분에 빨간색 밑줄을 그어줄겁니다.
그리고 메시지를 띄어줄텐데요 name
이 상수이기 때문에 값을 할당할 수 없다고 알려줍니다
상수는 나 자신에게도 스위프트에게도 값이 변하지 않는다고 약속해주는 겁니다
그래서 Xcode는 상수를 변경하려면 거절하는거죠
스위프트를 사용하는 개발자들은 가능하다면 상수를 쓰도록 해야합니다
그래야 코드가 읽고 이해하기 쉽기 때문이죠
실제로도 Xcode는 변하지 않는 변수를 사용한다면 경고를 줍니다.
중요 포인트!
변수랑 상수의 이름은 유일해야합니다.
만약 같은 이름을 쓴다면 에러가 나게 됩니다.
여러 가지 데이터 타입이 존재하고 스위프트는 이들을 개별적으로 다룹니다.
이미 앞에서 중요한 타입 중 한 가지를 접했죠 바로 String
입니다.
문자열은 길어질수도 짧을수도 심지어 그냥 비어있을수도 있습니다.
모습에 관계없이 스위프트에서는 모두 문자열입니다
name
을 문자열타입으로 작성했기 때문에 스위프트는 이 변수가 문자열이어야 함을 인지하고 있습니다.
근데 아래와 같이 작성하면 코드가 제대로 동작하지 않을겁니다
var name
name = "Tim MacGraw"
이 상황에서 두가지 옵션이 있는데요
변수를 생성하고 동시에 값을 할당하던지 아니면 타입작성을 사용하는것입니다.
타입 추론을 사용하면 당장 값을 할당하지 않고 나중에 데이터타입을 알려주게 합니다.
첫 번째 옵션같은 경우는 이미 앞에서 사용했봤으니 두번째를 보죠.
우리는 name
이 문자열 타입이 될걸 알고 있습니다.
그래서 :String
을 붙여서 스위프트에 이를 알려주죠
var name: String
name = "Time MacGraw"
참고로 :
앞뒤로 여백을 넣는 경우가 있는데 var name : String
처럼요. 잘못된 방법이니 사용하지 않도록 해야합니다
이제 정상적으로 할당이 되네요
여기서 알아가야할 점은 스위프트가 변수나 상수가 사용하는 데이터타입을 항상 알고싶어한다는 점입니다.
피할 수 없는 귀찮은 일이라고 생각될 수도 있지만 덕분에 타입에 대한 안정성을 확보하게 됩니다.
아래의 예시를 통해 확인해 볼건데요 이번엔 Int
라는 새로운 데이터타입으로 해볼겁니다. 숫자를 저장해주는 데이터 타입이죠
var name: String
name = "Tim MacGraw"
var age: Int
age = 25
String
과 Int
의 첫글자가 대문자로 시작하죠? 스위프트 표준 컨벤션이기 때문에 저대로 사용하셔야합니다.
코딩 컨벤션은 스위프트에 영향을 끼치지는 않지만 개발자들에게는 영향이 있습니다. 그러니까 잘 지켜서 해야겠죠?
데이터 타입은 대문자로 시작, 상수와 변수는 상관없습니다.
이제 타입 세이프티가 작동하기 때문에
name = 25
age = "Tim MacGraw"
이렇게 작성하면 타입때문에 에러가 뜹니다
위 코드에서 String
에 Int
를, Int
에 String
을 넣으려고 했기 때문에 스위프트에서 에러를 보냅니다.
2가지 타입을 더 살펴보죠. Float
와 Double
입니다.
이 타입은 스위프트에서 실수나 소수를 저장하기 위한 타입들입니다.
두가지 타입이 있는 이유는 정확도에 따라 사용하는게 다르기 때문입니다
하지만 보통의 경우 그게 큰 영향이 있지는 않기 때문에
애플의 공식 추천에 따라서 Double
을 사용하는걸 권장합니다
var latitude: Double
latitude = 36.166667
var longitude: Float
longitude = -86.783333
이 코드를 실제로 실행해보면 longitude는 "-86.78333"을 출력할겁니다.
실제값 보다'3'이 하나가 없죠? 이게 정확성? 범위에 대한 예시입니다.
Float
랑 Double
이 어떻게 다른지 더 확인해보고 싶다면
아래의 예시를 플레이 그라운드에 실행시켜보길 바랍니다
var longitude: Float
longitude = -86.783333
longitude = -186.783333
longitude = -1286.783333
longitude = -12386.783333
longitude = -123486.783333
longitude = -1234586.783333
실제로 확인해보면 표현해주는 자리값의 차이가 보입니다.
이제 Double
로 바꿔서 확인해볼까요?
Double
은 모든 자리수를 표현해주는게 확인됩니다.
Double
은 Float
보다 2배 더 범위가 길기 때문에 숫자를 자를 필요없이 표현합니다.
스위프트는 참과 거짓값을 저장하는 데이터 타입도 존재합니다.
Bool
이라고 하는데요 Boolean
의 줄임말입니다.
Bool
은 "아마도", "혹시나"같은 애매한 값을 취하지 않아요
오로지 참 또는 거짓 입니다.
var stayOutTooLate: Bool
stayOutTooLate = true
var nothingInBrain: Bool
nothingInBrain = true
var missABeat: Bool
missABeat = false
위에서 배웠듯이 데이터의 타입을 정하는데 2가지 방법이 있죠
선언함과 동시에 값을 선언해주는것과 타입작성을 이용하는 방법이 있습니다.
한가지를 선택해야 한다면 첫 번째를 권장합니다
그 방식이 훨씬 명확하거든요
var name = "Tim McGraw"
가 아랫것보다 선호됩니다
var name: String
name = "Tim McGraw"
그리고 모든 데이터 타입에 적용되지요
var age = 25
var longitude = -86.783333
var nothingInBrain = true
이 방법을 타입추론(type inference)라고 합니다.
스위프트는 변수에 사용되는 데이터에 따라 타입을 추론할 수 있기 때문에 사용할 수 있는 방법이지요
예를 들어 "-86.783333"같은 값은 Double
이나 Float
에 해당하겠죠
그리고 언급햇듯이 애플에서는 Double
을 권장하기 때문에 스위프트도 위 변수의 타입으로 Double
을 할당해줍니다.
완벽하게 선언하기를 바란다면 값을 선언하면서 동시에 데이터 타입명도 명시해주면 되겠죠
var name: String = "Tim McGraw"
연산자들은 처음 수학시간에 배우는 문자들과 같아요
+
나 -
같은 기호죠. 이 기호들은 스위프트에서도 존재하고 우리가 알고 있는 방식과 똑같이 작동해요
var a = 10
a = a + 1
a = a - 1
a = a * a
이번에는 아래를 시도해볼까요?
var b = 10
b += 10
b -= 10
+=
도 연산자인데요 "더한다음에 할당해라"라는 의미입니다.
좀 더 자세히 풀어보면 "b의 최근 값에 10을 더하고 그 결과를 다시 b에 할당해라" 라는 뜻이죠
-=
는 무슨 동작을 할지 상상이 되죠? 위와 똑같지만 더하기 대신 빼기를 합니다
연산자들은 Int
말고 다른 타입들에도 사용이 가능한데요 Double
에도 사용이 가능합니다
var a = 1.1
var b = 2.2
var c = a + b
그리고 String
에서는 +
을 사용하면 문자열끼리 합칩니다.
var name1 = "Tim McGraw"
var name2 = "Romeo"
var both = name1 + " and " + name2
또 한가지 볼 수 있는 보통 연산자는 나머지연산자입니다
%
기호로 사용할 수 있죠. 숫자를 나눈다음에 남은 나머지 숫자를 반환해줍니다
9 % 3
은 0을 반환하겠죠? 딱 나누어 떨어지니까
반면에 10 % 3
은 1을 반환할겁니다 3번나누고 1이 남으니까요
스위프트는 비교를 해주는 연산자도 있습니다.
아래처럼 진행되죠
var a = 1.1
var b = 2.2
var c = a + b
c > 3
c >= 3
c > 4
c < 4
위의 예시에서 크다(>), 크거나같다(>=), 작다(<) 등의 비교가 가능한것을 알 수 있습니다.
그리고 참(true)이나 거짓(false)으로 결과값을 반환해줍니다.
만약 값의 같음을 비교하고 싶다면 ==
을 사용하면 됩니다.
왜냐면 =
은 이미 값을 할당하는데 사용되고 있기 때문이죠
var name = "Tim McGraw"
name == "Tim McGraw"
참고로 스위프트는 대소문자를 구별하기 때문에 "Tim McGraw", "TIM MCGRAW", "TiM mCgRaW"을 비교하면 서로 다른 값임을 알 수 있습니다.
한가지 연산자가 더 있는데요 바로 !
연산자 입니다.
이 연산자는 반대값을 나타내는 연산자입니다.
참이라면 거짓을 나타내게 되겠죠?
var stayOutTooLate = true
stayOutTooLate
!stayOutTooLate
!
은 =
와도 같이 사용할 수 있습니다. !=
이렇게요
"같지 않다" 라는 의미를 가지게 됩니다.
멋있는 말처럼 보이죠? 근데 사실 굉장히 간단한 겁니다
변수나 상수를 문자열에 넣어주는 기능입니다.
var name = "Tim McGraw"
우리가 출력하는 메시지에 이름을 넣고 싶으면 \(이름)
형식으로만 써주면 됩니다. 간단하죠?
var name = "Tim McGraw"
"Your name is \(name)"
string interpolation을 통해 통합되었기 때문에 결과창에는 하나의 문자열만 출력되는걸 볼 수 있습니다.
저 방식을 +
연산자를 통해서도 구현할 수 있죠
var name = "Tim McGraw"
"Your name is " + name
하지만 이 방식은 효율적이지 않아요 특히 여러개의 변수들을 통합해야하는 경우에요
반면 string interpolation은 여러개의 데이터 타입들을 한번에 다룰 수 있습니다
var name = "Tim McGraw"
var age = 25
var latitude = 36.166667
"Your name is \(name), your age is \(age), and your latitude is \(latitude)"
+
연산자를 통해 구현하려면 무척 어려울 겁니다. 왜냐하면 Int
와 Double
을 String
으로 합하는걸 허락하지 않거든요
아 그리고 강력한 기능 하나가 있는데요 스위프트 표현식도 적용할 수 있답니다
예를 들어 사칙연산 수행하는 부분을 넣어보죠
\(age * 2)
부분의 연산이 정상적으로 진행됐죠?
배열은 하나의 집합아래 여러 값들을 모아주죠.
스위프트는 타입 추론을 통해 배열이 가지고 있는 값의 데이터를 유추해냅니다
var evenNumbers = [2, 4, 6, 8]
var songs = ["Shake it Off", "You Belong with Me", "Back to December"]
보시다시피 스위프트는 [
를 써서 배열의 시작과 끝을 나타냅니다. 내부의 요소들은 ,
로 구분되구요
배열 요소를 읽어들이기 위해 인덱스를 사용할 때는 첫번째 요소부터 0
으로 시작합니다 예시를 볼까요?
var songs = ["Shake it Off", "You Belong with Me", "Back to December"]
songs[0]
songs[1]
songs[2]
인덱스 순으로 값이 읽어지는걸 확인했습니다
한가지 주의할 점은 인덱스가 0부터 2까지 있죠?
인덱스 3을 읽어들이려는 시도를 하면 프로그램이 멈출겁니다.
꼭 실존하는 인덱스만 사용해야합니다
문자열을 입력했기때문에 스위프트도 데이터타입이 문자열이라고 인지하고 있다.
근데 이것을 확실히 하고 싶으면 특정 구문을 사용해서 변수의 타입을 확인할 수 있다.
var songs = ["Shake it Off", "You Belong with Me", "Back to December"]
type(of: songs)
배열의 문자열임을 확인할 수 있다.
만약에 문자열 배열에 숫자를 넣는 실수를 했다고 가정해볼게요
에러가 뜨게 됩니다
그리고 에러메시지를 적당히 듣기 쉽게 바꿔보면 어떤 타입을 가지길 원하는지 배열의 타입을 명확히하라 정도로 해석할 수 있습니다.
그럼 배열을 String
타입으로 해줄까요?
var songs: [String] = ["Shake it Off", "You Belong with Me", "Back to December", 3]
다연히 에러가 뜰겁니다 3
은 문자열이 아니니까요
그럼 어떻게 하라고
여러가지 데이터 타입을 한 배열에 두고 싶으면 Any
키워드를 사용하면 됩니다
이렇게 말이죠
var songs: [Any] = ["Shake it Off", "You Belong with Me", "Back to December", 3]
위에서 사용한 방식말고 빈 배열을 먼저 만들고 나중에 값을 채워놓고 싶다면
어떻게 해야할까요?
일단 아래의 구문은 에러가 납니다
var songs: [String]
songs[0] = "Shake it Off"
왜 에러가 날까요? var songs: [String]
구문은 스위프트에게 songs
배열은 String
요소를 가질꺼야 라고 말해주지만 이게 실제로 배열을 만들지는 않습니다. 그냥 일종의 조건을 내민것 뿐이죠
배열을 만드는 방법에는 몇가지가 있는데요 그중에서 지금 당장 이해가 쉬운것은 이 코드입니다
var songs: [String] = []
그리고 이 방법도 흔하게 쓰입니다
var songs = [String]()
둘 다 같은 기능을 하지만 후자가 조금더 간략해서 선호되곤 합니다
배열에서도 연산자를 활용할 수 있습니다
var songs = ["Shake it Off", "You Belong with Me", "Love Story"]
var songs2 = ["Today was a Fairytale", "Welcome to New York", "Fifteen"]
var both = songs + songs2
또한 +=
같은 연산자도 사용할 수 있습니다
both += ["Everything has Changed"]
앞에서 봤듯이 배열은 숫자 인덱스를 통해서 값에 접근할 수 있었죠
딕셔너리 또한 흔한 집합입니다. 하지만 key
값으로 접근한다는 점이 배열과 다르죠
예시를 위해 배열을 우선 보죠
var person = ["Taylor", "Alison", "Swift", "December", "taylorswift.com"]
태어난 달을 알고싶으면 person[3]
을 하면되겠죠?
하지만 만약 누락된 정보가 있다던가하면 우리가 필요로 하는 값의 인덱스는 배열마다 달라지겠죠. 즉 혼란이 생기게 됩니다.
이걸 딕셔너리로 다시 작성해볼까요?
var person = ["first": "Taylor", "middle": "Alison", "last": "Swift", "month": "December", "website": "taylorswift.com"]
person["middle"]
person["month"]
각 key
에 따라 필요한 값들이 정리되어있습니다. 보기에도 좀 더 쉽겠죠
필요한 값을 찾기에도 쉬울 겁니다.
만약 코드부분에서의 가독성을 높이고 싶다면 빈 여백을 주면 됩니다
var person = [
"first": "Taylor",
"middle": "Alison",
"last": "Swift",
"month": "December",
"website": "taylorswift.com"
]
person["middle"]
person["month"]
특정 조건을 만족할 때만 코드가 작동되길 원한다면 if
와 else
를 사용하면된다.
else
는 조건이 거짓일 때 작동되는 코드 블록을 제공한다.
또는 else if
를 통해 조건을 더 추가할수도 있고
var action: String
var person = "hater"
if person == "hater" {
action = "hate"
}
==
연산자를 통해서 person
에 있는 값이 정확히 "hater"와 일치하는지 확인한다.
맞다면 action
변수를 "hate"로 할당한다.
이번엔 else if
와 else
구문을 추가해보자
var action: String
var person = "hater"
if person == "hater" {
action = "hate"
} else if person == "player" {
action = "play"
} else {
action = "cruise"
}
순서에 따라 각 조건을 확인하고 한가지만 실행한다.
여러가지 값들을 한번에 조건으로 만들 수도 있는데
이럴때 &&
같은 연산자를 쓰면된다
var action: String
var stayOutTooLate = true
var nothingInBrain = true
if stayOutTooLate && nothingInBrain {
action = "cruise"
}
stayOutTooLate
와 nothingInBrain
둘 다 참이기 때문에 조건은 참이 된다.
연산자를 활용하는 또다른 방법인데 !
를 붙여서 반대값을 나타내게 할 수 있다.
if !stayOutTooLate && !nothingInBrain {
action = "cruise"
}
코드에서 같은 일을 반복할 때는 코드를 여러번 작성할 수도 있지만 반복문을 사용할 수도 있다
print("1 x 10 is \(1 * 10)")
print("2 x 10 is \(2 * 10)")
print("3 x 10 is \(3 * 10)")
print("4 x 10 is \(4 * 10)")
print("5 x 10 is \(5 * 10)")
print("6 x 10 is \(6 * 10)")
print("7 x 10 is \(7 * 10)")
print("8 x 10 is \(8 * 10)")
print("9 x 10 is \(9 * 10)")
print("10 x 10 is \(10 * 10)")
이 코드는 단순 반복을 통해 순서대로 곱셈한 결과를 나타낸다
근데 이건 효율적인 코드가 아니죠
반복문을 통해서 바꿔봅시다
for i in 1...10 {
print("\(i) x 10 is \(i * 10)")
}
열 줄짜리 코드가 3줄이 됐습니다
반복문이 하는일은 1부터10까지의 숫자를 i
에 대입해서 괄호안의 코드를 동작시킨겁니다.
만약 어느 숫자에 있는지 알 필요가 없다면 _
를 사용해도 됩니다
var str = "Fakers gonna"
for _ in 1...5 {
str += " fake"
}
print(str)
이 방법이 조금 더 빠르며 만약 i
를 작성했는데 사용하지 않는다면 스위프트에서 _
로 변경할것을 권하기도 합니다.
스위프트는 배열에 어떤 데이터가 쓰였는지 알기때문에 배열요소의 반복을 굉장히 심플하게 제공합니다
var songs = ["Shake it Off", "You Belong with Me", "Look What You Made Me Do"]
for song in songs {
print("My favorite song is \(song)")
}
또는 배열에서도 for i in
구문을 사용할 수도 있죠
var people = ["players", "haters", "heart-breakers", "fakers"]
var actions = ["play", "hate", "break", "fake"]
for i in 0...3 {
print("\(people[i]) gonna \(actions[i])")
}
그리고 배열은 ..<
같은 범위연산자가 유용하게 쓰인다.
배열의 요소가 3개라면 인덱스는 0부터 2까지이기 때문이다.
또한 숫자대신 배열.count
를 쓰면 더 쉽게 인덱스를 사용할 수 있다
윗 코드를 다시 작성해보자
var people = ["players", "haters", "heart-breakers", "fakers"]
var actions = ["play", "hate", "break", "fake"]
for i in 0..<people.count {
print("\(people[i]) gonna \(actions[i])")
}
원한다면 반복문안에 반복문을 집어넣을 수 있다.
전에 작성했던 반복문을 조합하면 아래처럼 작성할 수 있다.
var people = ["players", "haters", "heart-breakers", "fakers"]
var actions = ["play", "hate", "break", "fake"]
for i in 0..<people.count {
var str = "\(people[i]) gonna"
for _ in 1...5 {
str += " \(actions[i])"
}
print(str)
}
while
반복문은 멈추는 조건이 있기 전까지 계속 반복한다.
var counter = 0
while true {
print("Counter is now \(counter)")
counter += 1
if counter == 556 {
break
}
}
여기서 break
라닌 키워드가 보이는데 while
이나 for
반복문은 탈출할 때 사용한다. 그게 없다면 무한 반복이 되게 된다
continue
는 break
와 다른 개념이다. break
는 그 즉시 바로 반복문을 빠져나오고 반복문 다음을 진행하지만 continue
는 현재의 반복만 탈출하고 다시 반복문을 진행한다.
var songs = ["Shake it Off", "You Belong with Me", "Look What You Made Me Do"]
for song in songs {
if song == "You Belong with Me" {
continue
}
print("My favorite song is \(song)")
}
조건과 일치하는 두번째 요소만 건너 뛴 것을 확인 할 수 있다.
if
와 반복문을 봤지만 스위프트는 switch/case라는 또 다른 흐름제어를 가지고 있다.
switch
문의 기초는 내가 스위프트에게 검사할 변수를 알려주고 변수에서 발생할 수 있는 모든 case를 제공하는 것이다.
그럼 스위프트는 처음으로 일치하는 case를 찾아서 그 안의 코드를 동작시킬것이다.
let liveAlbums = 2
switch liveAlbums {
case 0:
print("You're just starting out")
case 1:
print("You just released iTunes Live From SoHo")
case 2:
print("You just released Speak Now World Tour")
default:
print("Have you done something new?")
}
간단한 예시를 통해 실제로 그런지 확인해봤다
많은 if
와 else if
를 사용해 구현할 수도 있겠지만 이쪽이 더 깔끔하다.
그리고 switch문을 사용할 때는 항상 default
구문을 추가해줘야한다.
마지막으로 스위프트에서는 다른 언어처럼 switch
구문에 break
를 사용할 수 없다
대신에 fallthrough
라는 키워드가 있긴 하지만 이건 다른 성격의 키워드이므로 사용에 주의하자
와 이번거는 진짜 기네요
다음거는 이것처럼 길지 않기를 바래봅니다... 제발