enum Optional<Wrapped>: ExpressibleByNiliteral {
case none
case some(Wrapped)
}
optional은 enum이다. '값이 존재하지 않음' 혹은 '특정 값을 wrap해놓은 값' 두가지를 가지는 것이다.
optional 사용
var optionalValue: Int? = 100
optionalValue = nil
? : 기본 옵셔널. 변수의 타입 뒤에 표현하며, 변수가 nil값을 포함할 수도 있음을 의미한다.
하지만 변수처럼 자유롭게 사용은 불가능하다. (optionalValue = optionalValue + 1과 같은 실행 불가능)
var implicitlyUnwrappedOptionalValue: Int! = 100
implicitlyUnwrappedOptionalValue = nil
! : 암시적 추출 옵셔널. 변수의 타입 뒤에 표현하며, 변수가 nil값을 포함할 수도 있음을 의미한다.
변수처럼 자유롭게 사용이 가능하다. (optionalValue = optionalValue + 1과 같은 실행 가능)
다만 이는 nil값이 아닐 것임에 대한 확신이 있을 때 사용한다. nil값을 포함할 수는 있지만 값을 항상 추출하여 변수처럼 사용하기 때문에 nil값이 존재할 경우 런타임 에러가 발생한다.
optional unwrapping
var number:Int? = 20
print(number!)
optional 변수를 unwrapping하여 사용할 수 있도록 한다.
만약 nil값이 존재하는 변수였을 경우 바로 런타임 에러가 발생한다.
cf. !으로 처음으로 암시적 추출 옵셔널을 사용했을 경우 이를 수행하지 않아도 바로 변수처럼 사용이 가능하다.
optional binding
옵셔널에 들어있는 값을 확인하고 추출하는 것이다.
var myName: String? = nil
var yourName: String! = nil
if let name: String = myName {
print(name)
} else {
print("myName is nil")
}
if let name = myName, let friend = yourName {
print("\(name) and \(friend)")
}
if-let 방식 : if문과 let을 바로 연이어 사용. 옵셔널 안에 값이 있는지 확인하고 있으면 해당 값을 꺼내온다.
값이 존재하지 않을 경우(nil) else문을 수행한다.
이렇게 설정한 상수는 if-let 구문 내부에서만 사용이 가능하다.
optional chaining
optional값 내부에 연속해서 optional값이 존재할 때 유용하게 사용된다.
guardJob = man?.home?.guard?.job
man, home, guard가 모두 optional값이라고 가정했을 때 위와 같은 방식으로 전개해 값을 가져올 수 있다.
하나씩 접근하다 중간에 nil값이 존재하면 접근을 멈추고 nil값을 반환한다.
guardJob = yagom?.home?.guard?.job ?? "슈퍼맨"
nil값이 반환되려 할 때 특정값이 대신 반환되도록 할 수 있다. 위의 경우 nil값이 반환되려 할 경우 대신 "슈퍼맨"이 반환된다.
class 메서드
swift에서 static 메서드는 다른 프로그래밍 언어와 같이 인스턴스를 생성하지 않고 바로 사용할 수 있는 메서드이다.
다만 이런 static 메서드는 상속 시 재정의가 불가능하다.
인스턴스를 생성하지 않고 바로 사용할 수 있지만 상속 시 재정의가 가능한 메서드를 class 메서드라고 한다.
class func classMethod() {
print("type method - class")
}
class 내부에서 위와 같이 작성하여 정의한다.
cf. 구조체와의 차이 : 클레스는 참조타입(데이터를 전할 때 메모리 위치전달)이고 구조체는 값타입(데이터를 전할 때 값을 복사) / 클레스는 상속이 가능하지만 구조체는 불가능
enum
enum Weekday {
case mon
case tue
case wed
case thu, fri, sat, sun
}
유사한 종류의 여러 값을 한 곳에 모아 정의한 것.
enum 자체가 하나의 데이터타입이 된다. (대문자 카멜케이스)
각 case는 고유의 값이 된다. (소문자 카멜케이스)
한 줄에 여러개도 정의될 수 있다.
var day: Weekday = Weekday.mon
day = .tue
enum 타입과 케이스를 사용해 값을 정의할 수 있다.
타입이 정해진 변수라면 케이스만 표현해도 괜찮다.
클로저
{ (매개변수 목록) -> 반환타입 in
실행 코드
}
매개변수와 반환 값이 존재할 수 있는 실행가능한 코드 블럭
이름을 필요로 하지 않는다.
함수는 일종의 이름있는 클로저이다.
let add: (Int, Int) -> Int
add = { (a: Int, b: Int) in
return a + b
}
func calculate(a: Int, b: Int, method: (Int, Int) -> Int) -> Int {
return method(a, b)
}
var calculated: Int
calculated = calculate(a: 50, b: 10, method: add)
이는 그대로 상수에 할당해 전달인자로 사용할 수 있다.
calculated = calculate(a: 10, b: 10) { (left: Int, right: Int) -> Int in
return left + right
}
후행클로저 : 클로저가 함수의 마지막 전달인자일 경우 이름을 생략한 후 외부에 클로저를 구현할 수 있다.
calculated = calculate(a: 10, b: 10, method: { (left: Int, right: Int) in
return left + right
})
else 블럭 내에 코드블럭을 종료하는 지시어(break,return 등)이 존재해야 한다.
guard let unwrapped: Int = someValue else {
return
}
unwrapped = 3
옵셔널바인딩에도 사용가능
if-let 바인딩과는 다르게 외부에서도 사용이 가능하다는 장점이 있다.
프로토콜
protocol Talkable {
// 프로퍼티 요구
var topic: String { get set }
var language: String { get }
// 메서드 요구
@objc optional func talk()
// 이니셜라이저 요구
init(topic: String, language: String)
}
java의 interface와 유사한 기능이다.
다만 protocol은 초기값 설정이 허용되지 않으며, optional이 붙어있는 메서드는 구현하지 않아도 되고, 정적멤버 선언이 가능하다는 차이점이 있다. (java의 interface는 초기값 설정이 가능하고, 모든 메서드를 구현해야하며, 정적멤버 선언이 불가능하다.)
상속형태로 클래스에서 받아와 작성한다. 단, 클래스와는 다르게 다중 상속이 가능하다.
someAny is Talkable
if let someAny: Talkable = someAny as? Talkable {
someAny.talk()
}
제네릭으로 들어올 타입에 제약을 걸어 들어올 수 있는 타입을 제한하는 것을 타입 제약이라고 한다.
이를 통해 어떤 타입이 들어올지 알 수 없는 제네릭에도 특정 작업을 수행할 수 있게 된다.
func makeSet<T: Comparable>(inputArray: [T]) -> [T] {
var result = [T]()
for element in inputArray {
if !result.contains(element) {
result.append(element)
}
}
return result.sorted()
}
예를 들어 위와 같은 함수의 경우, !result.contains(element)에서 Equatable 제약이 필요하고, result.sorted()에서 Comparable 제약이 필요하다. 하지만 Comparable 제약을 만족하면 Equatable 제약도 만족하므로, Comparable 제약만 존재하면 된다.
추가적으로 제약을 필요로 할 경우 함수 선언 부 뒤에 func makeSet<T: Comparable>(inputArray: [T]) -> [T] where T: FloatingPoint와 같이 추가하면 된다.