请参阅底部的编辑。我相信我在此处发布的链接可以回答我的问题。
我正在编写一个需要对照相机和位置进行访问的iOS应用,以便用户可以拍摄照片并将照片与拍摄照片的CLLocation存储在一起。我决定实现一个基于操作的体系结构,在其中创建4个操作,每个操作取决于最后一个,以检查并执行以下步骤。更具体地说,每次用户想要拍照并上传照片时,我都请求访问相机和位置。
操作:
1. RequestCameraAccessOperation
2. RequestLocationWhenInUseOperation
3. TakePictureOperation
4. GetLocationOperation
依赖链:
2取决于1
3取决于2
4取决于3
我目前正在添加错误检查以及操作和相关操作的取消。现在,我正在通过在其main()的第一个操作结束时添加cancel()调用来测试取消。但是,没有任何从属操作正在取消。我正在检查他们的主要方法,以查看它们是否被取消,但这似乎无济于事。该文档说:
将操作添加到队列后,该操作将不再可用。队列接管并处理该任务的调度。但是,如果以后您决定根本不想执行该操作(例如,由于用户按下了进度面板中的“取消”按钮或退出了该应用程序),则可以取消该操作以防止其不必要地消耗CPU时间。通过调用操作对象本身的cancel()方法或调用OperationQueue类的cancelAllOperations()方法来执行此操作。 取消操作不会立即强制其停止正在执行的操作。尽管所有操作都希望尊重isCancelled属性中的值,但是您的代码必须显式检查此属性中的值并根据需要中止。
这是我的操作代码:
创建操作并设置依赖项
// create operations
let requestCameraAccessOp = RequestCameraAccessOperation()
let requestLocationWhenInUseOp = RequestLocationWhenInUseOperation()
let takePictureOp = TakePictureOperation(viewController: self)
let locationOp = GetLocationOperation(locationManager: locationManager)
locationOp.completionBlock = { [weak networkManager, unowned self] in
// code that unwraps optionals and sends them to the networkManager
self.dismiss(animated: true, completion: nil)
}
// set operation dependencies
requestLocationWhenInUseOp.addDependency(requestCameraAccessOp)
takePictureOp.addDependency(requestLocationWhenInUseOp)
locationOp.addDependency(takePictureOp)
// add operations to the queue
operationQueue.addOperations([requestCameraAccessOp,
requestLocationWhenInUseOp,
takePictureOp,
locationOp],
waitUntilFinished: false)
第一次操作
class RequestCameraAccessOperation: Operation {
let imagePicker = UIImagePickerController()
var error: AVError.Code?
override func main() {
if isCancelled { return }
let available = UIImagePickerController.isSourceTypeAvailable(.camera)
let status = AVCaptureDevice.authorizationStatus(for: .video)
switch (available, status) {
case (false, _):
error = AVError.contentIsUnavailable
case (true, .authorized):
break
case (true, .notDetermined):
AVCaptureDevice.requestAccess(for: .video) { accessGranted in
if !accessGranted {
self.error = AVError.applicationIsNotAuthorizedToUseDevice
}
}
case (true, .restricted):
fallthrough
case (true, .denied):
// present alert to the user to change authorization in settings
case (true, _):
error = AVError.unknown
}
// always cancel for now to test that cancellation works
self.cancel()
// if let error = error {
// self.cancel()
// }
}
}
第二次操作
class RequestLocationWhenInUseOperation: Operation {
var error: OperationError?
override func main() {
if isCancelled {
cancel()
}
let enabled = CLLocationManager.locationServicesEnabled()
let status = CLLocationManager.authorizationStatus()
switch (enabled, status) {
case (true, .authorizedWhenInUse):
break
case (true, .authorizedAlways):
break
default:
// unsure of how to handle errors
error = .failed("Error")
}
// if let error = error {
// completion(.failed)
// } else {
// completion(.satisfied)
// }
}
}
第3和第4个操作具有相同的取消检查,因此我将避免冗余并跳过发布它们的代码。
据我所知,取消的原因为何不可行,有3种可能性。
编辑:阅读this后,看来我的假设是错误的,标记操作不会取消相关操作。
为此,最好使用每个组的队列将它们拆分。因此,为每个组在并发模式下创建一个NSOperation子类,包括一个队列,然后将每个子操作添加到该队列中。覆盖取消并调用[超级取消],然后调用[self.queue cancelAllOperations]。
我需要在operationQueue本身上调用cancelAllOperations。我不知道如何检查取消并在两次操作之间调用它。添加操作后,我无法控制operationQueue。这样做可能是可行的,但这似乎过于复杂,而不是“智能”解决方案。
此博客post描述了从上一个操作标记为完成后立即开始执行从属操作的位置。
我没看到什么?