Delegate and Protocols

Hi,


I recently just learnt how to pass UIImage and String data between two VCs using the following delegate and protocol method:



// ProtocolVC.swift

// ProAndDel


import UIKit


protocol GreetingsDelegate {

func userTappedGreet(image: UIImage, name: String)

}


class soundViewController: UIViewController {


var delegate: GreetingsDelegate? = nil


override func viewDidLoad() {

super.viewDidLoad()

}


@IBAction func doIt(_ sender: Any) {

delegate?.userTappedGreet(image: UIImage(named: "MyImage")!, name: "HelloMoon")

dismiss(animated: true, completion: nil)

}

}



// DelegateVC.swift

// ProAndDel


import UIKit


class ViewController: UIViewController, GreetingsDelegate {



@IBOutlet weak var receivingGreeting: UILabel!

@IBOutlet weak var receivingImage: UIImageView!



override func viewDidLoad() {

super.viewDidLoad()

}


func userTappedGreet(image: UIImage, name: String) {

receivingImage.image = image

receivingGreeting.text = name


}


override func prepare(for segue: UIStoryboardSegue, sender: Any?) {

if segue.identifier == "tapGreetingsButton" {

let soundViewController: soundViewController = segue.destination as!

soundViewController

soundViewController.delegate = self

}

}

}


I was wondering if there is an easy way to also include sound this method?


Thanks in advance

zwolf

Replies

What do you mean by including sound ?


If you want to pass the reference of a sound, that's pretty easy


For a system sound, such as kSystemSoundID_Vibrate :


add to protocol

protocol GreetingsDelegate {
    func userTappedGreet(image: UIImage, name: String, sound: SystemSoundID)
}

you call as

    func userTappedGreet(image: UIImage, name: String, sound: SystemSoundID) {
        receivingImage.image = image
        receivingGreeting.text = name
        AudioServicesPlaySystemSound(SystemSoundID(sound))
    }



You can also pass your own registered sound : then pass 2 strings as parameters

protocol GreetingsDelegate {
    func userTappedGreet(image: UIImage, name: String, soundResource: String, soundType: String)
}

    func userTappedGreet(image: UIImage, name: String, soundResource: String, soundType: String) {
        receivingImage.image = image
        receivingGreeting.text = name
         let filePath = Bundle.main.path(forResource: "ButtonTap", ofType: "wav")
         let fileURL = URL(fileURLWithPath: filePath!)
         var soundID:SystemSoundID = 0
         AudioServicesCreateSystemSoundID(fileURL as CFURL, &soundID)
         AudioServicesPlaySystemSound(soundID)
    }

In IBAction :


    @IBAction func doIt(_ sender: Any) {
        delegate?.userTappedGreet(image: UIImage(named: "MyImage")!, name: "HelloMoon", soundResource: "ButtonTap", soundType: "wav")
        dismiss(animated: true, completion: nil)
    }

"ButtonTap.wav" is a file in your project

Hi Claude31,


The simulator crashes when passing data back to the delegate VC.


On the: let fileURL = URL(fileURLWithPath: filePath!) line is the Thread1 unexpectedly found nil while unwrapping...


Also, say there are more than one soundFile, shouldn't the constant in the function be:


let filePath = Bundle.main.path(forResource: "", ofType: "")


and only in the @IBOutlet do I call the particupar sound file object


i.e.


delegate?.userTappedGreet(image: UIImage(named: "MyImage")!, name: "HelloMoon", soundResource: "ButtonTapped", soundType: "wav")

dismiss(animated: true, completion: nil)


?

As I wrote, this assumes that you have included in your project the file ButtonTap.wav


So, a more secure coding is to test for nil (but normally, that should always be OK)


     if let filePath = Bundle.main.path(forResource: "ButtonTap", ofType: "wav") {
         let fileURL = URL(fileURLWithPath: filePath) 
         var soundID:SystemSoundID = 0 
         AudioServicesCreateSystemSoundID(fileURL as CFURL, &soundID) 
         AudioServicesPlaySystemSound(soundID) 
     }



No need for an IBOutlet for it.