@TaskLocal

2025. 3. 22. 22:39·iOS/Swift Concurrency
반응형

👋 들어가기 전

정말 오랜만에 컨커린시 관련 포스팅이다.

최근에 현생이 정말 정신이 없다.

주말은 쉬는 날인데 현재는 평일에 없는 학습시간을 위한 날인 것 같다.

정말 침대에 눕고 싶다. ㅋㅋㅋ 

 

잡소리는 그만하고 오늘의 주제로 들어가기 전 간단한 사전 지식을 알아보자.


✊@property wrapper

프로퍼티 래퍼 정말 무의식적으로 많이 썼고 특히, SwiftUI를 사용할 때
많이 쓴 것 같다.

 

한번 구조를 간단하게 정리해보자.

전체적인 내용인 출처 첫번 째 링크를 참고했다.

목적

프로퍼티 래퍼의 목적은 반복적인 로직을 담당하는 하나의 타입처럼 선언하여

프로퍼티의 타입처럼 쉽게 사용할 수 있게 만들어주는 것이다.

구조

property wrapper는 크게 2가지 프로퍼티를 제공한다.

wrappedValue 

wrappedValue는 가장 핵심적인 프로퍼티이며 필수 구현 프로퍼티다.

위에서 말한 반복적인 로직을 이곳에서 처리한다.

projectedValue

추가적인 로직이 필요할 때 사용하므로  구현 여부는 옵셔널이다.

사용할 때는 변수에 $를 붙혀 사용한다.

예

예는 String 값의 시작 값을 대문자로 변환해주고

upperCase를 projectedValue로 제공해주는 형태의 프로퍼티 래퍼를 만들어보자.

import Foundation

@propertyWrapper
struct Capitalized {
  private var _value: String = ""

  var wrappedValue: String {
    get {
      return _value.capitalized
    }

    set {
      _value = newValue
    }
  }

  var projectedValue: String {
    return _value.uppercased()
  }

  init(_ value: String = "") {
    self._value = value
  }
}

struct Person {
  @Capitalized var engName: String

  func sayHello() {
    print("Hello, my name is \(engName)")
    print("Hello, my name is \(_engName)")
  }
}

var p = Person()
p.engName = "abcde"
print(p.engName) //Abcde
print(p.$engName) //ABCDE
p.sayHello()
// Hello, my name is Abcde
// Hello, my name is Capitalized(_value: "abcde")

 

여기서 보면 sayHello 함수에서 만들지 않은 _engName 변수가 있다.

이건 propertywrapper로 만든 Capitalized로 접근할 수 있도록 변수 앞에 _를 붙혀 제공한다.


☝️구조 및 정의

구조

오늘의 주제인 @TaskLocal을 들어가기전 프로퍼티 래퍼에 대해 알아봤다.

 

왜냐하면 형태를 보면 알겠지만 @TaskLocal 역시 프로퍼티 래퍼 형태로 사용된다.

 

구현 구조를 살펴보면 다음과 같이 프로퍼티 래퍼와 매우 비슷한 구조이다.

wrappedValued와 projectValue가 보인다.

정의

공식문서를 보면 특정 스코프에 바인딩되어 사용할 수 있는 value 키다.


✌️특징

Task 메타데이터에 포함된다.

우리는 자식 Task에게 Task 메타데이터가 상속되는 것을 알고 있다.

우선순위, 실행중인 엑터 등  메타 데이터에 @TaskLocal 값이 포함된다.

static 형태로 선언되야 한다.

문법적인 약속, 별도의 작업간 데이터 공유 없이 사용하기 위해 그런 듯

옵셔널 또는 기본 값을 선언해야한다.

옵셔널로 선언해주거나 옵셔널이 아니라면 기본 값을 부여해야한다.

값의 변경은 wrappedValue로 하지 않는다.

위에 구조를 보면 당연한거지만 get-only 이므로 wrappedValue 자체는 변경이 불가능하다.

값의 변경은 projectedValue를 이용한다.

값의 직접적인 변경은 할 수 없고 projectedValue의 withValue를 이용해서 현재 Task 바운더리에서

@TaskLocal 값을 일시적으로 변경한다.


👍 예제 코드

코드를 보고 출력 값을 예상해보자.

import Foundation

enum Level {
  case low
  case medium
  case high
}

class Game {
  @TaskLocal
  static var level: Level = .low

  func printLevel() async {
    print("현재 난이도는 \(Game.level) 입니다.")
  }
}


let game = Game()

Task {
  print("#1 location [첫번 째 Task] \(Game.$level.get())")
  print("------------------------------------")

  await Game.$level.withValue(.medium) {
    print("값 변경:  medium")
    print("#2 location [첫번 째 Task] \(Game.$level.get())")
    print("------------------------------------")

    Task {
      print("#3 location [두번 째 Task] \(Game.$level.get())")
      print("------------------------------------")
    }
  }
  print("첫번 째 값 변경 종료")
  print("#4 location [첫번 째 Task] \(Game.$level.get())")

  await Game.$level.withValue(.high) {
    print("값 변경: high")
    print("#5 location [첫번 째 Task] \(Game.$level.get())")
    print("------------------------------------")

    Task {
      print("#6 location [세번 째 Task] \(Game.$level.get())")
    }
  }
}

#1 location [첫번 째 Task] low
------------------------------------
값 변경:  medium
#2 location [첫번 째 Task] medium
------------------------------------
첫번 째 값 변경 종료
#4 location [첫번 째 Task] low
값 변경: high
#5 location [첫번 째 Task] high
------------------------------------
#3 location [두번 째 Task] medium
------------------------------------
#6 location [세번 째 Task] high

😀 목적

공통된 로직을 상태(예제로는 level)에 따라 전혀 다른 동작하게 컨트롤 하기위해 사용된다.

 

이 때 범위 제약적으로 컨트롤 한다는 중요한 특징을 기억하자.


출처

 

Property wrappers in Swift | Swift by Sundell

This week, let’s take a look at how Swift’s property wrappers work, and explore a few examples of situations in which they could be really useful.

www.swiftbysundell.com

 

 

TaskLocal | Apple Developer Documentation

Wrapper type that defines a task-local value key.

developer.apple.com

 

반응형

'iOS > Swift Concurrency' 카테고리의 다른 글

Actor  (0) 2025.05.08
컨커런시 문법 정리  (0) 2025.03.22
Task Cancellation  (0) 2024.10.27
구조적 동시성 (1)  (0) 2024.10.26
async await  (0) 2024.10.24
'iOS/Swift Concurrency' 카테고리의 다른 글
  • Actor
  • 컨커런시 문법 정리
  • Task Cancellation
  • 구조적 동시성 (1)
Hamp
Hamp
남들에게 보여주기 부끄러운 잡다한 글을 적어 나가는 자칭 기술 블로그입니다.
  • Hamp
    Hamp의 분리수거함
    Hamp
  • 전체
    오늘
    어제
    • 분류 전체보기 (329)
      • CS (30)
        • 객체지향 (2)
        • Network (7)
        • OS (6)
        • 자료구조 (1)
        • LiveStreaming (3)
        • 이미지 (1)
        • 잡다한 질문 정리 (0)
        • Hardware (2)
        • 이론 (6)
        • 컴퓨터 그래픽스 (0)
      • Firebase (3)
      • Programing Langauge (41)
        • swift (34)
        • python (6)
        • Kotlin (1)
      • iOS (134)
        • UIKit (37)
        • Combine (1)
        • SwiftUI (34)
        • Framework (7)
        • Swift Concurrency (22)
        • Tuist (6)
        • Setting (11)
        • Modularization (1)
        • Instruments (6)
      • PS (59)
        • 프로그래머스 (24)
        • 백준 (13)
        • LeetCode (19)
        • 알고리즘 (3)
      • Git (18)
        • 명령어 (4)
        • 이론 (2)
        • hooks (1)
        • config (2)
        • action (7)
      • Shell Script (2)
      • Linux (6)
        • 명령어 (5)
      • Spring (21)
        • 어노테이션 (6)
        • 튜토리얼 (14)
      • CI-CD (4)
      • Android (0)
        • Jetpack Compose (0)
      • AI (11)
        • 이론 (10)
        • MCP (1)
        • LangGraph (0)
  • 블로그 메뉴

    • 홈
    • 태그
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    dp
    boostcamp
    SwiftUI
    Swift
    Tuist
    dfs
    protocol
    Spring
    property
    dispatch
    IOS
    프로그래머스
    concurrency
    투포인터
    백준
    AVFoundation
    UIKit
    GIT
    lifecycle
    CS
  • 최근 댓글

  • 최근 글

  • 반응형
  • hELLO· Designed By정상우.v4.10.0
Hamp
@TaskLocal
상단으로

티스토리툴바