Swift 기본 타입

낯선 언어를 매일 학습하며 몰입과 성장을 기록하는 일지

  ·  7 min read

오늘의 포커스 #

  • Swift 공식 문서 중 Type에 대한 이해

The Baiscs #

Naming constatns and Variables #

  • 유니코드 문자를 포함한 거의 대부분의 문자가 변수 또는 상수의 이름이 될 수 있음
  • 다만 이름에 공백, 수학 기호, 화살표, 사적 유니코드 스칼라 값, 선, 박스 문자는 허용되지 않는다.
  • 숫자는 허용되나 시작을 숫자로 할 수는 없다.
  • 동일이름, 동일타입으로는 중복 변수 또는 상수를 만들 수 없음
  • 또한 변수를 상수로, 상수를 변수로 변경 불가
  • 다른 언어와 다르게 스위프트의 예약어를 이름으로 쓰고 싶다면 backticks으로 감싸서 사용해야 한다.
  • 하지만 스위프트의 키워드의 경우 예외 없이 사용 불가
var friendlyWelcome = "Hello!"
friendlyWelcome = "Bonjour!

Printing Constants and Variables #

  • 상수 또는 변수를 print(\_:separator:terminator:) 함수로 출력 가능
print(friendlyWelcome)
// prints Bojour
  • print(\_:separator:terminator:) 함수
    • 전역 함수
    • 하나 또는 많은 값들을 적절한 결과로 출랴
  • separatorterminator 인자는 기본값이 존재, 생략 가능
  • terminator의 기본값은 line break
  • 다른 값을 너어주고 싶으면 해당 인자에 원하는 값을 넣어줄 수 있음
  • 문자열 보간(interpolation)을 사용 가능
    • interpolation: 긴 문자열의 경우 placeholder에 변수명을 집어 넣어 해당 변수의 값을 문자열 안에 바꾸어 넣는 기능
    • print("The current value of friendlyWelcome is \(friendlyWelcome)")
      

Comments #

  • Comments는 C, C++, Java와 상동

Semicolosn #

  • 다른 언어와 달리 스위프트는 세미콜론을 각 statement 뒤에 붙일 필요가 없음
  • 다만 원한다면 사용할 수 있음
  • 다중 statement를 한 줄로 쓸 때는 semicolon으로 statement를 구분시켜야함

Integers #

  • Integer의 경우 비트 수의 크기를 선택 가능
  • unsigned는 앞에 U를 붙여 표현 가능
    • UInt8, Int32, Int8
  • Swift는 추가적으로 뒤에 숫자가 없는 Int 타입을 제공
  • Int 타입은 플랫폼의 native word size에 따라 Int 타입의 크기를 결정
  • Int는 32 비트 플랫폼에서는 Int32, 64 비트 플랫폼에서는 Int64가 자동 선택
  • UInt도 마찬가지로 적용됨

Floating-Point Numbers #

  • 특정 사이즈의 floating-point Numbers가 필요하지 않다면 Double 타입을 사용
  • 특정 크기는 Float32, Float64처럼 Float 뒤 크기를 지정 가능
  • 다만 그래픽 코드의 경우 빠른 GPU 처리에 적합한 Float를 사용

Type Safety And Type Inference #

Numeric Literals #

  • 기본은 10진수
  • 0b 접두사는 2진수
  • 0o 접두사는 8진수
  • 0x 접두사는 16진수
  • e접두사는 10의 승수를 의미
  • p는 2의 승수를 의미
  • 가독성을 위해 패딩 또는 언더 대시를 넣을 수 있음
    • let paddedDouble = 00123.456
    • let oneMillion = 1_000_000
    • let justOverOneMillion = 1_000_000.000_000_1

Numeric Type Conversion #

  • Type(variable) 또는 Type(value)의 형태로 타입 변환 가능
  • Floating point numbers에서 Integer로의 Conversion은 내림 연산
  • Int(-3.9) = -3

Type Aliases #

  • typealias 키워드를 이용해서 type aliases를 선언
  • typealias AudioSample = UInt16
  • 문맥적으로 더욱 적절한 타입명을 붙여줄 수 있음

Booleans #

  • Boolean은 논리값을 가짐
    • true, false
  • 조건문에서 사용 가능
if turnipsAreDelicious {
  print("Mmm, tasty tunips!")
} else {
  print("Eww, turnips are horrible.")
}
  • Swift의 타입 안정성은 다른 타입을 Bool 타입 대신하여 쓸 수 없도록 함
    • while(1)과 같은 코드 불가

Tuples #

  • 튜플은 여러개의 값을 하나의 단일 값으로 묶는 타입
  • 튜플 안의 값은 어떤 타입이나 들어 올 수 있고, 다른 값들의 타입들이 동일할 필요도 없음
    • (404, "Not Found")는 튜플로 생성된 HTTP Status Code
    • Int와 String을 하나의 튜플로 묶음
  • 사용 하지 않을 값에 대해서는 언더스코어(_)를 통해 해당 부분을 무시할 수 있음
let (justTheStatusCode, _) = http404Error
print("The status code is \(justTheStatusCode)")

print("The status code is \(justTheStatusCode.0)")
print("The status message is \(justTheStatusCode.1)")
  • 또한 선언 시 각각의 튜플 요소들에 이름을 지을 수 있음
let http200Status = (statusCode: 200, description: "OK")
  • 튜플은 함수의 값을 리턴할 때 매우 유용
  • 예제와 같은 웹 페이지 탐색을 시도하는 함수의 경우 (Int, String) 튜플 타입을 페이지 탐색의 성공 또는 실패를 표현하기 위해 리턴하기 때문
  • 다만 복잡하게 연관된 값들을 묶기에는 적절하지 않음
  • 복잡한 구조의 경우 class 또는 srtructure를 고려해야 함

Options #

  • 값이 없을 수도 있는 상황에서 사용
  • optional은 2가지를 의미
    • 값이 특정 타입이어서 해당 값에 접근하기 위해 optioanl은 unwrap
    • 값이 아예 없는 경우
let possibleNumber = "123"
let convertedNumber = Int(possibleNumber)
// convertedNumber is "Optional Int"
  • 하지만 이 코드는 실패, possibleNumber가 Optional로 선언되지 않았기 때문
  • Optional 타입은 optional을 포함하고 있는 타입의 변수명 뒤에 ?를 붙여야함

nil #

  • 값없음 상태는 특별한 값인 nil을 할당하여 optional value에 설정
var serverResponseCode: Int? = 404
serverResponseCode = nil
  • 처음 Optional 타입 선언 시 값을 정해주지 않으면 기본값으로 nil이 들어감
var surveyAnswer: String?
// surveyAnswer is automatically set to nil
  • nil과의 비교 조건문을 통해 해당 optional variable이 값을 가지고 있는지 확인
  • non optional type에서는 nil을 사용 불가

Optional Binding #

  • optional 타입이 값을 가지고 있는지 확인할 때 사용
  • 사용가능하다면 임시 상수 또는 변수로서 사용 가능한 변수를 만들기 위해 optional binding 사용
  • if또는 while문을 옵셔널 안의 값의 확인을 위해 사을
  • 이후 single action의 부분으로서 변수 또는 상수값으로 추출
if let actualNumber = Int(possibleNumber) {
    print("The string \"\(possibleNumber)\" has an integer value of \(actualNumber)")
} else {
    print("The string \"\(possibleNumber)\" couldn't be converted to an integer")
}
// Prints "The string "123" has an integer value of 123".
  • 위의 코드는 optional type이 unwrap이 되어 정상 할당 되었는지를 조건으로 봄
let myNumber = Int(possibleNumber)
// Here, myNumber is an optional integer
if let myNumber = myNumber {
    // Here, myNumber is a non-optional integer
    print("My number is \(myNumber)")
}
// Prints "My number is 123".
  • 위 코드도 마찬가지로 myNumber라는 상수에 nil이 아니라면 정상 할당될 것이므로 optional 안에 값이 있는지 확인할 수 있음
if let firstNumber = Int("4"), let secondNumber = Int("42"), firstNumber < secondNumber && secondNumber < 100 {
    print("\(firstNumber) < \(secondNumber) < 100")
}
// Prints "4 < 42 < 100".


if let firstNumber = Int("4") {
    if let secondNumber = Int("42") {
        if firstNumber < secondNumber && secondNumber < 100 {
            print("\(firstNumber) < \(secondNumber) < 100")
        }
    }
}
// Prints "4 < 42 < 100".

Providing a Fallback Value #

  • nil-coalescing operator(??)를 이용하여 기본 값을 주는 것은 missing value를 다루는 또 다른 방법
let name: String? = nil
let greeting = "Hello, " + (name ?? "friend") + "!"
print(greeting)
// Prints "Hello, friend!"
  • name이 nil이 아니라면 name을 선택, name이 nil이라면 firend가 선택됨

Force Unwrapping #

  • nil이 corrupted state or programmer error와 같은 unrecoverable failrue를 표헌할 때 !를 optionals 이름의 끝에 추가하여 그 값에 접근 가능
  • 이것을 optional value의 force unwrapping라 함
  • non-nil 값을 unwrap할 때는 unwrapped된 값이 리턴
  • nil값을 force unwrap할 때는 런타임 에러 발생
  • !는 `fatalError(:file:line:)의 shorter spelling
let possibleNumber = "123"
let convertedNumber = Int(possibleNumber)

let number = convertedNumber!

guard let number = convertedNumber else {
    fatalError("The number was invalid")
}

Implicitly Unwrapped Optionals (암시적 추출 옵셔널) #

  • 초기 설정 직후, 이후 생애 동안 값이 항상 존재한다고 보장될 때만 사용(String!).
  • 사용 시 매번 언래핑 없이 비옵셔널처럼 접근 가능. 단, nil이면 런타임 에러.
  • 나중에 nil 가능성이 있으면 String?로 유지하고 바인딩 사용.
let possibleString: String? = "optional"
let forced: String = possibleString! // 명시적 강제 언래핑

let assumed: String! = "implicitly unwrapped"
let auto: String = assumed            // 자동 언래핑

let stillOptional = assumed           // 타입: String?
if assumed != nil {
    print(assumed!)                   // 안전 확인 후 강제 언래핑
}
if let definite = assumed {
    print(definite)                   // 바인딩으로 안전하게 사용
}

Memory Safety 한눈에 #

  • 확정 초기화: 값을 읽기 전에 반드시 초기화.
  • 경계 안전: 배열/버퍼는 유효 인덱스만 접근.
  • 수명 안전: 값의 생애 동안만 메모리 접근(해제 후 사용 금지).
  • 겹치는 접근은 증명 가능한 경우에만 허용(동시성 데이터 레이스 방지).
  • 이름에 unsafe, unchecked, unmanaged가 포함된 API 사용 시 안전 책임은 개발자에게 있음.

Error Handling 기초 #

  • 실패 원인을 전달·전파하기 위해 throws/try/do-catch 사용.
  • 옵셔널은 “값 유무”만 전달하는 반면, 오류 처리는 “실패 이유”를 표현.
enum SandwichError: Error {
    case outOfCleanDishes
    case missingIngredients([String])
}

func makeASandwich() throws {
    // 상황에 따라 오류를 던질 수 있음
}

do {
    try makeASandwich()
    // 성공 시 진행
} catch SandwichError.outOfCleanDishes {
    // 설거지 실행
} catch SandwichError.missingIngredients(let items) {
    // 재료 구매
} catch {
    // 기타 오류 처리
}

Assertions와 Preconditions #

  • 공통: 런타임 검증. 거짓이면 즉시 종료(복구 불가한 잘못된 상태).
  • Assertions: 디버그 빌드에서만 평가 → 개발 중 가정 검증에 적합.
  • Preconditions: 디버그/프로덕션 모두 평가 → 반드시 참이어야 하는 전제 확인.
  • 최적화 -Ounchecked에선 precondition 미검증. fatalError는 항상 종료.
let age = -3
assert(age >= 0, "나이는 음수가 될 수 없습니다.") // 디버그에서만 평가

if age < 0 {
    assertionFailure("잘못된 상태 감지")
}

let index = 1
precondition(index > 0, "Index must be greater than zero.") // 프로덕션에서도 평가

// 미구현 스텁
func todo() -> Never {
    fatalError("Unimplemented")
}