Swift Doc 톺아보기 (1) - 기본

요나·2023년 5월 2일
0

Swift Doc 톺아보기

목록 보기
1/4

The Basics

이 글은 https://bbiguduk.gitbook.io/swift 에 나오는 스위프트 문법을 공부하면서 새롭게 알게 된 지식들을 정리한 포스팅입니다.


상수와 변수 (Constants and Variables)

  • 코드에서 저장한 값이 변경되지 않는 값이라면, 무조건 let 키워드로 상수로 설정하는 것이 좋다.
  • 일단 let으로 설정하고 바꾸어야 할 때 로 var로 바꾸기를 습관화하자.
  • 중요한 건 아니지만, 상수는 설정(set)한다고 하고, 변수는 초기화(initialize)한다고 한다.
  • 여러 개의 변수나 상수 동시 선언 가능하다.
    var x = 0.0, y = 0.0, z = 0.0

타입 명시 (Type Annotations)

  • 타입 명시할 때는 공백 한 칸 꼭 쓰기.
  • 같은 타입의 변수 동시 선언 가능하다.
    var red, green, blue: Double

정수 (Integers)

  • 정수는 부호가 있는 정수(signed: 양수, 0, 음수)와 부호 없는 정수(unsigned: 양수, 0)으로 나뉜다.
  • 정수는 8, 16, 32, 64-bit의 signed와 unsigned가 있으며, UInt8, Int8 등의 타입명을 가진다.
  • 정수 타입은 minmax 프로퍼티를 가진다.
    let minValUInt8 = UInt8.min // 0
    let maxValUInt8 = UInt8.max // 255
    
    let minValInt8 = Int8.min // -128
    let maxValInt8 = Int8.max // 127
  • Int의 사이즈는 시스템의 플랫폼에 따라서 바뀐다. (64-bit에서 Int.max == Int64.max)
  • UInt는 왠만하면 unsigned 정수값이 필요한 경우에만 사용하도록 하자. (→ 타입 추론에 용이)

부동 소수점 숫자 (Floating-Point Numbers)

  • Float은 32-bit 부동 소수점, Double은 64-bit 부동 소수점 숫자를 표기한다.
  • Float은 최소 6자리, Double은 최소 15자리의 정확성을 가진다.
  • 당연하게도(?) 부동 소수점 숫자는 maxmin 프로퍼티를 가지지 않는다.

타입 안정성과 타입 추론 (Type Safety and Type Inference)

  • Swift는 타입 세이프하기 때문에, 컴파일 단계에서 타입 오류를 잡아낸다.
  • 타입 추론 덕분에 변수에 리터럴 값(literal value) 혹은 리터럴(literal)을 지정할 수 있다.
  • 정수와 부동소수 리터럴을 결합하면 Double 타입으로 유추된다.
    let pi = 3 + 0.14159 // Double.Type
  • 타입 명시는 변수 선언만 해도 사용 가능한 반면, 타입 추론은 초기값을 지정해주어야만 사용 가능.
    let typeAnnotation: String // 가능
    let typeInferece = "" // 가능
    let typeInferece // 불가능
  • 일반적으로 더 큰 타입으로 추론된다.
    let wantToBeFloat = 10.0
    type(of: wantToBeFloat) // Double
    
    let wantToBeCharacter = "C"
    type(of: wantToBeCharacter) // String

숫자 리터럴

  • 정수 리터럴 4가지.
    let decimalInteger = 17
    let binaryInteger = 0b10001
    let octalInteger = 0o21 
    let hexadecimalInteger = 0x11
  • 1.25e2 는 1.25 x 10², 또는 125.0 , 1.25e-2 는 1.25 x 10⁻² , 또는 0.0125
  • 각 숫자 리터럴은 가독성을 위한 추가 포맷을 포함할 수 있다.
    let paddedDouble = 000123.456
    let oneMillion = 1_000_000.000_000

숫자 타입 변환 (Numeric Type Conversion)

  • 정수 간 변환
    • 각 숫자 타입이 저장 가능한 범위를 벗어나면 컴파일 오류가 발생한다.
    • UInt 타입으로 음수를 저장하거나, max, min 값을 넘기는 경우가 대표적이다.
  • 정수와 부동 소수점 간 변환
    • 정수와 부동 소수점 변수와 상수 간의 타입의 변환은 명시적이어야 한다.

    • 리터럴 값은 명시적인 타입이 없기 때문에 특별히 형변환이 필요하지 않다.

      // 변수/상수
      let three = 3
      let point = 0.14159
      let pi = Double(three) + point
      
      // 리터럴
      let pi = 3 + 0.14159
    • 부동 소수점 값을 정수 타입으로 변환하면(Int(pi)), 소수점 아래는 버린다.

타입 별칭 (Type Aliases)

  • 타입 별칭으로 이미 존재하는 타입을 다른 이름으로 바꿔 정의할 수 있다.
    • 특정 크기의 데이터로 작업할 때 유용하다.

      typealias AudioSample = UInt16
      var maxAmplitudeFound = AudioSample.min // 0

튜플 (Tuples)

  • 튜플은 여러 값을 단일 복합 값으로 그룹화한다.
    • 모든 타입이 가능하며, 서로 같은 타입일 필요도 없고 원하는 만큼 타입을 포함할 수 있다.

    • 튜플의 내용을 별도의 상수로 분해(Decompose)할 수 있다.

      let http404Error = (404, "Not Found") // (Int, String)
      
      let (statusCode, statusMessage) = http404Error
      let (statusCodeOnly, _) = http404Error
  • 0에서 시작하는 인덱스를 통하여 튜플의 Element들에 접근할 수 있다.
    http404Error.0 // 404
    http404Error.1 // Not Found
  • 튜플 정의할 때 각 Element들에 이름을 정할 수 있고, 이를 통해 접근할 수도 있다.
    let http200Status = (statusCode: 200, description: "OK")
    
    http200Status.statusCode // 200
    http200Status.description // "OK"
  • 튜플은 함수의 반환 값으로 사용할 때 특히 유용하다.
  • 튜플은 관련된 값들의 간단한 그룹들을 만드는 데 유용하지 복잡한 데이터 구조와는 맞지 않는다.
    • 복잡한 구조일 경우에는 클레스나 구조체를 사용하는 것이 좋다.

옵셔널 (Optionals)

  • 옵셔널의 두 가지 가능성
    1. 값이 있을 가능성 → 값을 풀어서(Unwrap) 값에 접근 가능
    2. 값이 없을 가능성 → nil
  • 옵셔널은 ‘어떠한 타입에 대하여 값이 없음’을 나타낼 수 있다.
    • 예로, Int()String 타입을 Int 타입으로 반환하지만 문자가 포함된 경우는 불가능하다.

    • nil 반환 가능성이 있기 때문에, Optional 값을 반환한다. (즉 Int 이거나, 아무런 값도 없다.)

      let possibleNumber = "123"
      let convertedNumber = Int(possibleNumber) // Optional(123)
      
      let convertedNumber: Int = Int(possibleNumber) // 에러 발생
      let convertedNumber: Int? = Int(possibleNumber) // 사실 위는 타입추론 된 것이다

nil

  • Optional 타입 변수에 nil을 할당할 수 있다.
    var serverResponseCode: Int? = 404
    serverResponseCode = nil // Int 타입으로 바꾸면 에러 발생
  • 초기값이 할당되지 않은 Optional 변수는 nil이 자동할당 된다.
    var optionalString: String? // nil
  • Swift의 nil은 Object-C의 nil과 다르다.
    • Object-C: 존재하지 않는 객체에 대한 포인터
    • Swift: 특정 타입의 값이 없음(→ 정확히는 없을 가능성)을 나타내며 포인터 아님

If 구문과 강제 언래핑 (If Statements and Forced Unwrapping)

  • if 구문으로 옵셔널과 nil을 비교할 수 있다.
  • 비교하는 것만으로는 언래핑되지 않기 때문에 강제 언래핑해야한다.
    • 값이 반드시 들어있을 경우에만 사용해야 하므로 if 구문 스코프 내에서 쓰는 것이 좋다.

      if convertedNumber != nil {
      	print("\(convertedNumber!)")
      }

옵셔널 바인딩 (Optional Binding)

  • **Optional변수(우측항)가 값을 포함하고 있는지 확인하여 임시 상수나 변수(좌측항)**으로 사용한다.
    • 일반적으로 사용하는 let 뿐 아니라 var도 사용 가능하다. (스코프 내에서만 적용됨)

      let optionalString: String? = "Not Optional"
      if var strValue = optionalString {
          print(strValue) // Not Optional
      } else {
          print("nilkaboo")
      }
  • 옵셔널 바인딩하는 스코프에서 옵셔널 변수를 사용하지 않아도 되면 같은 이름으로 선언해도 무방하다.
    let myNumber = Int("123")
    
    if let myNumber = myNumber {
        print(myNumber) // 123
    }
    
    print(myNumber) // Optional(123)
  • 이를 더욱 간단하게 표현하여 할당을 생략할 수 있다.
    • 언래핑할 상수/변수의 이름만 작성하면 암시적으로 같은 이름의 언래핑된 상수가 만들어진다.

      if let myNumber {
      		print(myNumber)
      }
  • if 구문에 쉽표로 복수 바인딩이나 조건식을 부여할 수 있다.
    • nil 값이 존재하거나 조건식이 false이면 전체 구문이 false가 된다.

      if let firstNumber = Int("27") {
          if let secondNumber = Int("72") {
              if firstNumber < secondNumber && firstNumber + secondNumber < 100 {
                  print(firstNumber + secondNumber) // 99
              }
          }
      }
      
      if let firstNumber = Int("27"),
         let secondNumber = Int("72"),
         firstNumber < secondNumber,
         firstNumber + secondNumber < 100 {
          print(firstNumber + secondNumber) // 99
      }

암시적으로 언래핑 된 옵셔널 (Implicitly Unwrapped Optionals)

  • 직접 Optional 상수/변수에 특정 타입의 값을 지정했을 경우 매번 언래핑하여 사용하는 것은 비효율적.
  • IUO는 내부적으로 옵셔널이지만, 옵셔널이 아닌 값과 동일하게 사용 가능하다.
    • 명시적으로 옵셔널이 아닌 타입의 상수/변수에 담으려고 하면 강제로 언래핑된다.

    • 옵셔널 타입 상수/변수에 담으면 강제 언래핑되지 않고 옵셔널 타입이 된다.

      let possibleString: String? = "optional string"
      let forcedString: String = possibleString!
      
      let assumedString: String! = "implicitly unwrapped optional string"
      let implicitString: String = assumedString // 이때 강제 언래핑
      
      let optionalString: String = assumedString // Optional("...")
  • IUO 변수 안에 nil 값이 들어 있을 경우 접근하면 (컴파일 에러가 아닌) 런타임 에러가 발생한다.
    • 만약 나중에 변수 수명 중 nil이 될 가능성이 조금이라도 있다면 IUO 사용하면 안 된다.
  • IUO는 기본적으로 옵셔널로 취급되기 때문에 if 구문에서 nil 체크도, 옵셔널 바인딩도 가능하다.
    • nil 체크 시 비교연산 하면서 옵셔널로 확정되어 if 스코프 안에서는 다시 옵셔널로 래핑된다.

      if assumedString != nil {
      	print(assumedString!) // 언래핑 안 하면 Optional("...")로 나온다.
      }
      
      if let definiteString = assumedString {
      	print(definiteString)
      }

에러 처리 (Error Handling)

  • 에러가 발생할 수 있는 함수는 선언 부에 throws 키워드를 포함해야 한다.
    • 그 함수를 호출할 때는 표현식 앞에 try 키워드가 있어야 한다.

      func canThrowAnError() throws {
      	// ...
      }
      
      do {
      	try canThrowAnError()
      	// no error zone
      } catch {
      	// error thrown
      }

역설과 전제조건 (Assertions and Preconditions)

  • Assertion: 개발 단계에서 디버그 빌드 시에만 동작하며, 복구 불가능한 에러를 표기할 때 사용한다.
  • Precondition: 기능적으로는 Assertion과 유사하지만, 디버깅과 프로덕션 빌드 양쪽에 사용한다.
profile
var yona = IOSDeveloper(stage: 0)

0개의 댓글