Operation & OperationQueue 정리

Ios_Roy·2025년 8월 22일
0

TIL

목록 보기
21/25
post-thumbnail

Operation & OperationQueue 핵심 정리

Swift (Foundation)의 OperationOperationQueue는 더 높은 수준의 비동기 작업 제어를 위한 도구입니다.
GCD 기반 작업과 달리, 캡슐화, 의존성, 취소(cancellation), 상태 추적 등이 구조적으로 제공됩니다.


Operation

  • single task에 관한 데이터와 코드를 나타내는 추상 클래스
  • 해당 클래스를 서브클래싱하여 사용하면 안정적으로 task를 실행시킬 수 있는 효과 존재

직역 하자면
Operation 클래스는 추상 클래스이기 때문에 직접 사용하지 않고 서브 클래스를 사용하거나 시스템 정의 하위 클래스(NSInvocationOperation 또는 BlockOperation) 중 하나를 사용하여 실제 작업을 수행합니다. 추상적임에도 불구하고, Operation의 기본 구현에는 작업의 안전한 실행을 조정하기 위한 중요한 논리가 포함되어 있습니다. 이 내장 논리의 존재는 다른 시스템 개체와 올바르게 작동하는지 확인하는 데 필요한 접착제 코드보다는 작업의 실제 구현에 집중할 수 있습니다.

작업 객체는 싱글 샷 객체입니다. 즉, 작업을 한 번 실행하고 다시 실행하는 데 사용할 수 없습니다. 일반적으로 작업을 작업 대기열(OperationQueue 클래스의 인스턴스)에 추가하여 작업을 실행합니다. 작업 대기열은 보조 스레드에서 직접 실행하거나 libdispatch 라이브러리(Grand Central Dispatch라고도 함)를 사용하여 간접적으로 작업을 실행합니다. 대기열이 작업을 실행하는 방법에 대한 자세한 내용은 OperationQueue를 참조하십시오.

작업 대기열을 사용하고 싶지 않다면, 코드에서 직접 start() 메서드를 호출하여 직접 작업을 실행할 수 있습니다. 작업을 수동으로 실행하는 것은 준비 상태가 아닌 작업을 시작하면 예외가 발생하기 때문에 코드에 더 많은 부담을 줍니다. isReady 속성은 작업 준비 상태를 보고합니다.

OperationQueue

  • Operation 객체들을 priority에 의해서 실행시키는 queue
  • operation queue에 Opertaion 객체를 담아놓으면 task가 끝날때까지 queue가 없어지지 않고 존재
  • 해당 queue에서 Operation들을 삭제하거나 명령시킬 수 있는 장점이 존재 (task관리에 이점)

작업 대기열은 우선 순위와 준비 상태에 따라 대기열에 있는 작업 객체를 호출합니다. 대기열에 작업을 추가한 후에는 작업이 작업을 완료할 때까지 대기열에 남아 있습니다. 작업을 추가한 후에는 대기열에서 직접 제거할 수 없습니다.

핵심 개념

1. 기능 캡슐화 & 모듈성

  • Operation을 서브클래싱하거나 클로저 기반 BlockOperation을 사용함으로써 하나의 작업(task)을 명확하게 캡슐화할 수 있음
  • 모듈화된 단위로 만들면 재사용성, 테스트 용이성, 책임 분리 모두 향상

2. 상태 추적 & 실행 제어

  • Operation은 다음과 같이 명확한 상태(Status) 를 제공합니다:
    • .isReady
    • .isExecuting
    • .isFinished
    • .isCancelled
  • 이러한 상태를 통해:
    • 작업의 실행/대기/취소 등을 세밀히 제어할 수
    • 실행 흐름을 코딩 로직이 아닌 OperationQueue에 위임 가능

3. 종속성 & 순서 지정

  • operation.addDependency(otherOperation) 으로 선행 작업 후행 작업으로 순서를 지정할 수 있음
  • OperationQueue는 이 종속성을 자동으로 해석하여 실행 순서를 관리

4. 취소(Cancellation)

  • operation.cancel() 호출로 작업 취소를 요청
  • .isCancelled 상태는 작업이 Pending, Ready, Executing 상태에 있을 때만 넘어올 수 있음
  • 취소 후 자동으로 .isFinished 상태로 전이됨
  • 작업 중 isCancelled 체크하여, 가능한 빨리 종료할 수 있도록 구현 필요

5. 상태(State) 흐름 요약

Pending (큐 대기) ---> Ready (실행 조건 만족)
       ⇓                         ⇓
    Cancelled? ---------------> Executing (start() 호출)
                                        ⇓
                                  Finished (작업 완료)
  • Pending: OperationQueue에 추가된 상태
  • Ready: 실행 조건(대기, 의존성 등)이 완료되어 실행 준비 완료
  • Executing: 실제 작업 수행 중 (start() 실행)
  • Finished: 작업이 끝나고 Queue에서 제거된 상태
  • Cancelled: 어느 단계에서든 취소 시도, 곧바로 Finished로 전이

6. 책임 분리 & 진행 추적

  • Operation은 자신이 수행할 단일 책임(single responsibility) 만 가짐
  • Progress API 또는 커스텀 상태 제공을 통해 작업 진행 상황 추적 가능
  • 예: 다운로드 → 데이터 처리 → UI 업데이트 작업을 각각 Operation으로 분리

GCD vs Operation

Swift에서 비동기 작업을 수행하는 대표적인 두 가지 방법은 GCD(Grand Central Dispatch)Operation / OperationQueue 입니다.
Operation은 내부적으로 GCD를 활용하며, 더 높은 수준의 추상화와 기능(종속성, 취소 등)을 제공합니다.


GCD vs Operation 비교

구분GCDOperation / OperationQueue
정의동시에 실행될 작업 단위(closure) 를 큐에 제출Operation 객체로 작업을 캡슐화
종속성종속성 설정 불가 (A 후에 B 보장 어려움).addDependency() 로 작업 간 순서 보장 가능
재사용성Closure 중심 → 재사용 어려움클래스 서브클래싱 / BlockOperation 으로 모듈화 가능
취소취소 불가cancel() 로 취소 가능
상태 추적작업 상태 추적 불가.isReady, .isExecuting, .isFinished, .isCancelled 로 상태 확인 가능
모듈화코드 블록 단위 실행Operation 클래스로 기능 캡슐화 가능

🛠️ Operation 사용 방법

1. Operation 서브클래싱

  • Operation을 subclassing → main() 오버라이드
  • main() : setup + 작업 실행, 반드시 super.main() 호출 금지
  • start() : 스레드 생성 또는 비동기 작업 호출 시작
    • 실행 상태 변경을 KVO(Key-Value Observing) 로 알림
  • 주요 프로퍼티:
    • isAsynchronous
    • isExecuting
    • isFinished
    • isCancelled

2. BlockOperation (단순 사용법)

let blockOperation = BlockOperation {
    print("Executing!")
}

let queue = OperationQueue()
queue.addOperation(blockOperation)

📦 Operation 모듈화 예시

final class ContentImportOperation: Operation {

    let itemProvider: NSItemProvider

    init(itemProvider: NSItemProvider) {
        self.itemProvider = itemProvider
        super.init()
    }

    override func main() {
        guard !isCancelled else { return }
        print("(main) Importing content...")
        
        // .. import the content using the item provider
    }
}

let queue = OperationQueue()

let fileURL = URL(fileURLWithPath: "..")
let contentImportOperation = ContentImportOperation(itemProvider: NSItemProvider(contentsOf: fileURL)!)

contentImportOperation.completionBlock = {
    print("Importing completed!")
}

queue.addOperation(contentImportOperation)

// 출력 예시:
// (main) Importing content...
// Importing completed!

⚠️ 주의: Operation 인스턴스는 한 번만 실행 가능
(완료 or 취소된 이후에는 동일 인스턴스를 다시 실행할 수 없음)


🔗 Dependency (종속성)

B 작업은 A 작업이 끝난 뒤 실행되도록 종속성 설정 가능:

let fileURL = URL(fileURLWithPath: "..")
let contentImportOperation = ContentImportOperation(itemProvider: NSItemProvider(contentsOf: fileURL)!)
contentImportOperation.completionBlock = {
    print("Importing completed!")
}

let contentUploadOperation = ContentUploadOperation(itemProvider: NSItemProvider(contentsOf: fileURL)!)
contentUploadOperation.addDependency(contentImportOperation)
contentUploadOperation.completionBlock = {
    print("Uploading completed!")
}

queue.addOperations([contentImportOperation, contentUploadOperation], waitUntilFinished: true)

// 출력 예시:
// (main) Importing content...
// (main) Uploading content...
// Importing completed!
// Uploading completed!

✅ 요약

  • Operation 서브클래싱 또는 BlockOperation으로 작업 캡슐화
  • .addDependency()로 작업 순서 정의
  • cancel() 호출 처리 & isCancelled 체크 구현
  • 상태(isReady, isExecuting, isFinished, isCancelled) 추적 가능한 구조 설계
  • OperationQueue에 작업 추가 및 동시성 조절 (예: maxConcurrentOperationCount`)
  • Progress 또는 커스텀 상태 로깅으로 진행 상황 시각화
  • GCD: 단순하고 가볍게 비동기 실행
  • Operation: 모듈화 + 상태 관리 + 종속성 제어 + 취소 지원
  • 따라서 복잡한 작업 흐름 제어가 필요할 때는 Operation, 간단한 비동기 실행에는 GCD 가 적합
  • KVO, KVC를 지원한다. (OperationQueue, Operation)
  • Operation Dependency를 가져서, Operation간의 종속성을 설정할 수 있다.
  • DispatchQueue와 같이 QoS를 지원한다.

📚 참고 리소스

profile
iOS 개발자 공부하는 Roy

0개의 댓글