ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Swift 공식문서 톺아보기 (2) - 둘러보기 2
    Swift 2025. 6. 18. 17:20

    안녕하세요 :) 🧀

    지난 둘러보기 1에 이어서 Swift 공식문서 둘러보기(A Swift Tour) 섹션을 마무리 지어 보겠습니다.

     

    Swift 공식문서 톺아보기 (1) - 둘러보기 1

    안녕하세요 :) 🧀매년 초에 버킷 리스트를 작성할 때 빠지지 않고 등장했던 것 중 하나가 “개발 블로그 시작하기” 였는데, 드디어 시작을 하게 되었습니다.앞으로 블로그를 통해 iOS 개발 관련

    cheeseios.tistory.com


    🎯 Computed property의 newValue

    struct EquilateralTriangle {
      private var sideLength: Double = 0
      
      var perimeter: Double {
        get {
          return 3 * sideLength
        }
        set {
          sideLength = newValue / 3
          print("triangle.sideLength: \(sideLength)") // 10
        }
      }
    }
    
    var triangle = EquilateralTriangle()
    triangle.perimeter = 30
    
    print("triangle.perimeter: \(triangle.perimeter)") // 30

     

    Computed proerty set 블록 안에서 제공되는 newValue는 프로퍼티에 새로 할당된 값을 가리키는 매개변수입니다.

    기본적으로 이름을 지정하지 않으면 newValue라는 이름으로 사용할 수 있지만, 직접 이름을 지정해서 사용이 가능합니다.

    var perimeter: Double {
      get {
        return 3 * sideLength
      }
      set(myNewValue) {
        sideLength = myNewValue / 3
        print("triangle.sideLength: \(sideLength)") // 10
      }
    }

     

    위와 같이 set(지정된 이름) { ... } 형태로 작성하면, 임의의 이름으로 접근 가능해요!

    🎯 willSet·didSet의 newValue·oldValue

    private var sideLength: Double = 0 {
      willSet {
        print("곧 \(newValue)로 바뀔 예정") // 곧 10.0로 바뀔 예정
      }
      didSet {
        print("이전 값은 \(oldValue)") // 이전 값은 0.0
      }
    }
    
    // 직접 이름 지정하기
    willSet(myNewValue) { ... }
    didSet(myOldValue) { ... }

     

    Computed property의 willSet에서는 newValue로 바뀔 값을, didSet에서는 oldValue로 이전 값을 참조할 수 있습니다.

    마찬가지로 괄호 안에 원하는 이름을 지정해서 접근이 가능합니다.

    🎯 async let

    func loadData() async {
      let userID = await fetchUserID()
      let userName = await fetchUserName()
      print("ID: \(userID), name: \(userName)")
    }

     

    일반적인 async/await은 위와 같은 코드가 있을 때 fetchUserID(), fetchUserName()을 순차적으로 호출합니다.

    func loadData() async {
      async let userID = await fetchUserID()
      async let userName = await fetchUserName()
      
      // 두 작업이 동시에 시작됨
      let id   = await userID
      let name = await username
      print("ID: \(id), name: \(name)")
    }

     

    async let은 비동기 함수를 병렬(parallel)로 실행하고, 이후에 필요할 때 결과를 await로 받아옵니다.

    즉, fetchUserID(), fetchUserName()이 동시에 시작되고 준비된 결과부터 사용이 가능합니다.

    (작동원리나 더 자세히 알아볼 게 많아 보이지만 우선 둘러보기니까 여기까지..)

    🎯 TaskGroup

    위에서 본 async let은 병렬로 처리하는 방식입니다. TaskGroup도 마찬가지지만 목적과 제어하는 범위에서 차이가 있습니다.

    간략하게 설명하면 작업 수가 동적으로 바뀌거나, 완료된 순서대로 중간에 바로 처리한다거나, 에러가 발생하면 즉시 그룹 전체를 취소한다거나!

    group.addTask {
      await fetchUserID(from: server)
    }
    • addTask를 호출하는 순간 해당 child task가 실행 예약됩니다.
    • 여러 서버에 동시에 요청을 보내거나, 반복문 등으로 동적 개수의 비동기 작업을 생성할 때 특히 유용합니다.
    for await result in group {
      results.append(result)
    }
    • for await 루프는 작업이 완료된 순서대로 결과를 하나씩 꺼냅니다.
    • 모든 child task가 끝나면 루프가 종료됩니다.

    🎯 actor

    // 스레드에안전하지 않은 일반 클래스
    class UnsafeCounter {
      var value = 0
      
      func increment() {
        value += 1
      }
    }
    
    // 스레드에 안전한 actor
    actor SafeCounter {
      var value = 0
      
      func increment() {
        value += 1
      }
    }

     

    내부 상태에 대한 동시 접근을 자동으로 직렬화하여 스레드 안전을 보장하는 타입입니다.

    클래스와 유사하지만,

    • actor로 선언하면 내부의 프로퍼티와 메서드가 암묵적으로 격리(isolated)됩니다.
    • 동일한 인스턴스에 여러 비동기 메서드가 접근해도, Swift 런타임이 자동으로 직렬화(serialization) 처리해 줍니다.
    • actor 외부에서 actor의 프로퍼티나 메서드를 호출할 땐 await를 통해 안전하게 접근합니다.

    🎯 enum도 protocol을 채택한다.

    protocol Toggleable {
      mutating func toggle()
    }
    
    enum LightSwitch: Toggleable {
      case on
      case off
      
      mutating func toggle() {
        self = self == .on ? .off : .on
      }
    }

     

    LightSwitch라는 enum이 Toggleable 프로토콜을 채택하여 모든 스위치 타입에 대해 공통의 toggle() 기능을 제공합니다.

    class, struct 뿐만 아니라 enum도 프로토콜을 채택함으로써 일관된 인터페이스 제공, 재사용성, 확장성 등을 높일 수 있습니다.

    🎯 struct와 mutating

    struct SimpleStruct {
      var simpleDescription: String = "Hello, World!"
      
      func adjust() {
        simpleDescription += " (adjusted))"
      }
    }

     

    위 struct는 에러가 발생합니다.

    Left side of mutating operator isn't mutable: 'self' is immutable

    이유는 struct에서 메서드는 기본적으로 self가 불변(immutable)으로 취급되기 때문에, 내부 프로퍼티를 수정하려면 컴파일에 실패합니다.

    struct SimpleStruct {
      var simpleDescription: String = "Hello, World!"
      
      mutating func adjust() {
        simpleDescription += " (adjusted))"
      }
    }

     

    이렇게 func 키워드 앞에 mutating을 작성하면 self를 변경할 수 있음을 명시적으로 선언하여 내부 프로퍼티를 업데이트할 수 있게 됩니다. 요약하면 아래와 같습니다.

    • 값 타입인 struct는 기본적으로 인스턴스 메서드 내에서 self를 변경할 수 없습니다.
    • mutating 키워드를 붙여야 "이 메서드는 자기 자신을 변경할 것이다"라는 의도를 컴파일러에게 알려, 프로퍼티 수정이 허용됩니다.

     


    마치며

    이렇게 해서 간략하게 두 번에 나눠서 둘러보기가 마무리되었네요ㅎㅎ

    앞으로는 특정 주제에 맞춰 하나씩 상세하게 더 알아가 보도록 하겠습니다.

    참조

     

    Documentation

     

    docs.swift.org

Designed by Tistory.