Swift는 타입 세이프(type-safe)한 언어예요. 그래서 컴파일할 때 코드에서 타입이 맞지 않으면 오류를 내줍니다. 또한, Swift는 타입을 추론할 수 있어서 모든 상수와 변수에 타입을 일일이 지정할 필요는 없어요. 예를 들어, 정수와 부동소수점을 함께 사용하면 Swift는 자동으로 Double 타입으로 추론합니다.
타입 별칭은 기존의 타입에 새로운 이름을 붙여주는 기능입니다. 예를 들어볼까요?
typealias AudioSample = String
var audioName: AudioSample = "audio"
이렇게 하면 AudioSample
이라는 이름으로 String
타입을 사용할 수 있어요. 이후에 AudioSample
이 마치 새로운 타입인 것처럼 사용할 수 있는 거죠.
튜플은 여러 값을 하나로 묶을 때 사용합니다. 각각의 값이 어떤 타입이든 상관없고, 같은 타입일 필요도 없어요.
let http404Error = (404, "Not Found")
이렇게 HTTP 상태 코드와 메시지를 하나로 묶어서 사용할 수 있죠. 또, 튜플을 분해해서 사용할 수도 있어요
let (statusCode, statusMessage) = http404Error
print("The status code is \(statusCode)")
print("The status message is \(statusMessage)")
이런 식으로 튜플의 값을 쉽게 분해해서 사용할 수 있답니다. 튜플의 요소에 이름을 붙여 더 편하게 접근할 수도 있어요
let http200Status = (statusCode: 200, description: "OK")
print("The status code is \(http200Status.statusCode)")
print("The status message is \(http200Status.description)")
튜플은 간단한 데이터 묶음을 표현할 때 유용하지만, 복잡한 구조를 나타낼 때는 클래스나 구조체를 사용하는 게 더 좋습니다.
옵셔널은 값이 있을 수도, 없을 수도 있음을 나타내는 타입입니다. 값이 없으면 nil
로 표현하죠.
let possibleNumber: String = "123"
let convertedNumber: Int? = Int(possibleNumber)
여기서 Int?
는 옵셔널 타입을 나타내며, possibleNumber
가 숫자 문자열이면 Int
로 변환하고, 그렇지 않으면 nil
을 반환합니다.
옵셔널 변수는 nil
을 가질 수 있어요. 이 말은, 변수에 값이 없음을 나타낼 때 nil
을 사용할 수 있다는 뜻입니다.
var serverResponseCode: Int? = 404
serverResponseCode = nil
이렇게 옵셔널로 선언한 변수는 값을 넣거나 nil
로 비울 수 있어요.
옵셔널 바인딩은 옵셔널에 값이 있는지 확인하고, 그 값을 안전하게 꺼내 사용할 수 있게 해줍니다.
if let actualNumber = convertedNumber {
print("The string \"\(convertedNumber)\" has an integer value of \(actualNumber)")
} else {
print("The string \"\(convertedNumber)\" could not be converted to an integer")
}
이 코드에서는 convertedNumber
에 값이 있는지 확인하고, 값이 있으면 actualNumber
에 할당해서 사용하는 방법입니다. 이런 과정을 옵셔널 바인딩이라고 해요.
옵셔널 값이 없을 때 기본값을 제공하고 싶다면, nil-결합 연산자(??
)를 사용하면 됩니다
let name: String? = nil
let greeting = "Hello, " + (name ?? "friend") + "!"
print(greeting)
// Prints "Hello, friend!"
여기서는 name
이 nil
이면 "friend"라는 기본값이 사용됩니다.
강제 언래핑은 옵셔널을 강제로 풀어주는 방법이에요. 변수 뒤에 느낌표(!
)를 붙이면 되는데, nil
일 경우 런타임 에러가 발생할 수 있으니 주의해야 해요.
let possibleNumber = "123"
let convertedNumber = Int(possibleNumber)
let number = convertedNumber!
print("number: \(number)")
// Prints number: 123
강제 언래핑은 nil
이 아닌 경우에만 안전하게 사용할 수 있습니다. nil
일 가능성이 있다면 옵셔널 바인딩이나 nil 결합 연산자를 사용하는 게 더 안전해요.
때로는 옵셔널 값을 항상 갖고 있다고 확신할 수 있을 때, 일일이 언래핑하지 않고 자동으로 언래핑되게 할 수 있습니다. 이걸 암시적으로 언래핑된 옵셔널이라고 해요.
let assumedString: String! = "An implicitly unwrapped optional string."
let implicitString: String = assumedString // Unwrapped automatically
하지만 조심해야 해요. 만약 assumedString
이 nil
이라면 접근할 때 에러가 발생할 수 있거든요.
Swift에서는 에러가 발생할 수 있는 상황을 처리할 수 있도록 에러 핸들링 기능을 제공해요. throws
키워드를 사용해 에러를 던질 수 있고, do-try-catch
구문을 사용해 그 에러를 처리할 수 있습니다.
func makeASandwich() throws {
// this function may or may not throw an error
}
do {
try makeASandwich()
eatASandwich() // 에러가 없을 경우 실행
} catch SandwichError.outOfCleanDishes {
washDishes()
} catch SandwichError.missingIngredients(let ingredients) {
buyGroceries(ingredients)
}
이처럼 에러가 발생할 수 있는 코드를 try
로 감싸고, 에러가 발생하면 catch
블록에서 처리합니다.
Swift에서는 에러를 처리하는 다양한 방법이 있어요
try?
: 에러가 발생하면 nil
을 반환해요. 간단하게 결과만 필요할 때 유용합니다.
let result = try? someThrowingFunction()
try!
: 에러가 발생하지 않음을 확신할 때 사용해요. 에러가 발생하면 프로그램이 크래시할 수 있으니 주의해야 해요.
let result = try! someThrowingFunction()
rethrows
: 함수 자체는 에러를 던지지 않지만, 전달받은 클로저가 에러를 던질 수 있을 때 사용해요. 예를 들어, 고차 함수가 클로저를 파라미터로 받을 때 rethrows
를 사용합니다.
func someFunction(callback: () throws -> Void) rethrows {
try callback()
}
코드가 올바르게 작동하는지 확인하기 위해 Assertions
와 Preconditions
를 사용할 수 있어요. 이 두 가지는 코드가 예상치 못한 상황에서 어떻게 반응할지 확인하는 데 유용해요.
Assertions
는 주로 개발 중에 잘못된 상태를 감지하는 데 사용돼요. 예를 들어, 나이가 음수가 될 수는 없겠죠? 이럴 때 assert
로 조건을 걸어두는 겁니다.
let age = -3
assert(age >= 0, "A person's age can't be less than zero.")
// 이 Assertion은 -3이 0보다 크지 않기 때문에 실패합니다.
이렇게 하면 디버깅할 때 논리적인 오류를 쉽게 발견할 수 있어요.
Preconditions
는 Assertions
와 달리 프로덕션 코드에서도 반드시 지켜져야 하는 조건을 검사해요. 예를 들어, 배열의 인덱스가 범위를 벗어나면 안 되겠죠?
// 배열의 인덱스를 접근하기 전에 반드시 인덱스가 유효한지 검사
precondition(index >= 0 && index < array.count, "Index out of bounds")
이렇게 해서 잘못된 인덱스 접근을 방지할 수 있답니다.
정리하자면, Assertions
는 개발 중 논리 오류를 조기에 발견하기 위해 사용하고, Preconditions
는 프로덕션 코드의 안전성을 보장하기 위해 필수 조건을 확인할 때 사용해요. 각각의 목적에 맞게 잘 활용하면 코드를 더 안전하게 만들 수 있습니다.
타입 세이프티와 타입 추론
타입 별칭(Type Aliases)
typealias
키워드를 사용해 기존 타입에 새 이름을 부여할 수 있음.튜플(Tuples)
옵셔널(Optionals)
nil
로 표현.nil
nil
로 표현.강제 언래핑(Force Unwrapping)
!
를 붙여 강제로 값을 언래핑. nil
일 경우 런타임 에러 발생 가능.암시적으로 언래핑된 옵셔널(Implicitly Unwrapped Optionals)
nil
일 경우 에러 발생.에러 처리(Error Handling)
throws
키워드를 사용해 에러를 던지고, do-try-catch
구문으로 처리.try?
, try!
, rethrows
를 사용해 다양한 에러 처리 방법 제공.Assertions
Preconditions
Assertions과 Preconditions의 차이
출처
이 글은 swift 공식문서를 읽고 정리한 내용입니다.
https://bbiguduk.gitbook.io/swift/language-guide-1/the-basics