Keep getting nil when strung to add Drawing to Drawing Set

When ever I tap the sumitBtn to train the model, I get an error for exampleDrawings.addDrawing(drawing) it is getting the drawing as an image properly so I'm not sure why its getting nil there.


Code Block
struct ExampleDrawingSet {
    /// The desired number of drawings to update the model
    private let requiredDrawingCount = 3
    /// Collection of the training drawings
    private var trainingDrawings = [UserDrawing]()
    /// The emoji or sticker that the model should predict when passed similar images
    //let emoji: Character
    let key = "Test Key"
    /// A Boolean that indicates whether the instance has all the required drawings.
    var isReadyForTraining: Bool { trainingDrawings.count == requiredDrawingCount }
    var count: Int {
            trainingDrawings.count
        }
    /*
    init(for emoji: Character) {
        self.emoji = emoji
    }*/
   /// Creates a batch provider of training data given the contents of `trainingDrawings`.
   /// - Tag: DrawingBatchProvider
    var featureBatchProvider: MLBatchProvider {
        var featureProviders = [MLFeatureProvider]()
        let inputName = "drawing"
        let outputName = "label"
        for drawing in trainingDrawings {
            let inputValue = drawing.featureValue
            let outputValue = MLFeatureValue(string: key)
            //let outputValue = MLFeatureValue(string: String(emoji))
            let dataPointFeatures: [String: MLFeatureValue] = [inputName: inputValue,
                                                               outputName: outputValue]
            
            if let provider = try? MLDictionaryFeatureProvider(dictionary: dataPointFeatures) {
                featureProviders.append(provider)
            }
        }
       return MLArrayBatchProvider(array: featureProviders)
   }
    /// Adds a drawing to the private array, but only if the type requires more.
    mutating func addDrawing(_ drawing: UserDrawing) {
        if trainingDrawings.count < requiredDrawingCount {
            trainingDrawings.append(drawing)
        }
    }
}


Code Block
class Page6MachinLearning: UIViewController, PKCanvasViewDelegate {
    @IBOutlet var canvasView: PKCanvasView!
    @IBOutlet var submitBtn: UIButton!
    var submitWorkItem: DispatchWorkItem?
    var exampleDrawings: ExampleDrawingSet!
    var drawingCount = Int() 
    override func viewDidLoad() {
        super.viewDidLoad()
        configureCanvasView()
    }
    @IBAction func submitBtn(_ sender: Any) {
        print("User tapped \"Done\"; kicking off model update...")
        submitDrawing(canvasView: canvasView)
        drawingCount+=1
        print(drawingCount)
        if drawingCount == 3 {
        // Convert the drawings into a batch provider as the update input.
        let drawingTrainingData = exampleDrawings.featureBatchProvider
        // Update the Drawing Classifier with the drawings.
        DispatchQueue.global(qos: .userInitiated).async {
            ModelUpdater.updateWith(trainingData: drawingTrainingData) {
                DispatchQueue.main.async { self.dismiss(animated: true, completion: nil) }
            }
        }
        } // End If
    }
  
    /// Configures the `PKCanvasView`
    func configureCanvasView() {
        canvasView.backgroundColor = .clear
        canvasView.isOpaque = false
        canvasView.tool = PKInkingTool(.pen, color: .white, width: 20)
        canvasView.delegate = self
        canvasView.allowsFingerDrawing = true
    }
    // MARK: - PKCanvasViewDelegate
    func canvasViewDidBeginUsingTool(_ canvasView: PKCanvasView) {
        // Cancel the submission of the previous drawing when a user begins drawing
        // This lets the user draw another stroke without a time limit of 0.5 seconds
        submitWorkItem?.cancel()
    }
    func canvasViewDrawingDidChange(_ canvasView: PKCanvasView) {
        let drawingRect = canvasView.drawing.bounds
        guard drawingRect.size != .zero else {
            return
        }
        // Check if the user is crossing out previous stickers
        let intersectingViews = canvasView.subviews
            .compactMap { $0 as? UILabel }
            .filter { $0.frame.intersects(drawingRect) }
        guard intersectingViews.isEmpty else {
            // If the current drawing intersects with existing stickers,
            // remove those stickers
            intersectingViews.forEach { $0.removeFromSuperview() }
            canvasView.drawing = PKDrawing()
            return
        }
        submitWorkItem = DispatchWorkItem { self.submitDrawing(canvasView: canvasView) }
        DispatchQueue.global(qos: .userInitiated).asyncAfter(deadline: .now() + 5, execute: submitWorkItem!)
    }
    func submitDrawing(canvasView: PKCanvasView) {
        // Get the rectangle containing the drawing
        let drawingRect = canvasView.drawing.bounds.containingSquare
        // Turn the drawing into an image
        // Because this image may be displayed at a larger scale in the training view,
        // a scale of 2.0 is used for smooth rendering.
        let image = canvasView.drawing.image(from: drawingRect, scale: UIScreen.main.scale * 2.0)
        // Store the white tinted version and the rectangle in a drawing object
        let drawing = UserDrawing(image: image.cgImage!, rect: drawingRect)
        didProduce(drawing: drawing, sender: self)
        DispatchQueue.main.async {
            canvasView.drawing = PKDrawing()
        }
    }
}
extension Page6MachinLearning: DrawingDelegate {
    func didProduce(drawing: UserDrawing, sender: Any?) {
        DispatchQueue.main.async { self.addDrawing(drawing) }
    }
    func addDrawing(_ drawing: UserDrawing) {
        print("drawing - \(drawing)")
        exampleDrawings.addDrawing(drawing) //Error here
    }
}






Accepted Reply

Got it working. Added to Example DrawingSet

Code Block
    init(for key: String) {
        self.key = key
    }


then in viewDiLoad I set it

Code Block
exampleDrawings = ExampleDrawingSet(for: "key")

Replies

I cannot find any code to set a non-nil value to exampleDrawings.
I do not understand why you expect it to be non-nil.
Got it working. Added to Example DrawingSet

Code Block
    init(for key: String) {
        self.key = key
    }


then in viewDiLoad I set it

Code Block
exampleDrawings = ExampleDrawingSet(for: "key")

You have several threads opened. Don't forget to close them once solved.