Swift를 공부하기에 앞서 여러 유튜브 강의와 공식 도큐먼트 등을 찾아보았다.
그 중 boost course에서 나오는 야곰님의 Swift 강의가 가장 좋다고 느꼈고 그 이유는 아래와 같다:
Swift를 배우며 내용을 문서화 하기 위해 쓰는 개인적인 블로그 글이지만, 모든 내용의 base에는 부스트 코스에 나오는 야곰님의 강의를 바탕으로 쓰는 것이며 문제가 발생할 경우 모든 글을 지울 것이다
Reference
https://www.boostcourse.org/mo122/joinLectures/38564
swift는 대소문자를 구별하는 문법임을 유의!
print 는 단순 문자열 출력, dump는 인스턴스의 자세한 설명까지 콘솔 로그에 출력하는 함수다
\() in Swift == ${} in Dart
(e.g. print(“ 안녕하세요 저는 \(name)입니다“) )
싱수의 경우 let name: type = value
변수 var name: type = value
White space에 민감한 문법이기 때문에 반드시 변수나 상수의 이름 바로 뒤에 :을 붙이고 한 칸 띄운 뒤 type 선언
일단 변수나 상수명만 선언해두고 lazy하게 값을 할당하려는 경우 반드시 type을 명시 해야 한다. (dart도 하다못해 dynamic name; var name; 이렇게 하듯이)
당연히 상수는 lazy declaration을 할 때 단 한번만 값을 할당할 수 있다.
—
Bool, Int, Float, Double, Character 등의 값들은 익숙하니까 건너뛰고..
UInt
는 unsigned integer다. 당연히 음수 할당하려고 하면 컴파일 에러가 난다.
신기한 부분은 C언어보다도 implicit type conversion을 허용 안해준다. Float to int, int to Bool 도 안될 뿐더러. Float <-> double까지도 안된다.
Character type과 String type 모두 큰 따옴표 (“”)를 사용한다. 이런 건 대충해도 됐던 Dart에서의 안이한 습관을 이어가지 말자.
신기한 것은 Character type은 Unicode에서 가능한 모든 character가 되기 때문에 다양한 언어 뿐 아니라 이모지까지 된다! (왕신기)
당연히 String type 역시 이모지를 중간에 넣을 수 있다. Character <-> String 역시도 implicit type casting은 안된다.
그냥 컴파일러가 암시적으로 타입을 바꿔주는 모든 행위가 금지라고 생각하는 것이 편하다!
—
어떤 타입도 담을 수 있는 타입으로 Any, AnyObject 라는 타입이 있다
var example: Any = 100
example = “스트링도 되지롱”
example = 123.45
이런 식으로 Any type으로 선언된 변수는 어떤 값도 담을 수 있다. 다만 위 예시에서 example의 값을
Primitive type으로 선언된 다른 변수나 상수에 넣으려고 하면 에러가 난다.
AnyObject도 Any와 비슷하지만, class instance만 넣을수 있다!
var example2: AnyOjbect = Persion();
은 되지만 example2 = 123.45
은 안된다.
nil은 비어있음을 의미하기 때문에 Any나 AnyObject에도 할당할 수 없다.
위 예시에서 example1 = nil
혹은 example2 = nil
을 한다면 둘다 컴파일 에러가 난다.
—
다시 한번 collection type들의 정의에 대해 간단히 짚고 넘어가자
Array<Int> 는 [Int]로 줄여서 표현할 수 있다. (e.g. var int: Array[Int] = [Int]() )
var integers: Array<Int> = Array<Int>()
// 위와 동일한 표현
// var integers: Array<Int> = [Int]()
// var integers: Array<Int> = []
// var integers: [Int] = Array<Int>()
// var integers: [Int] = [Int]()
// var integers: [Int] = []
// var integers = [Int]()
당연히 let을 사용해서 array 선언하면 바꿀 수가 없고, append, removeAt 등의 메소드도 사용 불가능
var dict: Dictionary<String, Any> = [String: Any]()
오이오이 딱 봐도 Map 타입 같아 보이는 익숙한 이 친구는 뭐냐구~ json 파일받는 용인 것 같은 건 기분 탓이냐고~
// var anyDictionary: Dictionary <String, Any> = Dictionary<String, Any>()
// var anyDictionary: Dictionary <String, Any> = [:]
// var anyDictionary: [String: Any] = Dictionary<String, Any>()
// var anyDictionary: [String: Any] = [String: Any]()
// var anyDictionary: [String: Any] = [:]
// var anyDictionary = [String: Any]()
Dictionary 에서 특정 pair를 지우기 위해선 dict.removeValue(forKey: “키 이름”) 을 해주거나 dict[“키 이름”) = nil 을 선언해주면 된다.
set는 선언할 때 따로 줄임말이 없고 var setA: Set<Int> = Set<Int>()
이런 식으로만 선언해줘야 한다.
다만 집합의 특성을 가지고 있기 때문에 집합 전용 연산을 할 수 있다.
—
Swift도 다른 언어와 마찬가지로 function name, function body, parameter, parameter type, return type이 필요하고 그 형식은 아래와 같다.
func sum(a: Int, b: Int) -> Int {
return a + b
}
만약 반환값이 없다면 return type에 Void를 넣어주거나 아예 -> returnType
부분을 생략해도 된다.
다른 언어들과 다르게, 선언에서 표기한 매개변수들에 값을 적어주는 방식으로 호출한다. 예를 들어 위 함수 선언의 예제에서 sum이란 함수의 매개 변수가 a와 b 였으니, 이를 그대로 사용해서
sum(a: 3, b: 5)
이런 식으로 호출해야 한다.
func greeting(friend: String, me: String = "yagom") {
print("Hello \(friend)! I'm \(me)")
}
위 예제처럼 default value를 설정하고 싶은 parameter에
parameterName: parameterType = defaultValue
를 선언하면 된다.
기본 값이 설정된 파라매터에 값을 넣으면 그 값을 쓰고, 값을 안넣으면 기본 값을 쓴다.
파라매터에 매개변수의 역할을 알기 쉽게 label을 붙일 때 사용한다.
사용성과 readability를 높이기 위해 사용되는 것이지, 기능적으로 다른 건 없는 것 같다.
func greeting(to friend: String, from me: String) {
print("Hello \(friend)! I'm \(me)")
}
greeting(to: "john", from: "sydney")
함수마다 딱 하나의 가변 매개변수라는 것을 가질 수 있다.
전달 받을 값의 개수가 확실하지 않을 때 사용한다.
보통 이런 문제를 해결하기 위해서 List나 array를 사용하지만,
swift에선 굳이 그럴 필요가 없다.
func printNumbers(_ numbers: Int...) {
for number in numbers {
print(number)
}
}
printNumbers(0, 1, 2, 3, 4, 5)
/*결과
0
1
2
3
4
5
*/
다만 variadic parameter에 아무 값도 안넣거나 nil을 넣으면 오히려 에러가 생기므로, 차라리 해당 변수를 아예 빼야 한다.
printNumbers(numbers: 0, 1, 2, 3, 4, 5) //Good
printNumbers(numbers: ) //Error
printNumbers(numbers: nil) //Error
printNumbers() //Good
Swift의 함수는 객체 형태로 저장되기 때문에 일종의 data type처럼 사용 가능하다. 따라서
var someFunction: (String, String) -> Void = greeting(to:from:)
someFunction("john", "sydney")
동일한 파라매터와 리턴 타입을 가진 다른 function으로 someFunction을 다시 할당할 수 있지만, 타입이 다른 함수는 할당할 수 없다.
func runAnother(function: (String, String) -> Void) {
function("jenny", "mike")
}
// Hello jenny! I'm mike
runAnother(function: greeting(friend:me:))
// Hello jenny! I'm mike
runAnother(function: someFunction)
위와 같이 함수 안의 파라매터로 함수를 넣어줄 수도 있다!
func minMax(array: [Int]) -> (min: Int, max: Int) {
var currentMin = array[0]
var currentMax = array[0]
for value in array[1..<array.count] {
if value < currentMin {
currentMin = value
} else if value > currentMax {
currentMax = value
}
}
return (currentMin, currentMax)
}
let bounds = minMax([8, -6, 2, 109, 3, 71])
println("min is \(bounds.min) and max is \(bounds.max)")
// prints "min is -6 and max is 109"
하나 이상의 값을 반환하는 함수를 만들 땐 tuple로 반환 타입을 만들면 된다.
친구 노트북 뺏어서 작성된 건가요?