Task Cancellation

2024. 10. 27. 14:43·iOS/Swift Concurrency
반응형

이전과 차이점

기존 GCD를 이용했을 때는 작업을 취소하기가 거의 불가능했거나 많이 번거로웠다.

하지만 Swift Concurrency에서는 작업의 취소가 굉장히 편해졌다.

 

이번 포스팅부터는 컨커런시에서 취소하는 법 정확히는 취소를 전파하고 그 취소에 대한 핸들링하는 법을 알아보자. 

 

종류

1. 명시적 취소

cancel() 메서드를 통해 자식 작업들에게 취소를 전파

2. 암시적 취소

자식 작업에서 에러가 발생했을 때


특징

1. 작업 취소가 가능한 구조는 다음과 같다.

  • 동일한 context , Task 안의 Task 또는 Task.detached는 해당되지 않음
  • 구조적 동시성 구조 ,  async let or TaskGroup

2. 작업의 취소는 즉각 취소가 아닌 취소되었음을 알리는 행위다.

  • task.canecl()을 통해 Task.isCancelled 속성을 true로 변경시킨다.
  • Task.isCancelled 속성을 통해 작업이 취소 되었는 지 알려준다.
let task = Task(priority: .medium) {
    sleep(1)
    let datas = await multiFetchDatas()
    
}

sleep(6)
task.cancel() // 6 초후 Task.isCancelled 값을 true로 전파

 

3. 실제로 작업 취소를 하려면 별도의 처리가 필요하다.

  • 취소 되기전에 해야할 행동 역 Error를 던지기전에 처리한다.
  • 이 때 던지는 에러는 CancellationError으로 많이 쓴다.
  • 커스텀 에러를 던져도 된다. 
func asyncFetchData() async throws -> Data {
    
	print("실행")
    guard Task.isCancelled  else {
        print("취소됨")
        // 취소되기전 할 작업이 있다면 ..
        throw CancellationError() // 또는 커스텀 에러
    }
  	...  
 }
  • 위 처럼 guard와 CancellationError를 쓰기 귀찮고 취소되면 바로 Error를 리턴하고 싶으면 Task.checkCancellation()을 사용
func asyncFetchData() async throws -> Data {
    
	print("실행")
	 try Task.checkCancellation() // Task.isCancelled가 true가 되면 바로 Error 리턴
  	...  
 }

4. 한번 취소된 작업은 다시 재개될 수 없다.

5. 취소된 것까지의 작업 결과를 사용하기 위해서는 Error 보단 nil을 이용

  • 작업이 취소될 때 위른 Error를 던져 위에 알렸지만 지금까지 한 작업의 결과가 필요하다면 옵셔널을 이용하자.
  • try? 와 옵셔널 바인딩을 이용해서 작업이 취소되면 nil이 오는 특징을 살려 끝난 결과만이라도 살릴 수 있다.
func multiFetchDataWithTaskGroup() async -> [Data?] {
    
    return await withTaskGroup(of: Data?.self, returning: [Data?].self) { group in
        
        for _ in 0..<3 {
            group.addTask(priority: .background) {
                return try? await asyncFetchData() // Error일 경우 nil
            }
        }
        
        var result: [Data?] = []
        
        for await data in group {
            if let data  { // nil이 아닐 때만 append
                result.append(data)
            }
            
        }
        return result
    }
}

실제 사례

SwiftUI task 메서드

Adds an asynchronous task to perform before this view appears.
nonisolated
func task(
    priority: TaskPriority = .userInitiated,
    _ action: @escaping () async -> Void
) -> some View
  • swiftUI에서 onAppear 때 비동기 context를 사용할 때 보통 Task {}를 이용했었다.
}.onAppear {
    Task {
        // do SomeThing
    }
}
  • 하지만 task 메서드를 통해 더 쉽고 효율적으로 사용할 수 있다.
.task(priority: <#T##TaskPriority#>) { 
 	// doSomething
}
  • 여기서 task 메서드의 가장큰 장점은 별도의 취소를 안해도 화면이 사라지면 알아서 취소를 해준다는 점

취소 핸들러

개요

위 그림을 통해 보면 상위 작업 또는 계층에서 아래의 작업이 Error를 던져주기 전까지는 작업이 끝나지 않고 있다.

 

취소 핸들러를 이용하면 작업이 취소되는 즉시 감지할고 동작할 수 있게 도와주는 녀석이 있는데

바로 그게 취소핸들러다.

정의

execute an operation with a cancellation handler that’s immediately invoked if the current task is canceled.

 

현재 작업이 취소되자마자 즉시 실행되는 핸들러

func withTaskCancellationHandler<T>(
    operation: () async throws -> T, // 비동기 또는 동기 코드 
    onCancel handler: () -> Void, // 즉시 동작할 핸들러
    isolation: isolated (any Actor)? = #isolation
) async rethrows -> T

특징

  • 현재 작업이 취소되자마자 즉시 실행됨
  • 하위 작업에서 Error가 전달될 때까지 기다리지 않고 바로 실행됨

예제 코드

let value = await withTaskCancellationHandler {
    try? await Task.sleep(for: .seconds(3))
    return 1
} onCancel: {
    print("핸들러 코드")
}

 


참고

 

task(priority:_:) | Apple Developer Documentation

Adds an asynchronous task to perform before this view appears.

developer.apple.com

 

 

withTaskCancellationHandler(operation:onCancel:isolation:) | Apple Developer Documentation

Execute an operation with a cancellation handler that’s immediately invoked if the current task is canceled.

developer.apple.com

 

 

withTaskCancellationHandler(handler:operation:) | Apple Developer Documentation

There's never been a better time to develop for Apple platforms.

developer.apple.com

 

반응형

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

컨커런시 문법 정리  (0) 2025.03.22
@TaskLocal  (1) 2025.03.22
구조적 동시성 (1)  (0) 2024.10.26
async await  (0) 2024.10.24
swift concurrency 등장배경  (0) 2024.10.24
'iOS/Swift Concurrency' 카테고리의 다른 글
  • 컨커런시 문법 정리
  • @TaskLocal
  • 구조적 동시성 (1)
  • async await
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)
  • 블로그 메뉴

    • 홈
    • 태그
  • 링크

  • 공지사항

  • 인기 글

  • 태그

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

  • 최근 글

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

티스토리툴바