0

I have stumbled across the following piece of code and I can't understand exactly how it works.

There is the following property which is populated when a method of AVCapturePhotoCaptureDelegate is called:

var photoCaptureCompletionBlock: ((UIImage?, Error?) -> Void)?

The delegate method is triggered by the following piece of code:

func captureImage(completion: @escaping (UIImage?, Error?) -> Void) {

    let settings = AVCapturePhotoSettings()
    self.photoOutput?.capturePhoto(with: settings, delegate: self)
    self.photoCaptureCompletionBlock = completion
}

The line that triggers the delegate is:

self.photoOutput?.capturePhoto(with: settings, delegate: self)

and immediately after that the completion variable is assigned to self.photoCaptureCompletionBlock

Conceptually I would understand the opposite, i.e. to assign self.photoCaptureCompletionBlock to completion and not the other way around (which is not possible without an inout variable since completion is a let).

What are the mechanics behind this assignment? How does it work?

EDIT: For context, the delegate method that is called is the following:

func photoOutput(_ output: AVCapturePhotoOutput,
                                 didFinishProcessingPhoto photoSampleBuffer: CMSampleBuffer?,
                                 previewPhoto previewPhotoSampleBuffer: CMSampleBuffer?,
                                 resolvedSettings: AVCaptureResolvedPhotoSettings,
                                 bracketSettings: AVCaptureBracketedStillImageSettings?,
                                 error: Error?) {

    if let error = error {

        self.photoCaptureCompletionBlock?(nil, error)

    } else if let buffer = photoSampleBuffer,
        let data = AVCapturePhotoOutput.jpegPhotoDataRepresentation(forJPEGSampleBuffer: buffer, previewPhotoSampleBuffer: nil) {

        let image = UIImage(data: data)
        self.photoCaptureCompletionBlock?(image, nil)

    } else {

        self.photoCaptureCompletionBlock?(nil, CameraControllerError.unknown)

    }

}

1 Answer 1

2

Your method captureImage(completion: @escaping (UIImage?, Error?) -> Void) is not a part of AVCapturePhotoCaptureDelegate protocol. It is a custom method of the object's API which implements this protocol.

So since there is no full code of that object, I can only guess. In this method you start photo capturing and pass the completion block, which will be triggered when photo capturing will finish.

This completion block stored in object's variable and I think some other method of delegate, for ex this one func photoOutput(AVCapturePhotoOutput, didFinishProcessingPhoto: AVCapturePhoto, error: Error?) in object implementation will trigger this completion block after photo capturing will be finished.

Sign up to request clarification or add additional context in comments.

6 Comments

The issue that I cannot figure out doesn’t have to do with the delegate method. It has to do with the closure assignment mechanics
Sorry, didn't get it. What exactly you don't understand? Because here we save closure in object's variable to be able to use it later in other method or to fire it from external object since closure is not private.
Since I assign completion to self.photoCaptureCompletion block and not self.photoCaptureCompletion to completion, how does the data pass to completion?
You don't need to pass data to completion. You call this method with your own completion which is assigned to photoCaptureCompletionBlock. After this photoCaptureCompletionBlock will be called from another method.
That’s the issue. I am not using self.photoCaptureCompletion block anywhere, however when I call captureImage function the data is passed in the completion block. That’s what I don’t understand. Why it works (I thought it shouldn’t)
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.