Unexpectedly found nil while unwrapping an Optional value bluetooth with swift - swift

import UIKit
import CoreBluetooth
import SciChart
let maestroBrainDataCBUUID = CBUUID(string: "49535343-1E4D-4BD9-BA61-23C647249616")
class HRMViewController: UIViewController {
var sciChartSurface: SCIChartSurface?
var wave:Double! = 0.0
var lineDataSeries: SCIXyDataSeries!
var scatterDataSeries: SCIXyDataSeries!
var lineRenderableSeries: SCIFastLineRenderableSeries!
var scatterRenderableSeries: SCIXyScatterRenderableSeries!
var timer: Timer?
var phase = 0.0
var i = 0
#IBOutlet weak var brainRateLabel: UILabel!
wave is meaning of bluetooth data as realtime.
var centralManager: CBCentralManager!
var maestroPeripheral:CBPeripheral!
override func viewDidLoad() {
super.viewDidLoad()
<elide>
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if nil == timer{
timer = Timer.scheduledTimer(withTimeInterval: 0.01, repeats: true, block: updatingDataPoints)
}
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if nil != timer{
timer?.invalidate()
timer = nil
}
}
func updatingDataPoints(timer:Timer){
i += 1
if wave != nil {
lineDataSeries.appendX(SCIGeneric(i), y: SCIGeneric((wave)))
}
phase += 0.01
sciChartSurface?.zoomExtents()
sciChartSurface?.invalidateElement()
}
func createDataSeries(){
lineDataSeries = SCIXyDataSeries(xType: .double, yType: .double)
lineDataSeries.fifoCapacity = 500
lineDataSeries.seriesName = "line series"
for i in 0...500{
lineDataSeries.appendX(SCIGeneric(i), y: SCIGeneric(wave))
}
i = Int(lineDataSeries.count())
}
I tried to make realtime chart using sci-chart framework.
But if I try to run coding, I get the error:
"Unexpectedly found nil while unwrapping an Optional value"
How to solve this problem?
Is there anyone who have experience like as me TT?
extension HRMViewController: CBCentralManagerDelegate {
func centralManagerDidUpdateState(_ central: CBCentralManager) {
switch central.state {
<elide>
}
}
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic,
error: Error?) {
switch characteristic.uuid {
case maestroBrainDataCBUUID:
wave = Double(brainData(from: characteristic))*3.3/65536
default:
print("Unhandled Characteristic UUID: \(characteristic.uuid)")
}
}
I used it to chart a wave value, but I got an error when I stripped off the option. So if we use if to make the line chart appear if it is not nil, then there was an error, and I tried several times and got a runtime error. What should I do?

I think it could be caused by missing createDataSeries() call in your code. So when updatingDataPoints() is called lineDataSeries instance isn't initialized.
Try adding createDataSeries() call before updateDataPoints() will be called or at least add nil check for lineDataSeries instance in updateDataPoints().

Related

How Do I Fix My Activity Indicator From Not Appearing/Freezing?

#IBOutlet weak var Input: UITextField!
#IBOutlet weak var Heads: UILabel!
#IBOutlet weak var working: UIActivityIndicatorView!
#IBAction func Toss(_ sender: Any) {
DispatchQueue.global().sync {
//set up variables and method
var input = 0
func integer(from textField: UITextField) -> Int {
guard let text = textField.text, let number = Int(text) else {
return 0
}
return number
}
var runningTotal = 0
//collect input
input = integer(from: Input)
//start loading symbol
DispatchQueue.main.async() { [self] in
working.startAnimating()
}
//do math
for _ in 0..<input {
let currentTrial = Int.random(in: 0...1)
if(currentTrial == 1) {
runningTotal += 1
}
}
DispatchQueue.main.async { [self] in
//set output
Heads.text = String(runningTotal)
//stop loading symbol
working.stopAnimating()
}
}
}
This program calculates the number of heads flipped when conducting x coin flips (specified by the user). My activity spinner does not show up at all, even though it is set up to appear when animated. Any help would be appreciated!
So, start by going and having a look at the documentation for DispatchQueue
The sync function reads...
func sync(execute: () -> Void) Submits a block object for execution
and returns after that block finishes executing.
which is not what you want, this will block the main thread and prevent the UI from been updated.
Instead, what you want to use is one of the async variants, for example...
func async(group: DispatchGroup?, qos: DispatchQoS, flags:
DispatchWorkItemFlags, execute: () -> Void) Schedules a block
asynchronously for execution and optionally associates it with a
dispatch group.
You should also get the input value before you run the background thread, as you should avoid accessing components outside of the context of the main thread.
Runnable example...
class ViewController: UIViewController {
#IBOutlet weak var textField: UITextField!
#IBOutlet weak var working: UIActivityIndicatorView!
#IBOutlet weak var headsLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
headsLabel.isHidden = true
}
#IBAction func doStuff(_ sender: Any) {
var input = 0
func integer(from textField: UITextField) -> Int {
guard let text = textField.text, let number = Int(text) else {
return 0
}
return number
}
input = integer(from: textField)
working.startAnimating()
DispatchQueue.global(qos: .userInitiated).async {
//set up variables and method
var runningTotal = 0
//do math
for _ in 0..<input {
let currentTrial = Int.random(in: 0...1)
if(currentTrial == 1) {
runningTotal += 1
}
}
DispatchQueue.main.async { [self] in
headsLabel.isHidden = false
//set output
headsLabel.text = String(runningTotal)
//stop loading symbol
working.stopAnimating()
}
}
}
}

Recording and playing back audio working on simulator but not on real iPhone device [duplicate]

This question already has answers here:
What does "Fatal error: Unexpectedly found nil while unwrapping an Optional value" mean?
(16 answers)
Closed 3 years ago.
On the "soundPlayer.play()" line below I get an error:
Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value.
However, this only happens when pressing the play button on a real device.
Also please ignore that I named my button "plat" button instead of play button, hah.
class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate, AVAudioRecorderDelegate, AVAudioPlayerDelegate {
#IBOutlet weak var recordBTN: UIButton!
#IBOutlet weak var platBTN: UIButton!
var soundRecorder : AVAudioRecorder!
var soundPlayer : AVAudioPlayer!
var fileName: String = "audioFile.m4a"
var player: AVAudioPlayer!
var bannerView: GADBannerView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
bannerView = GADBannerView(adSize: kGADAdSizeBanner)
addBannerViewToView(bannerView)
bannerView.adUnitID = "ca-app-pub-3940256099942544/2934735716"
//ca-app-pub-9351248624194777/2551009478 real
bannerView.rootViewController = self
bannerView.load(GADRequest())
setupRecorder()
platBTN.isEnabled = false
}
func getDocumentsDirectory() -> URL {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
return paths[0]
}
func setupRecorder() {
let audioFilename = getDocumentsDirectory().appendingPathComponent(fileName)
let recordSetting = [ AVFormatIDKey : kAudioFormatAppleLossless,
AVEncoderAudioQualityKey : AVAudioQuality.max.rawValue,
AVEncoderBitRateKey : 320000,
AVNumberOfChannelsKey : 2,
AVSampleRateKey : 44100.2] as [String : Any]
do {
soundRecorder = try AVAudioRecorder(url: audioFilename, settings: recordSetting )
soundRecorder.delegate = self
soundRecorder.prepareToRecord()
} catch {
print(error)
}
}
func setupPlayer() {
let audioFilename = getDocumentsDirectory().appendingPathComponent(fileName)
do {
soundPlayer = try AVAudioPlayer(contentsOf: audioFilename)
soundPlayer.delegate = self
soundPlayer.prepareToPlay()
soundPlayer.volume = 1.0
} catch {
print(error)
}
}
func audioRecorderDidFinishRecording(_ recorder: AVAudioRecorder, successfully flag: Bool) {
platBTN.isEnabled = true
}
func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
recordBTN.isEnabled = true
platBTN.setTitle("Play", for: .normal)
}
#IBAction func recordAct(_ sender: UIButton) {
if recordBTN.titleLabel?.text == "Record" {
soundRecorder.record()
recordBTN.setTitle("Stop", for: .normal)
platBTN.isEnabled = false
} else {
soundRecorder.stop()
recordBTN.setTitle("Record", for: .normal)
platBTN.isEnabled = false
}
}
#IBAction func playAct(_ sender: UIButton) {
if platBTN.titleLabel?.text == "Play" {
platBTN.setTitle("Stop", for: .normal)
recordBTN.isEnabled = false
setupPlayer()
soundPlayer.play() //Thread 1: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value
} else {
soundPlayer.stop()
platBTN.setTitle("Play", for: .normal)
recordBTN.isEnabled = false
}
}
#IBAction func playBtnPressed(_ sender: UIButton) {
playSound(soundName: "4chordsong3") //
}
#IBAction func pausePressed(_ sender: UIButton) {
if player?.play() != nil{
player.pause()
}
}
When I press the "play" button, the program immediately crashes and I get the error shown above. Is there any way I can fix this?
I found the solution. I simply added this to the setupRecorder method.:
let session = AVAudioSession.sharedInstance()
try! session.setCategory(AVAudioSession.Category.playAndRecord)//

FBLoginManager undeclared type

I installed FacebookSDK using Cocoapods, according to Terminal, I have installed FacebookSDK 4.8.0 (CoreKit, ShareKit and LoginKit), I imported the .h files in my BH-File.h, and already initialized everything in my AppDelegate.
For some reason, when trying to log in using a custom button, when I initialize FBLoginManager, I get an error Use of undeclared type "FBLoginManager".
this is my code
if (FBSDKAccessToken.currentAccessToken() == nil)
{
let fbLoginManager : FBSDKLoginManager =
fbLoginManager.logInWithReadPermissions(["public_profile", "email"], fromViewController: self, handler: { (loginResult, error) -> Void in
if error == nil {
print (FBSDKAccessToken.currentAccessToken().tokenString)
}
else {
print ("ERROR*****: \(error)")
}
})
}
What fixed to me was adding import FBSDKCoreKit and FBSDKLoginKit to my class, for some reason is not enough adding it in the BH-file.h
Try something like this, I just checked the code and it works (it's not exactly what you're looking for but I'm sure you can modify it as needed)
import UIKit
import FBSDKCoreKit
import FBSDKLoginKit
class ProfileViewController: UIViewController,FBSDKLoginButtonDelegate {
// #IBOutlet weak var nameLabel: UILabel!
#IBOutlet weak var nameLabel: UILabel!
#IBOutlet weak var imageView: UIImageView!
#IBOutlet weak var nextButton: UIButton!
#IBOutlet weak var fbLoginButton: FBSDKLoginButton!
override func viewDidLoad() {
super.viewDidLoad()
self.fbLoginButton.delegate = self
self.fbLoginButton.readPermissions = ["public_profile"]
self.fbLoginButton.publishPermissions = ["publish_actions"]
NSNotificationCenter.defaultCenter().addObserver(
self,
selector: "fbProfileChanged:",
name: FBSDKProfileDidChangeNotification,
object: nil)
FBSDKProfile.enableUpdatesOnAccessTokenChange(true)
// If we have a current Facebook access token, force the profile change handler
if ((FBSDKAccessToken.currentAccessToken()) != nil)
{
self.fbProfileChanged(self)
} }
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func prefersStatusBarHidden() -> Bool {
return true
}
//facebooks functions
func loginButton(loginButton: FBSDKLoginButton!, didCompleteWithResult result: FBSDKLoginManagerLoginResult!, error: NSError!) {
if (error != nil)
{
print( "\(error.localizedDescription)" )
}
else if (result.isCancelled)
{
// Logged out?
print( "Login Cancelled")
}
else
{
// Logged in?
print( "Logged in, segue now")
self.performSegueWithIdentifier("showHome", sender: self)
}
}
func loginButtonDidLogOut(loginButton: FBSDKLoginButton!) {
}
//see bitfountain
func fbProfileChanged(sender: AnyObject!) {
let fbProfile = FBSDKProfile.currentProfile()
if (fbProfile != nil)
{
// Fetch & format the profile picture
let strProfilePicURL = fbProfile.imagePathForPictureMode(FBSDKProfilePictureMode.Square, size: imageView.frame.size)
let url = NSURL(string: strProfilePicURL, relativeToURL: NSURL(string: "http://graph.facebook.com/"))
let imageData = NSData(contentsOfURL: url!)
let image = UIImage(data: imageData!)
self.nameLabel.text = fbProfile.name
self.imageView.image = image
self.nameLabel.hidden = false
self.imageView.hidden = false
self.nextButton.hidden = false
}
else
{
self.nameLabel.text = ""
self.imageView.image = UIImage(named: "")
self.nameLabel.hidden = true
self.imageView.hidden = true
}
}
#IBAction func nextButtonPressed(sender: UIButton) {
self.performSegueWithIdentifier("showHome", sender: self)
}
}

Swift: AudioPlayerDidFinished will not be called

My AudioPlayerDidFinishPlaying will not be called after audio has finished. I know it has something to do with my delegate, but I can't fix it on my own.
Can somebody give me some tips? I Googled a lot and I found other questions here with the same issue but it didn't work for me.
Thanks
import UIKit
import Parse
import AVFoundation
class ViewControllerMies: UIViewController, AVAudioPlayerDelegate {
var timer = NSTimer()
var player: AVAudioPlayer = AVAudioPlayer()
var currentStateAudio = ""
var oldAudio = String()
func startTimer() {
if player.playing == false {
print("Tijd voor de Spice Girls")
}
let query = PFQuery(className:"CurrentState")
query.getObjectInBackgroundWithId("9r61TRaRqu") {
(objects: PFObject?, error: NSError?) -> Void in
if error == nil && objects != nil {
self.currentStateAudio = objects!.objectForKey("currentState") as! String
print(self.currentStateAudio)
} else {
print(error)
}
}
if (oldAudio != self.currentStateAudio)
{
let audioPath = NSBundle.mainBundle().pathForResource(self.currentStateAudio, ofType: "mp3")!
do {
try player = AVAudioPlayer(contentsOfURL: NSURL(fileURLWithPath: audioPath))
} catch {
// Process error here
}
player.play()
oldAudio = self.currentStateAudio
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("startTimer"), userInfo: nil, repeats: true)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func audioPlayerDidFinishPlaying(player: AVAudioPlayer, successfully flag: Bool)
{
print("Finished Playing")
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
you're not setting yourself as the player's delegate
before calling play() do player.delegate = self
if you are using private delegate then its will not call too use this for resolving this issue
//MARK:- This is correct delegate working fine (use this)
func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
audioRecorder = nil
}
//MARK:- Insted of this (this will not call)
private func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
audioRecorder = nil
}

Crash when repeating a sound with AudioEngine in Swift

I'm trying to play sounds with different effects. In a previous viewController I record a sound, then in the next screen, it can be played with the effects. First time it works ok but the second time it crashes with error as follows:
2015-08-07 13:00:45.900 Pitch Perfect[9643:1121173] 13:00:45.900
ERROR: AVAudioEngine.mm:253: AttachNode: required condition is
false: !nodeimpl->HasEngineImpl() 2015-08-07 13:00:45.953 Pitch
Perfect[9643:1121173] Terminating app due to uncaught exception
'com.apple.coreaudio.avfaudio', reason: 'required condition is false:
!nodeimpl->HasEngineImpl()'
import UIKit
import AVFoundation
class PlaySoundsViewController: UIViewController, AVAudioPlayerDelegate {
var receivedAudio:RecordedAudio!
var audioPlayer: AVAudioPlayer!
var disabledButton:UIButton!
var firstTime:Bool = true
var audioEngine:AVAudioEngine!
var audioFile:AVAudioFile!
var audioPlayerNode:AVAudioPlayerNode!
var audioStopped:Bool!
var typeOfSound:IntegerLiteralType!
#IBOutlet weak var stopButton: UIButton!
#IBOutlet weak var reverbButton: UIButton!
#IBOutlet weak var echoButton: UIButton!
#IBOutlet weak var darthButton: UIButton!
#IBOutlet weak var chipmonkButton: UIButton!
#IBOutlet weak var snailButton: UIButton!
#IBOutlet weak var rabbitButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
audioPlayer = AVAudioPlayer(contentsOfURL: receivedAudio.filePathUrl, error: nil)
audioPlayer.enableRate=true
audioPlayer.delegate=self
var session = AVAudioSession.sharedInstance()
session.setCategory(AVAudioSessionCategoryPlayback, error: nil)
audioPlayerNode=AVAudioPlayerNode();
audioEngine = AVAudioEngine()
audioFile = AVAudioFile(forReading: receivedAudio.filePathUrl, error: nil)
audioStopped=true;
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func playAnimalSound(animal: String) {
if audioStopped==false {
resetAudio(typeOfSound)
}
typeOfSound = 1
audioPlayer.currentTime=0
switch animal {
case "snail":
audioPlayer.rate=0.5
case "rabbit":
audioPlayer.rate=2.0
default:
showMessage("Sound not found. How can it be?")
}
audioPlayer.play()
stopButton.hidden=false
stopButton.enabled=true
}
#IBAction func playSnailSound(sender: UIButton) {
highlightButton(sender)
playAnimalSound("snail")
}
#IBAction func playRabbitSound(sender: UIButton) {
highlightButton(sender)
playAnimalSound("rabbit")
}
func soundEnded() {
stopButton.hidden=true
disabledButton.enabled=true;
if(audioEngine.running) {
audioEngine.stop()
audioEngine.reset();
}
}
func playAudioWithVariablePitch(pitch: Float, type: String) {
if audioStopped==false {
resetAudio(typeOfSound)
}
audioEngine.attachNode(audioPlayerNode)
switch type {
case "normal":
typeOfSound = 2
var changePitchEffect = AVAudioUnitTimePitch()
changePitchEffect.pitch = pitch
audioEngine.attachNode(changePitchEffect)
audioEngine.connect(audioPlayerNode, to: changePitchEffect, format: nil)
audioEngine.connect(changePitchEffect, to: audioEngine.outputNode, format: nil)
case "reverb":
typeOfSound = 3
var changeReverbEffect = AVAudioUnitReverb()
changeReverbEffect.loadFactoryPreset(AVAudioUnitReverbPreset(rawValue: 4)!)
changeReverbEffect.wetDryMix=50;
audioEngine.attachNode(changeReverbEffect)
audioEngine.connect(audioPlayerNode, to: changeReverbEffect, format: nil)
audioEngine.connect(changeReverbEffect, to: audioEngine.outputNode, format: nil)
case "delay":
typeOfSound = 3
var changeDelayEffect = AVAudioUnitDelay()
audioEngine.attachNode(changeDelayEffect)
audioEngine.connect(audioPlayerNode, to: changeDelayEffect, format: nil)
audioEngine.connect(changeDelayEffect, to: audioEngine.outputNode, format: nil)
default:
showMessage("oops, there was an internal problem. Never mind")
}
audioPlayerNode.scheduleFile(audioFile, atTime: nil, completionHandler: soundEnded)
audioEngine.startAndReturnError(nil)
stopButton.hidden=false
stopButton.enabled=true
audioPlayerNode.play()
}
func audioPlayerDidFinishPlaying(player: AVAudioPlayer!, successfully flag: Bool) {
if flag {
stopButton.hidden=true
disabledButton.enabled=true;
audioStopped=true
println("I hid stopButton and enabled the disabled one")
}
}
#IBAction func playDelaySound(sender: UIButton) {
highlightButton(sender)
playAudioWithVariablePitch(0, type: "delay")
}
#IBAction func playReverbSound(sender: UIButton) {
highlightButton(sender)
playAudioWithVariablePitch(0, type: "reverb")
}
#IBAction func playChipmunkSound(sender: UIButton) {
highlightButton(sender)
playAudioWithVariablePitch(1000.0, type: "normal")
}
#IBAction func playDarthVaderSound(sender: UIButton) {
highlightButton(sender)
playAudioWithVariablePitch(-900.0, type: "normal")
}
#IBAction func stopPlaying(sender: UIButton) {
resetAudio(typeOfSound)
stopButton.hidden=true
stopButton.enabled=false;
disabledButton.enabled=true;
}
func highlightButton(button: UIButton) {
if firstTime {
firstTime=false
} else {
disabledButton.enabled=true;
}
button.enabled=false;
disabledButton=button;
}
func resetAudio(type: IntegerLiteralType) {
switch type {
case 1 :
audioPlayer.stop()
println("case 1")
case 2 :
println("case 2")
if audioEngine.running {
audioEngine.stop()
}
audioEngine.reset()
case 3 :
audioEngine.stop()
default:
break
}
audioStopped=true;
}
func showMessage(msg: String) {
var message=UIAlertView(title: "Alert", message: msg, delegate: nil, cancelButtonTitle: "ok I won't panic")
}
}
Does anybody know why it crashes? I have researched the AVAudioEngine, AVAudioPlayer and AVAudioPlayerNode classes with no results.
Thanks
I know this is an old issue, but I didn't see the correct answer above.
The reason why it crashes is actually outlined in the error message:
AttachNode: required condition is false: !nodeimpl->HasEngineImpl()
In other words, when attaching a node it is mandatory that that node is not already attached to an engine (!nodeimpl->HasEngineImpl()).
The solution is to remove the node using audioEngine.detachNode before attempting to add it again.
Finally the crashed was caused by initializing the audioPlayerNode and the audioEngine objects in the viewDidLoad function. They need to be instantiated every time you use them, apparently, or maybe after being stopped and reset.
Placing those lines in the beginning of the playAudioWithVariablePitch function directly instead of in the viewDidLoad function, solved the crash problem. I still have a problem with the playback of the pitched, reverb and echo sounds. They get cut before it's due and I still don't know why. It has to do with the completionHandler of the audioPlayerNode.scheduleFile method.
In my case, my timer was calling again and again and this code was written inside my timer
self.recognitionTask?.finish()
node.removeTap(onBus: 0)
self.request.endAudio()
self.recognitionTask = nil
//Maybe this line was causing the issue
self.audioEngine.stop()
So if you already have stopped the request, removed the tap and stopped the engine, then these lines should not be called again.
Hope this helps some one
It looks like you are resetting the engine after playing the variable pitch effect.
func soundEnded() {
stopButton.hidden=true
disabledButton.enabled=true;
if(audioEngine.running) {
audioEngine.stop()
audioEngine.reset();
}
}
audioPlayerNode.scheduleFile(audioFile, atTime: nil, completionHandler: soundEnded)
audioEngine.startAndReturnError(nil)
stopButton.hidden=false
stopButton.enabled=true
audioPlayerNode.play()
So the engine hasnt been setup again with the nodes added and the chain linked. When you try to play the playerNode, it crashes.