Operation Dependencies
- 필수 구성요소 operation이 끝나기 전에 종속 operation이 시작되지 않는 것을 보장합니다.
- 첫번째 operation에서 두번째 operation으로 데이터를 자동으로 전달하는 깔끔한 방법을 제공합니다.
- operation간의 종속성을 활성화하는 것이 GCD보다 Operation을 선택하는 주된 이유중 하나입니다.
Modular design
- 클래스들은 프로젝트 내에서 또는 프로젝트 간에 재사용이 가능하도록 단일 작업을 수행하는 것이 이상적입니다.
Specifying dependencies
- 종속성을 추가하거나 제거하려면 dependent operation에 있는 메서드를 호출해야합니다. 이미지를 다운로드하고 복호화해서 tilt shift를 통해 이미지를 변환하는 예를 생각해 봅시다.
let networkOp = NetworkImageOperation()
let decryptOp = DecryptOperation()
let tiltShiftOp = TiltShiftOperation()
decryptOp.addDependency(op: networkOp)
tiltShiftOp.addDependency(op: decryptOp)
- 어떠한 이유에서 종속성을 제거해야한다면 removeDependency(op:) 메서드를 호출하면 됩니다.
tiltShiftOp.removeDependency(op: decryptOp)
- Operation 클래스는 주어진 operation에 대한 종속성으로 표시되는 Operation 배열을 반환하는 읽기전용 프로퍼티와 종속성을 제공합니다.
Avoiding the pyramid of doom
- 종속성에는 코드를 더 쉽게 읽을 수 있다는 부가효과가 있습니다. 만약에 GCD를 사용해서 3개의 연쇄된 operation을 사용하려고하면 파멸의 피라미드를 만들게 될것입니다.
Watch out for deadlock
-
task가 다른 task에 종속될 때마다 주의하지 않으면 교착상태에가 발생할 수 있습니다. 이를 방지하기 위해 의존성 사슬을 그래프로 그려보는 것이 좋습니다. 그래프가 직선을 그리면 교착 상태가 발생할 가능성이 없습니다.
-
하나의 operation queue에 operation들이 또다른 operation queue에 한 operation에 종속되도록 하는 것은 유효합니다. 그렇게해도 루프가 없는 한 교착상태에서 안전합니다.
-
그러나 루프가 보이기 시작하면 거의 교착상태에 빠진 것입니다.
-
위의 그림을 설명하자면
-
Op2는 Op5가 완료되기 전까지 시작할 수 없습니다.
-
Op5는 Op3이 완료되기 전까지 시작할 수 없습니다.
-
Op3은 Op2가 완료되기 전까지 시작할 수 없습니다.
어떤 operation도 실행될 수 없습니다. 교착상태를 해결하기 위한 특별한 해결책이 없으며 종속성을 그려보지 않으면 파악하기 어려울 것입니다. 이러한 경우 다시 설계하는 수 밖에 없습니다.
Passing data between operations
- 이제 한 operation이 다른 operation에 안전하게 의존하도록 설정할 수 있으니 operation간에 데이터를 전달할 방법이 있어야합니다. 바로 프로토콜! NetworkImageOperation에는 image라고 하는 output 프로퍼티가 있습니다. 그러나 다른 곳에서 호출하는 경우는 어떤가요?
- operation의 장점중 일부는 이들이 제공하는 캡슐화 및 재사용성입니다. operation을 작성하는 모든 사람이 output 프로퍼티를 image라고 부른다고 예상할 수 없습니다. 예를 들어 내부적으로는 foodImage라고 부를 만한 충분한 이유가 있을 것입니다.
Using protocols
- ImageDataProvider를 준수하고 UIImage를 output으로 가지고 있는 모든 operation은 프로토콜을 구현해야합니다. 이 경우 프로퍼티 이름이 일대일로 일치하므로 작업이 쉬워집니다.
import UIKit
protocol ImageDataProvider {
var image: UIImage? { get }
}
- 클래스에 이미 정의된 프로퍼티가 포함되어있으면 다른 작업을 수행할 필요가 없습니다.
extension NetworkImageOperation: ImageDataProvider {}
extension TiltShiftOperation: ImageDataProvider {
var image: UIImage? { return outputImage }
}
Canceling Operation
- Operation을 사용하면, 올바르게 작성하기만 하면 실행중인 operation을 취소할 수 있습니다. 이것은 시간에 따라 필요가 없어질 수 있는 긴 operation에 유용합니다. 예를 들어, 사용자가 화면을 전환하거나 테이블 뷰 셀에서 스크롤로 인해 필요없어진 경우 등 사용자가 결과를 볼 필요가 없어진 경우 데이터를 계속 로드하거나 복잡한 연산을 하는 것이 의미가 없습니다.
The magic of cancel
-
일단 operation을 operation queue에 스케줄하면 더이상 제어할 수 없습니다. 이 때부터 queue에서 operation을 스케줄하고 관리합니다. queue에 추가된 후 변경할 수 있는 유일한 방법은 Operation에서 cancel메서드를 호출하는 것뿐입니다.
-
Operation을 취소하는 방법에 마법 같은 것은 없습니다. operation에 실행중지 요청을 보내면 computed 프로퍼티인 isCancelled가 true로 반환됩니다. 어떤 것도 자동으로 일어나지 않습니다. 처음에는 자동으로 iOS가 operation을 멈추기 않는 것이 이상해보일수 있지만 실제로 그렇지 않습니다.
-
OS에서 operation을 취소한다는 것은 어떤 의미일까요?
-
Operation이 단순히 exception을 던져야할까요?
-
정리해야 되는 것이 있을 수 있나요?
-
실행중인 네트워크를 취소할 수 있나요?
-
작업이 중지되었을 때 서버쪽에 알려주기 위해 보내는 메시지가 있나요?
-
operation이 중지되면 데이터가 손상되나요?
위에 적은 목록으로만으로도 취소가 요청되었음을 나타내는 플래그를 자동으로 설정하는 것이 가능한지 알 수 있습니다.
-
default start 구현은 먼저 isCancelled 플래그가 true인지 확인하고 true이면 바로 종료합니다.
Cancel and cancelAllOperations
- operation을 취소하는 인터페이스는 간단합니다. 특정 Operation을 취소하고 싶다면 cancel 메서드를 호출할 수 있습니다. 반면에 Operation queue에 있는 모든 operation을 취소하고 싶다면 OperationQueue에 정의 되어 있는 cancelAllOperations 메서드를 호출해야합니다.