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 } }