Duck
Duck

Reputation: 35993

How can I fail during an init?

I am trying to create this class:

class CaptureVideoDataOutput: AVCaptureVideoDataOutput, AVCaptureVideoDataOutputSampleBufferDelegate {

  private let imageCaptureModel: ImageCaptureModel

  override init() {
    super.init()
  }
  
  convenience init?(imageCaptureModel:ImageCaptureModel) {
    self.imageCaptureModel = imageCaptureModel
    
    let queueID = "\(Bundle.main.bundleIdentifier!).captureDeviceOutput"
    let captureVideoDataOutputQueue = DispatchQueue(label: queueID,
                                                    attributes: DispatchQueue.Attributes.concurrent)
    
    let captureVideoDataOutput = CaptureVideoDataOutput()
    captureVideoDataOutput.videoSettings = videoSettingsParameter
    captureVideoDataOutput.setSampleBufferDelegate(captureVideoDataOutput, queue: captureVideoDataOutputQueue)
    
    guard
      imageCaptureModel.captureSession.canAddOutput(captureVideoDataOutput) else {
      return nil
    }
    self = captureVideoDataOutput
  }

the idea is the user just using the convenience init and receive a nil if the whole thing fails on the guard or receive the object if it succeeds.

But this code is failing on the first line with

let' property 'imageCaptureModel' may not be initialized directly; use "self.init(...)" or "self = ..." instead

and on the last line with

Cannot assign to value: 'self' is immutable

Any ideas?

Upvotes: 0

Views: 63

Answers (1)

idmean
idmean

Reputation: 14895

Create an additional (private) initializer for CaptureVideoDataOutput that takes ImageCaptureModel and call it in the convenience initializer instead of CaptureVideoDataOutput():

  private init(_ model: ImageCaptureModel) {
    self.imageCaptureModel = model
    super.init()
  }

  convenience init?(imageCaptureModel:ImageCaptureModel) {
    let queueID = "\(Bundle.main.bundleIdentifier!).captureDeviceOutput"
    let captureVideoDataOutputQueue = DispatchQueue(label: queueID,
                                                    attributes: DispatchQueue.Attributes.concurrent)

    self.init(imageCaptureModel)
    videoSettings = videoSettingsParameter
    setSampleBufferDelegate(captureVideoDataOutput, queue: captureVideoDataOutputQueue)

    guard
      imageCaptureModel.captureSession.canAddOutput(captureVideoDataOutput) else {
      return nil
    }
  }

Note that also non-convenience initializers may return nil, so I'm not sure why you chose this setup. Consider this:

init?(model: ImageCaptureModel) {
    self.imageCaptureModel = model
    let queueID = "\(Bundle.main.bundleIdentifier!).captureDeviceOutput"
    let captureVideoDataOutputQueue = DispatchQueue(label: queueID,
                                                    attributes: DispatchQueue.Attributes.concurrent)

    super.init()
    videoSettings = videoSettingsParameter
    setSampleBufferDelegate(captureVideoDataOutput, queue: captureVideoDataOutputQueue)

    guard
        imageCaptureModel.captureSession.canAddOutput(captureVideoDataOutput) else {
        return nil
    }
}

Upvotes: 1

Related Questions