Swift 문법 정리
Integer Types
//Int8의 8은 비트를 뜻한다. 범위를 기억할필요는 없다. 아래와같이 실행해보면 된다.
Int8.min
Int8.max
Int16.min
Int16.max
Int32.min
Int32.max
Int64.min
Int64.max
//만약에 범위가 아니라 메모리의 크기를 알아보고 싶다면 아래처럼 하면 된다.
MemoryLayout<Int8>.size // 1이 출력되므로 1바이트의 메모리 크기를 가진다는 뜻이다.
MemoryLayout<Int16>.size
MemoryLayout<Int32>.size
MemoryLayout<Int64>.size
Int8.min
Int8.max
UInt8.min
UInt8.max
//특별한 이유가 없다면 주로 Int를 사용하게 된다. 이유는 정수를 가장 빠르게 처리할 수 있기 때문이다.
//32비트 컴퓨터를 사용한다면 Int 크기는 4바이트가 되고, 64비트를 사용한다면 8바이트가 되는데 iOS나 MacOS는 모두 64비트의 환경이므로 8바이트이다.
MemoryLayout<Int>.size
Int.min
Int.maxFloating-point Types
Type Safety
Swift는 형식 안정성을 보장하기 위해서 자료형을 엄격히 구분한다.
Type Alias
기본 자료형에 새로운 이름을 추가하는 문법, 새로운 자료형을 만드는 것은 아니라는 점을 주의 활용하기에 따라서 코드의 가독성을 높일 수 있다. Upper Camel Case를 사용한다.
Operators
truncatingRemainder(dividingBy:)
Short-circuit Evaluation
스위프트는 논리연산자를 평가할 때 아래 연산자처럼 &&일때 앞이 false면 && 뒤는 평가하지 않는다. 마찬가지로 || 연산에서도 앞이 true면 뒤는 평가하지 않는다. 이런 방식을 단락평가라고 한다.
Switch - Where
Switch - FallThrough
case 값이 충족했다면 바로 case 문을 빠져나가는 것이 아니라, 다음 case 문의 값과 상관없이 다음 case 문의 블록을 실행하고 case 문을 빠져나간다. 만약 다음 case 조건이 없고 default가 있다면 default를 실행하고 종료된다.
For-In
stride(from:to:by)
stride(from:through:by)
multiplication table
star - left triangle
star - right triangle
star - center triangle
star - diamond
star - pinwheel
Repeat-while
코드를 먼저 실행한 다음에 컨디션을 평가한다.
Control Transfer Statements
조건문, 반복문에서 일반적인 코드의 흐름을 바꾸기 위해 사용한다. break, continue, fallthrough, return, throw 제어를 전달한다는 것은 현재 실행중인 스코프에서 코드를 중지하고 다음에 실행할 코드를 바로 실행한다는 것이다.
break
반복문, 스위치문에서 사용된다. 문장을 종료한다. 문장을 종료하는데 가장 인접한 문장만 종료하고 이어서 실행된다.
continue
현재 실행중인 반복을 중지하고 다음 반복으로 이동한다. 문장을 중지하지는 않는다. 가장 인접한 문장에 영향을 준다. 무엇을 종료하고 무엇을 계속하는지만 구분하면 되겠다. break는 switch, loop에서 사용했지만 continue는 loop에서만 사용된다.
labeled statement
문장에 이름을 붙이고 :(콜론)을 붙인다. 주로 제어문과 반복문이 중첩된 코드에서 가장 인접한 문장이 아니라 원하는 문장을 종료하고 싶을때 주로 사용된다. break, continue와 함께 사용되고 반복문, if문, switch문에서 주로 사용된다.
Optionals
implicitly unwrapped optionals
optional pattern
Functions
함수이름은 주로 동사가 포함된다. 아규먼트 레이블은 주로 to in with 와 같은 전치사가 포함된다. 그리고 파라미터 네임에는 주로 명사가 사용된다. 파라미터가 1개라면 name은 Parameter Name임과 동시에 Argument Label이다. 파라미터가 2개라면 앞에가 Argument Label이고 뒤에가 Parameter Name이다. Argument Label를 사용하는 이유는 가독성을 높이기 위해서이다. Parameter Name은 함수 바디에서 사용된다. Argument Label은 함수를 호출할 때 사용된다.
variadic parameters
하나의 파라미터로 두 개이상의 파라미터를 전달할 수 있다. 아규먼트는 함수 내부로 전달할 때 배열형태로 전달된다. 가변파라미터는 함수마다 1개만 쓸 수 있다. 가변파라미터는 보통 처음이나 마지막에 선언한다. 중간에는 잘 선언하지 않는다. 가변파라미터는 기본값을 가질 수 없다. 전달할 수 있는 아규먼트수가 고정되어 있지 않기 때문에 가변파라미터라고 부른다.
in-out parameters
아규먼트로 전달된 함수의 값을 직접 바꿀 수 있다. 타입 앞에 inout을 적어준다. 호출 할때는 &을 적어준다. copy-in, copy-out 메모리 모델을 사용한다. copy-in : 변수에 저장된 값을 복사해서 전달한다. copy-out : 함수가 종료되면 함수에서 변경한 값이 아규먼트로 전달한 변수에 복사된다.
In-Out 자주하는실수, 제약조건
같은 변수를 전달한다. 상수를 전달한다. 리터럴 값을 전달한다. 리터럴은 값을 저장하고 있는 메모리 공간조차 없다. 함수의 기본값을 지정할 수 없다. 기본값은 리터럴값인데 위와 마찬가지로 메모리 공간조차 없다. 또한 기본값에 메모리 공간을 가진 변수도 지정할 수 없다. 그냥 문법적으로 기본값이 허용되지 않는다. 가변 파라미터는 inout 키워드에서 사용될 수 없다.
function types
함수를 변수나 상수에 저장할 수 있다. 파라미터로 전달할 수도 있다. 함수에서 리턴할 수도 있다.
nonreturning functions - never
리턴 타입 중에 하나인데, 음.. fatalError()하고 비슷한 느낌인 것 같다. 실제로 fatalError() 또한 리턴타입이 Never이긴 한데, 저 녀석이 있으면 함수가 정상적으로 리턴되지 않는다? 그리고 프로세스가 즉시 종료된다 뭐 그런의미인 것 같다. 사용예시는 아래와 같으나 솔직히 잘 모르겠다.
@discardableResult
리턴 값이 있는데 사용하지 않으면 Swift는 경고를 표시해준다. 그러나 리턴 값이 있어도 사용하지 않을 수도 있는 거다. 그럴 때 함수 위에 @discardableResult를 명시해주면 해당 경고가 사라진다. 다른 방법도 있는데 @discardableResult를 굳이 쓰지않고, 와일드카드 패턴을 이용해서 _ = saySomething() 라고 해줘도 그만이다.
Closures
capturing values
값을 캡처한다는 그냥 값을 가져와서 쓴다고 이해해도 괜찮다. 클로저 내부에서 클로저 외부에 있는 값에 접근하면 클로저는 값을 캡쳐(그냥 값을 가져와서 쓴다)한다. 값을 캡쳐할 때, objc에서는 값의 복사본을 가져와서 쓴다. 반면에 swift에서는 값의 참조를 캡쳐한다. 이말은 값의 원본값을 그대로 가져온다는 말이다. 그래서 클로저에서 가져온 값을 바꾸면 원래 값도 같이 변경된다.
정리하자면, 클로저 내부에서 외부에 있는 값에 접근하면 값의 참조를 획득한다. 내부에서 값을 바꾼다면 외부에 있는 원래값도 함께 바뀐다. 그렇기 때문에 클로저에서 값을 캡쳐할 때 메모리관리를 하지 않는다면 참조 사이클 문제가 발생한다.
escaping closure
탈출하는 클로저. 무엇으로부터 탈출해? 함수흐름으로부터! @escaping 키워드를 사용한다. 함수 내부에서 실행되는 클로저는 디폴트값으로 NonEscaping Closure이다. 이 말은, 함수가 시작되고나서 클로저가 실행되고 함수가 종료되기전에 클로저가 완료된다는 뜻이다. 그러면 반대로 Escaping Closure는 뭘까? Escaping Closure 는 함수의 실행이 종료되어도 호출될 수 있다는 것을 말한다. 즉, 시작시점과 종료시점이 특정되지 않는다. 함수가 시작되면 호출되는 것은 같지만 함수가 실행되는 중간에 함수가 실행될 수도 있고, 함수실행이 종료된 후에 실행될 수도 있다. 또, 함수 종료도 마찬가지로 함수 실행이 끝난 후에 종료될 수도 있다.
@autoclosure
파라미터로 전달되는 표현식을 표현식을 클로저로 래핑하는 단순한 특성이다. {} brace 를 안써도 되게 해주는 것으로 이해하면 쉽다. @autoclosure 특성을 선언하면 리턴타입은 자유롭지만, 파라미터는 항상 비워둬야 한다.
Tuple
tuple decomposition
tuple matching
튜플매칭과 인터벌매칭, 밸류바인딩패턴, 스위치문을 활용하면 if문보다 코드가 훨씬 더 깔끔해진다.
String
string types
NSString과 String은 호환된다. 개발자문서에서는 두 형식을 브릿징이 가능한 타입이라고 설명하고 있다. 두 자료형은 호환되지만 유니코드를 처리하는 방식이 다르다는 것은 알아야 한다. 다만 타입캐스팅이 필요하다.
multiline string literal
멀티라인은 """ ~ """ 같은 방식으로 명시적인 줄바꿈을 허용한다. 멀티라인을 시작할 때 """ 이후에 바로 문자열이 시작한다면 에러가 발생한다. 멀티라인의 내용은 항상 새로운 라인에서 시작해야 한다. 또 마지막에 있는 큰따옴표 또한 한줄에 단독으로 작성해야 한다. 마지막에 있는 큰따옴표는 항상 텍스트와 동일선상에 있거나 왼쪽에 있어야한다. 멀티라인에서 문장의 끝에 (백슬러쉬)를 추가하면 명시적으로 줄바꿈이 되어있어도 줄바꿈이 되지 않는다.
escape sequences
백슬래시( \ ) 뒤에 한 문자나 숫자 조합이 오는 문자 조합을 "이스케이프 시퀀스"라고 합니다. 줄 바꿈 문자, 작은따옴표, 또는 문자 상수의 다른 특정 문자를 나타내려면 이스케이프 시퀀스를 사용해야 합니다. 이스케이프 시퀀스는 단일 문자로 간주되므로 문자 상수로 유효합니다. \n 과 같은것들 !
raw string
Raw String은 \와 "를 문자그대로 처리한다. = Raw String을 활용하면 특수문자 등을 쉽게 추가할 수 있고, 문자열의 가독성이 증가한다. = String Interpolation 같은 경우에도 로우 스트링일때는 이스케이프 시퀀스가 인식되지 않기 떄문에 #을 추가해줘야 한다. = 정규식 문자열을 로우스트링으로 처리하면 불필요한 백슬래쉬가 사라지기 때문에 문자열을 더욱 직관적으로 작성할 수 있는 장점이 있다.
string interpolation
문자열을 동적으로 구현하는 방법이다. 코드가 간결해진다. 단점으로는 자동으로 타입을 바꿔주기 때문에 원하는 포맷을 지정할 수는 없다. (예를들어 size를 소수점 첫째자리까지 표현한다던지..) 그럴때는 아래의 포맷지정자를 사용한다.
string interpolation(swift 5+)
format specifier
https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Strings/Articles/formatSpecifiers.html#//apple_ref/doc/uid/TP40004265-SW1
string indices
string index는 정수타입이 아니다.
endindex는 마지막의 다음 인덱스다. 따라서 마지막인덱스를 가져오기 위해 index(before:) 메소드를 이용한다.
잘못된 인덱스를 사용하면 크래쉬가 발생한다.
string basic
문자열 연결
원하는 포맷으로 문자열을 연결
문자열을 중간에 연결
문자열의 특정문자, 범위를 삭제
drop
str.dropLast() //Substring
str.dropFirst() //Substring
str.drop(while:) //Substring
drop으로 시작하는 메소드들은 리턴값이 Substring 이므로 원본의 메모리를 공유한다.
문자열의 일부를 교체
문자열 비교
문자열 검색
문자열 분리
Collections
데이터 모음을 효율적으로 사용하기 위한 자료형이다. Swift에서는 아래와 같은 3가지의 컬렉션을 제공한다.
Array : 순서대로 저장되는 컬렉션
Dictionary : 키와 값이 쌍으로 연결된 컬렉션
Set : 수학에서 공부하는 집합연산을 제공하는 컬렉션
Swift에서 사용할 수 있는 컬렉션은 크게 2가지로 나뉜다.
Foundation Collection : 예전부터 사용되었던 컬렉션 클래스. - 컬렉션에 저장하는 하나의 데이터는 Element라고 부른다. - 컬렉션을 참조형식으로 처리해야 할 때 사용한다. - NSArray, NSDictionary, NSSet - Object(객체)형태만 저장이 가능하다. 문자열, 숫자 등을 저장하고 싶다면 NSNumber, NSValue 등을 사용해서 객체형식으로 바꿔주어야 한다. - 자료형에 제한이 없다. 하나의 컬렉션에 문자객체와 숫자객체를 저장하는 것도 가능하다. - 가변컬렉션(NSMutableArray, NSMutableDictionary, NSMutableSet)과 불변컬렉션(NSArray, NSDictionary, NSSet)을 별도로 제공한다. - 불변컬렉션에 가변변수의 값은 얼마든지 변경이 가능하지만, 가변컬렉션에 불변변수의 값을 변경이 불가능하다.
Swift Collection : Swift에서 새로 도입된 컬렉션 구조체.
컬렉션에 저장하는 하나의 데이터는 Element라고 부른다.
값형식
Array, Dictionary, Set
Object(객체)형태와 Value(값)형태 둘 다 저장가능하다.
동일한 자료형의 데이터만 저장해야 한다. 그랴소 선언 시점에 저장할 데이터의 자료형을 명시적으로 선언해야한다.
키워드로 가변(var)과 불변(let)을 결정한다.
불변컬렉션에 가변변수의 값은 얼마든지 변경이 가능하지만, 가변컬렉션에 불변변수의 값을 변경이 불가능하다.
Swift는 값형식이기 때문에 컬렉션에서 값을 복사한다. 하지만 상대적으로 문자열,숫자에 비해서 큰 데이터를 저장한다. 그렇기 때문에 반드시 복사가 필요한 경우에만 실제 복사를 실행하는 Copy-on-write 최적화 방식을 활용한다. 컬렉션이 변경되지 않는다면 항상 동일한 데이터를 사용하다가, 변경된다면 그 시점에 새로운 데이터를 생성하고 변경을 저장한다.
Array
Dictionary
Set
Property
Stored Properties
아래와 같이 어떤 값을 선언하고 할당하는 것을 저장 프로퍼티라고 한다. 프로퍼티는 구조체, 클래스 내부에 구현할 수 있다.
Lazy Stored Properties
지연 저장 프로퍼티라고 부른다. 지연 저장 프로퍼티는 초기화를 지연시킨다. 즉, 인스턴스가 초기화 되는 시점이 아니라 속성에 처음 접근하는 시점에 초기화된다. 항상 변수(var) 저장 속성으로 선언해야 한다. lazy let이 안된다는 말이다. 생성자에서 초기화하지 않기 때문에 선언시점에 기본값을 저장해야 한다. 이미지가 필수가 아니라 선택일 때 지연 저장 속성을 사용하면 불필요한 메모리 공간을 줄일 수 있다.
Computed Properties
연산 프로퍼티라고 부른다. 프로퍼티는 구조체, 클래스, 열거형 내부에 구현할 수 있다. 수학적으로 계산된다는 뜻이 아니라 다른 속성값을 기반으로 속성값이 결정된다는 뜻이다. 저장 속성은 메모리 공간을 가지지만, 계산 속성은 메모리 공간을 가지지 않는다. 다른 속성에 저장된 값을 읽어서 필요한 계산을 실행한 다음 리턴하거나 속성으로 전달된 값을 다른 속성에 저장한다. 계산때마다 다른 결과가 나올 수 있기 때문에 항상 var로 선언해야 한다. 읽기전용으로는 구현할 수 있지만, 쓰기 전용으로는 구현할 수 없다. 읽기전용으로 구현하려면 get만 작성해주면 되고 생략도 가능하다. 읽기, 쓰기 모두 가능하게 하려면 get 블럭과 set블럭을 모두 구현해주면 된다. set(name)과 같은 식으로 파라미터를 사용할 수 있다. 생략하면 newValue 키워드를 사용한다. 읽기전용 계산 속성은 get과 brace가 생략되기 때문에 클로저라고 생각할 수 있다. 그럴땐 자료타입 뒤에 할당연산자(=)가 있나없나를 보면 알 수 있다.(=이 있으면 클로저)
읽기 전용(set이 없는) 연산 프로퍼티
읽기 / 쓰기가 둘 다 있는 연산 프로퍼티
Keypath String Expression
먼저 Keypath, KVC, KVO 부터 대충 알아보자.
Keypath 문자열 키를 사용해서 속성에 접근하는 기술의 Key 부분을 말한다. Key Value Cording(KVC)와 Key Value Observing(KVO)의 근간을 이루는 개념이다. Keypath의 key도 딕셔너리처럼 문자열이다. 하나이상의 키가 점으로 연걸된 형태(a.b.c)이다. 키를 통해서 특정 속성에 접근한다. Keypath를 통해서 속성에 접근하기 위해서는 2가지 조건이 필요하다.
NSObject 클래스 상속
속성 앞에 @objc 특성을 추가
KVC(Key Value Cording) 문자열 키를 사용해서 속성에 접근하는 기술
KVO(Key Value Observing) Swift의
프로퍼티 옵저버(willSet, didSet)처럼 변수가 변경될 때마다 관찰해서 코드가 실행되도록 하는 기능이다. 실제로 동작이 유사하기도 하지만, 프로퍼티 옵저버가 내가 만든 타입에서 정의해서 사용해야 하는 것과는 달리 KVO는 외부 라이브러리같은 내가 건드리지 못하는 곳에서 해당 속성을 옵저빙하고 싶을 때 사용하곤 한다. KVO는 Objective-C 런타임에 의존하기 때문에, 순수한 swift 코드에서는 그리 좋지 않다. NSObject를 상속받은 @objc를 사용해야 하고, 각각의 프로퍼티에 @objc dynamic 표시를 해야한다.
어쨋건, p.value(forKey: "name")와 같은 식으로 키 값을 틀릴 수 있으니 나온 것이 바로 Keypath String Expression이다. 아래와 같은 식으로 keyPath를 생성한다. 잘못된 키패스는 컴파일 에러가 발생하기 때문에 미리 알 수 있다. 리턴 값이 String이라서 사용은 똑같이 할 수 있다. 하지만, 단점은 생성한 리턴 값이 Any?이기 때문에 타입캐스팅을 해주어야 한다. 그래서 이 점을 보완해서 나온 것이 Keypath Expression이다.
Keypath Expression
Keypath의 리턴값이 Any?라서 타입캐스팅이 필요했었다. 이 부분을 보완하기 위해 나온 기술이다. 한마디로 정의하면 백슬래시(\)와 닷(.)으로 원하는 속성까지 점으로 연결하는 표현식이다. Keypath Types을 사용한다. Keypath Types이 제네릭으로 구현되어 있기 때문에 타입캐스팅 없이 저장된 값을 바로 사용할 수 있다.
Keypath Types 스위프트가 제공하는 특별한 타입이다. 문자열로 된 키패스에 비해 다양한 기능을 제공한다. 두 개의 타입이 있는데 루트타입과 접근하는 속성의 타입이다. 종류는 아래와 같다. 자세한 건 공식문서를 보도록 하자. 딱히 안봐도 이해하는데 문제는 없다.
자, 그래서 어떻게 Keypath Expression을 사용할까?
Keypath String Expression Vs Keypath Expression

Last updated
