I thought I replied, but anyway:
I found this answer, and it has many solutions. The one that worked for me was "doing a hard restart of my iPhone." Ashamed I didn't think of trying that first.
Post not yet marked as solved
This is what worked for me. I went to this answer, which had a few answers.
The one that worked for me was: restart the iPhone. Which I am a little ashamed I didn't try on my own.
So it appears that I was misunderstanding where the fault/error lied.
I had changed an attribute in CoreData from String to Int. Since I had no data yet, I assumed that the existing entity would be over written. That was not the case.
So essentially I just have to delete the app from any device I am running them on, then rebuild.
Closing because again I asked a stupid question
Post not yet marked as solved
So I created the code below, and the weird thing was that the output read:
going in...
and we're out
Need to ask user
So essentially it blows right through the semaphore. However, if I declare the semaphore with 0, then the first semaphore.wait() is successful, and the program freezes because the userAlert permission box never pops up.
What is going on here?
print ("going in...")
let semaphore = DispatchSemaphore(value: 1 )
DispatchQueue.global(qos: .userInitiated).async {
let mediaAuthorizationStatus = AVCaptureDevice.authorizationStatus(for: .audio)
switch mediaAuthorizationStatus {
case .denied:
print (".denied")
case .authorized:
print ("authorized")
case .restricted:
print ("restricted")
case .notDetermined:
print("Need to ask user")
semaphore.wait()
AVCaptureDevice.requestAccess(for: .audio, completionHandler: { (granted: Bool) in
if granted {
semaphore.signal()
} else {
semaphore.signal()
}
})
@unknown default:
print("unknown")
}
print ("\(semaphore.debugDescription)")
}
semaphore.wait()
print ("and we're out")
I was informed that this wouldn't work. No matter where the instance of the class was generated, its methods would still run on the main queue by default.
It's kind of kludgy but someone gave me the answer here:
https://stackoverflow.com/questions/70616820/my-writing-the-installtap-buffer-to-an-avaudiofile-seems-to-fail-data-wise/70618216?noredirect=1#comment124895854_70618216
You need to let your AVAudioFile go out of scope (nil it at some point), that's how you call AVAudioFile's close() method, which presumably finishes writing out header information.
This is a rewriting of my original question, once I realized I was reading the flow incorrectly.
Working on a speech to text demo, which works. But I am still trying to learn the flow of Swift. While I may be calling it incorrectly, I'm looking at the closure in node.installTap as a C callback function. When the buffer is full, the code within the closure is called.
From what I interpret here, every time the buffer becomes full, the closure from within the node.installTap runs.
What I can't figure out is what triggers the closure within:
task = speechRecognizer?.recognitionTask(with: request, resultHandler: {})
The entire demo below works, am just trying to figure out how the AVAudioEngine knows when to call that second closure. Is there some connection?
func startSpeechRecognition (){
let node = audioEngine.inputNode
let recordingFormat = node.outputFormat(forBus: 0)
node.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat)
{ (buffer, _) in self.request.append(buffer) }
audioEngine.prepare()
do {
try audioEngine.start()
} catch let error {
...
}
guard let myRecognition = SFSpeechRecognizer() else {
...
return
}
if !myRecognition.isAvailable {
...
}
task = speechRecognizer?.recognitionTask(with: request, resultHandler:
{ (response, error) in guard let response = response else {
if error != nil {
print ("\(String(describing: error.debugDescription))")
} else {
print ("problem in repsonse")
}
return
}
let message = response.bestTranscription.formattedString
print ("\(message)")
})
}
I'm glad I asked this, but it turns out I do NOT understand the flow. How is
task = speechRecognizer?.recognitionTask(with: request, resultHandler: { (response, error) in guard let response = response else {
always being called multiple times? Does it have a connection to node.installTap?
No, there is no error, it's the flow I am trying to understand.
The code block in-between the last { } get's called multiple times , when the buffer is full I assume, and then the code continues to run everything below it as well.
Post not yet marked as solved
Experimenting around I found that if I didn't set the child's constraints (see below), then it would always work.
Is there a method to remove the constraints of a UIView before deleting it?
vc is the Child UIView and pc is its parent
func setConstraints (vc: UIViewController, pc: UIView) {
vc.view.translatesAutoresizingMaskIntoConstraints = false
var constraints = [NSLayoutConstraint]()
constraints.append(vc.view.leadingAnchor.constraint(equalTo: pc.safeAreaLayoutGuide.leadingAnchor))
constraints.append(vc.view.trailingAnchor.constraint(equalTo: pc.safeAreaLayoutGuide.trailingAnchor))
constraints.append(vc.view.bottomAnchor.constraint(equalTo: pc.safeAreaLayoutGuide.bottomAnchor))
constraints.append(vc.view.topAnchor.constraint(equalTo: pc.safeAreaLayoutGuide.topAnchor))
NSLayoutConstraint.activate(constraints)
}
For anyone coming across this with the same need, I found this to be a great tutorial:
https://youtu.be/SZJ8zjMGUcY (no, it's not me)
Doh! Thanks. Am going to blame the laziness of autocomplete. That’s why I like to type everything. Ingrains it better.
It works now with me only setting the background image. But can I leave setIamge blank? Or do I have to set it to nil?