Функция UIKeyInput deleteBackward () падает из-за одновременного вызова insertText () - PullRequest
0 голосов
/ 01 апреля 2020

Я пишу приложение для машинного обучения, которое работает как клавиатура. Он использует UIKeyInput и метод .target.insertText() для вставки результатов машинного обучения. Я реализовал ключ удаления, используя target?.deleteBackward(), и у меня периодически возникают сбои из-за того, что мои результаты машинного обучения могут срабатывать в то же время, когда пользователь нажимает клавишу удаления. Я пытался реализовать семафоры следующим образом:

let semaphoreDelete = DispatchSemaphore(value: 1)
func didOutput(pixelBuffer: CVPixelBuffer) {
    let currentTimeMs = Date().timeIntervalSince1970 * 1000
    guard (currentTimeMs - previousInferenceTimeMs) >= delayBetweenInferencesMs else { return }
    previousInferenceTimeMs = currentTimeMs
    // Pass the pixel buffer to TensorFlow Lite to perform inference.
    result = modelDataHandler?.runModel(onFrame: pixelBuffer)
    DispatchQueue.main.async {
    self.semaphoreDelete.wait()
    self.prediction = [
      "\(self.result!.inferences[0].label.description) : \(self.result!.inferences[0].confidence.description)",
      "\(self.result!.inferences[1].label.description) : \(self.result!.inferences[1].confidence.description)",
      "\(self.result!.inferences[2].label.description) : \(self.result!.inferences[2].confidence.description)"
    ]
    if (self.result?.inferences[0].confidence)! >= 0.99 {
        self.insertMachineLearningOutput()
        self.semaphoreDelete.signal()
    }
    }
    // Display results by handing off to the InferenceViewController.
    DispatchQueue.main.async {
        let resolution = CGSize(width: CVPixelBufferGetWidth(pixelBuffer), height: CVPixelBufferGetHeight(pixelBuffer))
    }
}
//checks machine learning output for command or character to insert
private func insertMachineLearningOutput() {
    switch self.result?.inferences[0].label {
    case "del":
    self.target?.deleteBackward()
    case "space":
    self.semaphoreDelete.signal()
    self.target?.insertText(" ")
    case "nothing":
    break
    default:
    self.target?.insertText(self.result!.inferences[0].label.description)
    }
}

Я также добавил семафор в метод my delete, который вызывается с клавиатуры:

    @objc func deleteChar(completion:@escaping () -> Void) {
        DispatchQueue.main.async {
            self.semaphoreDelete.wait()
            self.target?.deleteBackward()
            self.semaphoreDelete.signal()
        }

    }

Приложение просто заходит в тупик, когда я реализовать семафоры вот так ... Должен быть какой-то способ дать сигнал функции удаления, которую нельзя активировать, когда модель ML вставляет текст?

ОБНОВЛЕНИЕ ... Итак, я попытался использовать DispatchGroups, потому что использование семафоров не имеет смысла, поскольку обе задачи находятся в главном потоке.

let MLDispatchGroup = DispatchGroup()
func didOutput(pixelBuffer: CVPixelBuffer) {
  let currentTimeMs = Date().timeIntervalSince1970 * 1000
  guard (currentTimeMs - previousInferenceTimeMs) >= delayBetweenInferencesMs else { return }
  previousInferenceTimeMs = currentTimeMs

  // Pass the pixel buffer to TensorFlow Lite to perform inference.
  result = modelDataHandler?.runModel(onFrame: pixelBuffer)

  MLDispatchGroup.enter()
  DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
    //This block takes the model output and inserts it to the 
    // UITextView
    switch self.result?.inferences[0].label {
    case "del":
      self.target?.deleteBackward()
    case "space":
      self.target?.insertText(" ")
    case "nothing":
      break
    default:
      self.target?.insertText(self.result!.inferences[0].label.description)
    }
    // Display results by handing off to the InferenceViewController.
    let resolution = CGSize(width: CVPixelBufferGetWidth(pixelBuffer), height: CVPixelBufferGetHeight(pixelBuffer))
    self.MLDispatchGroup.leave()
  }
  MLDispatchGroup.notify(queue: DispatchQueue.main) {
    print("should be doing ML")
  }
}
@objc func deleteChar(completion:@escaping () -> Void) {
  MLDispatchGroup.enter()
  DispatchQueue.main.asyncAfter(deadline: .now()) {
    self.target?.deleteBackward()
    self.MLDispatchGroup.leave()
  }
  MLDispatchGroup.notify(queue: DispatchQueue.main) {
    print("should be deleting")
  }
}
...