Swift Soundboard App

702 views Asked by At

Hi I am a beginner programmer using swift who is trying to create a basic soundboard template. My code has been getting signal SiGABRT in the AppDelegate and I have no idea why. Could someone please tell me what is wrong with my code and or provide me with the code I could use to create a soundboard. This is what I have so far for my ViewController, any help would be greatly appreciated:

Class SoundListViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

    @IBOutlet weak var tableView: UITableView!
    var audioPlayer = AVAudioPlayer()
    var soundsArray: [Sound] = []
    var session = AVAudioSession.sharedInstance()
    var audioNSURL = NSURL()

override func viewDidLoad() {
    super.viewDidLoad()
    self.tableView.dataSource = self
    self.tableView.delegate = self

    let samplePath = NSBundle.mainBundle().pathForResource("RandomSound", ofType: "m4a")
    audioNSURL = NSURL.fileURLWithPath(samplePath!)!
    audioPlayer = AVAudioPlayer(contentsOfURL: audioNSURL, error: nil)
    audioPlayer.prepareToPlay()

    var soundPath = NSBundle.mainBundle().pathForResource("RandomSound1", ofType: "m4a")
    var soundURL = NSURL.fileURLWithPath(soundPath!)
    var sounds1 = Sound()
    sounds1.name = "Sound1"
    sounds1.URL = soundURL!
    self.soundsArray.append(sounds1)

    soundPath = NSBundle.mainBundle().pathForResource("RandomSound2", ofType: "m4a")
    soundURL = NSURL.fileURLWithPath(soundPath!)
    var sounds2 = Sound()
    sounds2.name = "Sound2"
    sounds2.URL = soundURL!
    self.soundsArray.append(sounds2)

    soundPath = NSBundle.mainBundle().pathForResource("RandomSound3", ofType: "m4a")
    soundURL = NSURL.fileURLWithPath(soundPath!)
    var sounds3 = Sound()
    sounds3.name = "Sound3"
    sounds3.URL = soundURL!
    self.soundsArray.append(sounds3)

}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
}

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return self.soundsArray.count
}

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    var cell = UITableViewCell()
    cell.textLabel?.text = self.soundsArray[indexPath.row].name
    println(cell)
    return cell
}

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    var sound = self.soundsArray[indexPath.row]
    var baseString : String = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)[0] as! String
    var pathComponents = [baseString, sound.URL]

    var rowSoundURL = NSURL.fileURLWithPathComponents(pathComponents)!


    if audioPlayer.playing && rowSoundURL == audioNSURL {

        audioPlayer.stop()

    } else {

        audioNSURL = rowSoundURL

        self.audioPlayer = AVAudioPlayer(contentsOfURL: audioNSURL, error: nil)
        self.audioPlayer.play()

    }

    tableView.deselectRowAtIndexPath(indexPath, animated: true)

}
1

There are 1 answers

3
i89 On

it's a simple mistake in your code ;-) In the viewDidLoad()-method you just set the soundURL variable to the full path of the media file (in that case to RandomSound1.m4a and so on)

In the didSelectRowAtIndexPath()-method of the table view delegate you do the following:

var sound = self.soundsArray[indexPath.row]
var baseString : String = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)[0] as! String
var pathComponents = [baseString, sound.URL]

and then

var rowSoundURL = NSURL.fileURLWithPathComponents(pathComponents)!

and that is the part, where the app crashes. This happens because the the NSURL-class tries to create a URL (like defined in RFCs 1808, 1738, and 2732) depending on baseString and sound.URL. If you check these to variables, it will look like the following:

sound.URL => "file:///private/var/mobile/Containers/Bundle/Application/2D30CB30-919A-4253-AEFD-7386ED63A553/soundboard.app/take_5.m4a"

baseString => "/var/mobile/Containers/Data/Application/63ADE8EB-DAE0-49E0-83A7-88378F675F9D/Documents" 

so when you now combine these two variables, the path is in wrong format and it leads to crash. Instead, you can just use sound.URL, and it will do what you want.

I implemented it that way:

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        var sound = self.soundsArray[indexPath.row]
        var baseString = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)[0] as! String

        if let rowSoundURL = sound.URL {
            if audioPlayer.playing && rowSoundURL == audioNSURL {

                audioPlayer.stop()

            } else {

                audioNSURL = rowSoundURL

                self.audioPlayer = AVAudioPlayer(contentsOfURL: audioNSURL, error: nil)
                self.audioPlayer.play()

            }
        }
        tableView.deselectRowAtIndexPath(indexPath, animated: true)
    }

Note: In my case, the URL variable of Sound is optional. Let me know if it works