macOS - AVCaptureSession.stopRunning() crash - swift

I have the following code (I copied whole class because I don't really get what the problem is; the function with the problem is displayImage - last 4 lines of code or so):
class ViewController: NSViewController {
#IBOutlet var previewBox: NSView!
#IBOutlet var captureBox: NSImageView!
let cameraSession = AVCaptureSession()
let device = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo) as AVCaptureDevice
var deviceInput: AVCaptureDeviceInput?
var dataOutput: AVCaptureStillImageOutput?
override func viewDidLoad() {
super.viewDidLoad()
}
override var representedObject: Any? {
didSet {
// Update the view, if already loaded.
}
}
#IBAction func scan(_ sender: NSButton) {
do {
deviceInput = try AVCaptureDeviceInput(device: device)
cameraSession.beginConfiguration()
if (cameraSession.canAddInput(deviceInput) == true) {
cameraSession.addInput(deviceInput)
}
dataOutput = AVCaptureStillImageOutput()
if (cameraSession.canAddOutput(dataOutput) == true) {
cameraSession.addOutput(dataOutput)
}
cameraSession.commitConfiguration()
let previewLayer = AVCaptureVideoPreviewLayer(session: cameraSession)
previewBox.layer?.addSublayer(previewLayer!)
previewLayer?.frame = (previewBox.layer?.frame)!
previewLayer?.connection.automaticallyAdjustsVideoMirroring = false
previewLayer?.connection.isVideoMirrored = true
cameraSession.startRunning()
}
catch let error as NSError {
NSLog("\(error), \(error.localizedDescription)")
}
}
#IBAction func capture(_ sender: NSButton) {
if let videoConnection = dataOutput?.connection(withMediaType: AVMediaTypeVideo) {
dataOutput?.captureStillImageAsynchronously(from: videoConnection, completionHandler: self.displayImage)
}
}
func displayImage(buffer: CMSampleBuffer?, err: Error?) {
let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(buffer)
cameraSession.stopRunning()
captureBox.image = NSImage(data: imageData!)
}
}
Now... everything looks ok the preview is working, the buffer seems to have something in it - although that may be corrupted also since I can't display the image even if I comment the line with the crash (the main problem I'm asking about now). But... when it get's to the stopRunning() function the app crashes (print below). Any idea what I'm doing wrong here? If I comment the stop running part the app doesn't crash but the image is not set (that's why I pasted all... I'm expecting the problem to be somewhere else in code).
IMPORTANT: This is cocoa app, not iOS (and apparently there are 999999 code examples for iOS and 0 for macOS).

Related

Get selected image in imagePickerController and pass it to coreML

I'm trying to do the recognition by using coreML, the function working and showing the result correctly. But I want to call the method into a button, like when I pressed the catDog button and it runs the method. But since the finalResult() and identifyCatOrDog() is its own function, so that I can't call it into the button. I tried to copy and paste the method inside the button, but it doesn't show me anything. How can I edit the code so that findResult() only work when I pressed the button not running automatically?
import UIKit
import CoreML
import Vision
import Photos
class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
#IBOutlet var loadImage: UIImageView!
#IBOutlet var Result: UILabel!
#IBAction func photoBtn(_ sender: UIButton) {
getPhoto()
}
#IBAction func cameraBtn(_ sender: UIButton) {
}
#IBAction func catDog(_ sender: UIButton) {
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func getPhoto() {
let picker = UIImagePickerController()
picker.delegate = self
picker.sourceType = .photoLibrary
present(picker, animated: true, completion: nil)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
picker.dismiss(animated: true, completion: nil)
guard let gotImage = info[.originalImage] as? UIImage else {
fatalError("No picture chosen")
}
loadImage.image = gotImage
identifyCatOrDog(image: gotImage)
}
func identifyCatOrDog(image: UIImage) {
let modelFile = ImageClassifier()
let model = try! VNCoreMLModel(for: modelFile.model)
let handler = VNImageRequestHandler(cgImage: image.cgImage!, options: [ : ])
let request = VNCoreMLRequest(model: model, completionHandler: findResults)
try! handler.perform([request])
}
func findResults(request: VNRequest, error: Error?) {
guard let results = request.results as? [VNClassificationObservation] else {
fatalError("Unable to get results")
}
var bestGuess = ""
var bestConfidence: VNConfidence = 0
for classification in results {
if (classification.confidence > bestConfidence) {
bestConfidence = classification.confidence
bestGuess = classification.identifier
}
}
Result.text = "Image is: \(bestGuess) with confidence \(bestConfidence) out of 1"
}
I take it that the problem is that sometimes when the image picker is dismissed, you want to call identifyCatOrDog, but other times you don’t.
One rather crude possibility is this: In the button action method, raise a bool instance property flag so that when didFinishPickingMedia is called you know whether or not to call identifyCatOrDog.
A more sophisticated way would be to divide things off into helper classes so that the operation of the image picker after pressing the catDog button takes place within a completely different code world.

IOS Swift - Camera view overlay shouldn't cover status bar

I am learning Swift - making progress. My application should scan a barcode. I am trying to show the camera in the middle of the screen between two strips of spaces above and below the UIview. There is a button at bottom strip of space to save the barcode number. My issue is, I need to show the status bar at the top of the screen with signal strength, time, battery etc., when user is scanning, but it is covered by the UI view when it open camera. I have reviewed other posts and incorporated the suggestions, but the issue persists. Any help is appreciated.
I have uploaded image showing the covered status bar.
Here is my code:
class ScannerViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate {
#IBOutlet weak var cameraView: UIView!
#IBOutlet weak var selectScan1: UIButton!
var captureSession: AVCaptureSession!
var previewLayer: AVCaptureVideoPreviewLayer!
override func viewDidLoad() {
super.viewDidLoad()
// view.backgroundColor = UIColor.black
captureSession = AVCaptureSession()
guard let videoCaptureDevice = AVCaptureDevice.default(for: .video) else { return }
let videoInput: AVCaptureDeviceInput
do {
videoInput = try AVCaptureDeviceInput(device: videoCaptureDevice)
} catch {
return
}
if (captureSession.canAddInput(videoInput)) {
captureSession.addInput(videoInput)
} else {
failed()
return
}
let metadataOutput = AVCaptureMetadataOutput()
if (captureSession.canAddOutput(metadataOutput)) {
captureSession.addOutput(metadataOutput)
metadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
metadataOutput.metadataObjectTypes = [.ean8, .ean13, .pdf417]
} else {
failed()
return
}
previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
previewLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill
previewLayer?.frame = self.cameraView.layer.frame
cameraView.layer.addSublayer(previewLayer!)
// **** note: select click to bounds check box in storyboard
captureSession.startRunning()
}

Zero amplitude and frequency from audiokit tracker on device but works on simulator

AudioKit
I have two view controllers that are doing different audio related function. The first view viewController, needs to record audio and also do real-time processing of the amplitude and frequency of the sound being recorded. The second view controller needs to play the recorded audio, and do some stuff with the playhead.
My problem is that when I go back and forth a few times between the two screens on my iphone 6 device, the amplitude and frequency of the tracker only equal 0. This behavior does not happen on my simulator. Similarly, I've tried different combinations of starting + stopping the tracker and/or the audio engine at different points in the workflow but then I just get crashes along the lines of https://github.com/audiokit/AudioKit/issues/643. One thing I have been trying to figure out is how to make a singleton instance of the aukiokit so I can only start the engine once, but I can't get it from examples.
Here are the key sections of code that use the audiokit, microphone and tracker:
First view controller in the workflow
class ViewController: UIViewController {
#IBAction func analyzeSpeechAction(_ sender: Any) {
//Audiokit.stop()
stopTimers()
let vc = AnalysisViewController(nibName: "AnalysisViewController", bundle: nil)
print("ANALYZING")
do {
try player.reloadFile()
} catch { print("Errored reloading.") }
let recordedDuration = player != nil ? player.audioFile.duration : 0
if recordedDuration > 0.0 {
recorder.stop()
}
tracker.stop()
navigationController?.pushViewController(vc, animated: true)
}
func stopTimers(){
if timerTest != nil {
timerTest!.invalidate()
timerTest = nil
}
if timer != nil {
timer!.invalidate()
timer = nil
}
}
var mic: AKMicrophone!
var tracker: AKFrequencyTracker!
var silence: AKBooster!
var mainMixer: AKMixer!
var timerTest : Timer?
var micMixer: AKMixer!
var recorder: AKNodeRecorder!
var player: AKAudioPlayer!
var tape: AKAudioFile!
var micBooster: AKBooster!
override func viewDidLoad() {
super.viewDidLoad()
AKAudioFile.cleanTempDirectory()
AKSettings.bufferLength = .medium
do {
try AKSettings.setSession(category: .playAndRecord, with: .allowBluetoothA2DP)
} catch {
AKLog("Could not set session category.")
}
AKSettings.defaultToSpeaker = true
AKSettings.audioInputEnabled = true
mic = AKMicrophone()
tracker = AKFrequencyTracker(mic)
tracker.start()
silence = AKBooster(tracker, gain: 0)
micMixer = AKMixer(mic)
micBooster = AKBooster(micMixer)
// Will set the level of microphone monitoring
micBooster.gain = 0
recorder = try? AKNodeRecorder(node: micMixer)
if let file = recorder.audioFile {
player = try? AKAudioPlayer(file: file)
}
mainMixer = AKMixer(micBooster)
do {
try recorder.record()
} catch { print("Errored recording.") }
AudioKit.output = mainMixer
}
viewDidAppear(){
AudioKit.stop()
AudioKit.output = silence
AudioKit.start()
if timer == nil{
timer = Timer.scheduledTimer(timeInterval: 1, target:self,
selector: #selector(ViewController.updateCounter), userInfo: nil, repeats: true)
}
}
#objc func updateUI() {
frame = frame + 1
print("AMP")
print(tracker.amplitude)
print(tracker.frequency)
}
}
Second View Controller
class AnalysisViewController: UIViewController {
#IBOutlet weak var barChartView: LineChartView!
#IBAction func recordSpeechNavigation(_ sender: Any) {
let vc = ViewController(nibName: "ViewController", bundle: nil)
//AudioKit.stop()
player.stop()
navigationController?.pushViewController(vc, animated: true)
}
#IBAction func playButtonAction(_ sender: UIButton) {
playAudio()
}
override func viewDidLoad() {
super.viewDidLoad()
//move to completion handler
player.completionHandler = {() -> Void in
self.playerStatusButton.setTitle("Play", for: .normal)
self.timerTest!.invalidate()
self.relativePlayheadPosition = 0.0
self.movePlayhead()
print("complete")
}
}
}
I kind of mashed up a bunch of examples to get this far so I apologize if I am improperly using some of the AudioKit methods. The key behavior occurs between viewDidLoad(), viewDidAppear() and updateUI() of the first view and recordSpeechNavigation() of the second view.
Does anyone have any insight into what might be happening or how I can properly implement this stuff?

Play Sound Using AVFoundation with Swift 2

I am trying to play a sound in my iOS app (written in Swift 2) using AVFoundation. I had it working with no issues with the previous version of Swift. I am using Xcode 7.0. I am not sure what the issue is and cannot find any additional info for Swift 2 regarding playing sounds. Here's my code for the sound part:
import AVFoundation
class ViewController: UIViewController {
var mySound = AVAudioPlayer()
override func viewDidLoad() {
super.viewDidLoad()
mySound = self.setupAudioPlayerWithFile("mySound", type:"wav")
mySound.play()
}
func setupAudioPlayerWithFile(file:NSString, type:NSString) -> AVAudioPlayer {
var path = NSBundle.mainBundle().pathForResource(file, ofType:type)
var url = NSURL.fileURLWithPath(path!)
var error: NSError?
var audioPlayer:AVAudioPlayer?
audioPlayer = AVAudioPlayer(contentsOfURL: url, error: &error)
return audioPlayer!
}
}
I am getting this error but have a feeling there maybe some other issue:
'NSString' is not implicitly convertible to 'String'; did you mean to use 'as' to explicitly convert?
Like Leo said
You need to implement do try catch error handling.
Here is another example of some code that will run sound when a button is pressed.
import UIKit
import AVFoundation
class ViewController: UIViewController {
#IBAction func play(sender: AnyObject) {
player.play()
}
#IBAction func pause(sender: AnyObject) {
player.pause()
}
var player: AVAudioPlayer = AVAudioPlayer()
override func viewDidLoad() {
super.viewDidLoad()
let audioPath = NSBundle.mainBundle().pathForResource("sound", ofType: "mp3")!
do {
try player = AVAudioPlayer(contentsOfURL: NSURL(fileURLWithPath: audioPath))
} catch {
// Process error here
}
}
}
I hope this helps!
You need to implement do try catch error handling. Try like this:
func setupAudioPlayerWithFile(file: String, type: String) -> AVAudioPlayer? {
if let url = NSBundle.mainBundle().URLForResource(file, withExtension: type) {
do {
return try AVAudioPlayer(contentsOfURL: url)
} catch let error as NSError {
print(error.localizedDescription)
}
}
return nil
}

Can't find fatal error: unexpectedly found nil while unwrapping an Optional value [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
It was working last night, but when I run my code, now I am receiving a:
fatal error: unexpectedly found nil while unwrapping an Optional value.
Can someone help me locate this error?
import UIKit
class UserRegistration: UIViewController, UINavigationControllerDelegate, UIImagePickerControllerDelegate, UITextFieldDelegate {
//USER REGISTRATION FORM
//Activity Indicator
var activityIndicator: UIActivityIndicatorView = UIActivityIndicatorView()
//Error
func displayAlert(title:String, error:String){
//create Alert
var alert = UIAlertController(title: title, message: error, preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "Ok", style: .Cancel, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
}
//User Profile Picture Selection
var profileImage = UIImage()
var isThereImage = false
#IBOutlet var uploadProfilePictureButton: UIButton!
#IBAction func uploadProfilePicture(sender: AnyObject) {
//Settings needed for image upload
var image = UIImagePickerController()
image.delegate = self
image.sourceType = UIImagePickerControllerSourceType.PhotoLibrary //can use '.camera' to access camera
image.allowsEditing = true
//Select image. FYI Completion is a function that happens when viewcontroller is presented
self.presentViewController(image, animated: true, completion: nil)
}
func imagePickerController(picker: UIImagePickerController!, didFinishPickingImage image: UIImage!, editingInfo: [NSObject : AnyObject]!) {
//Store image in local variable to be resized later
profileImage = image
println("Image is selected")
//Manually Close View Controller
self.dismissViewControllerAnimated(true, completion: nil)
//Remove button title
uploadProfilePictureButton.setTitle("", forState: .Normal)
//Display Image
uploadProfilePictureButton.setBackgroundImage(image, forState: .Normal)
//Set isThereImage Boolean
isThereImage = true
}
//---------------------------------------
//User Input Information
#IBOutlet var userEmailAddress: UITextField!
#IBOutlet var userPasswordOne: UITextField!
#IBOutlet var userPasswordTwo: UITextField!
#IBOutlet var passwordConfirmationMatch: UILabel!
var confirmedPassword = Bool()
//---------------------------------------
//Submit User Input to Database
#IBAction func userRegistration(sender: AnyObject) {
var error = ""
//Verify if User Exist and Passwords Match
if userEmailAddress.text == "" || userPasswordOne.text == "" || confirmedPassword == false {
error = "Please enter an email address and password, or make sure your passwords match."
println("Registration had an error")
}
if error != "" {
displayAlert("Error in Registration", error: error)
} else {
//Sign Up User
var user = PFUser()
//Resize Profile Picture
let size = CGSizeApplyAffineTransform(profileImage.size, CGAffineTransformMakeScale(0.5, 0.5))
let hasAlpha = true
let scale: CGFloat = 0.0 // Automatically use scale factor of main screen
UIGraphicsBeginImageContextWithOptions(size, !hasAlpha, scale)
profileImage.drawInRect(CGRect(origin: CGPointZero, size: size))
let scaledImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
//User Information
user.password = userPasswordTwo.text
user.email = userEmailAddress.text
user.username = userEmailAddress.text
if isThereImage == false {
displayAlert("Please upload a picture for your profile.", error: error)
}else if isThereImage == true {
var imageData = UIImagePNGRepresentation(scaledImage)
var imageFile = PFFile(name: userEmailAddress.text + ".png", data:imageData)
user.setObject(imageFile, forKey: "userProfileImage")
}
user.setObject("", forKey: "firstName")
user.setObject("", forKey: "lastName")
user.setObject("", forKey: "userLocation")
//Insert Activity Indicator here
activityIndicator = UIActivityIndicatorView(frame: CGRectMake(0, 0, 50, 50))
activityIndicator.center = self.view.center
activityIndicator.hidesWhenStopped = true
activityIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.Gray
view.addSubview(activityIndicator)
activityIndicator.startAnimating()
UIApplication.sharedApplication().beginIgnoringInteractionEvents()
//-------------------------------
user.signUpInBackgroundWithBlock {
(succeeded: Bool!, signupError: NSError!) -> Void in
//Stop activity indicator whether there is an error or not
self.activityIndicator.stopAnimating()
UIApplication.sharedApplication().endIgnoringInteractionEvents()
if signupError == nil {
// Hooray! Let them use the app now.
println("Registration Completed")
} else {
//Keep this here!
if let errorString = signupError.userInfo?["error"] as? NSString{
error = errorString
} else {
error = "Please try again later."
}
self.displayAlert("Could not Sign Up", error: error)
println(signupError)
}
}
}
//Print Confirmation to Cortana
}
//---------------------------------------
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
passwordConfirmationMatch.hidden = true
//UITextField Delegate
self.userEmailAddress.delegate = self
self.userPasswordOne.delegate = self
self.userPasswordTwo.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//Password Matching Function
func passwordCheck() {
if userPasswordTwo.text == userPasswordOne.text {
passwordConfirmationMatch.hidden = false
confirmedPassword = true
println("Password match")
} else {
passwordConfirmationMatch.hidden = true
confirmedPassword = false
println("Passwords don't match")
}
}
//Handle Keyboard
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
self.view.endEditing(true)
passwordCheck()
}
func textFieldShouldReturn(textField: UITextField!) -> Bool {
userEmailAddress.resignFirstResponder()
userPasswordOne.resignFirstResponder()
userPasswordTwo.resignFirstResponder()
passwordCheck()
return true
}
}
The error you get indicates that one of your variables that has been declared as optional was nil when your code tried to access it.
Do you get any more info from the error? Like the name of the variable for example? If not, use some breakpoints to find the culprit and make sure it is not nil when the time to use it comes.