I am currently working on code that disables a UIImageView while an AVAudioPlayer is playing. The AVAudioPlayer and the ImageView I want to disable are located in two different classes. I tried writing a delegate to have my two classes communicate. For some reason, the protocol method is never run even though my class conforms to the protocol, calling the method and setting the delegate to self. In my Card class, in the audioDidFinishPlaying method, I unwrap the delegate safely. When I run my code, the print statement is called every time instead of the isOn method. Can anyone offer any advice on this issue?
The code for the class containing my AVAudioPlayer is below
import Foundation; import UIKit; import AVFoundation
protocol isOnProtocol{
func isOn()
}
class Card: NSObject
{
var delegate: isOnProtocol?
var player: AVAudioPlayer?
var image: UIImage
var soundUrl: String
init(image: UIImage, soundUrl: String, isActive:Bool = true) {
self.image = image
self.soundUrl = soundUrl
}
func playSound()
{
guard let url = Bundle.main.url(forResource: self.soundUrl, withExtension: "m4a") else { return }
do
{
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
try AVAudioSession.sharedInstance().setActive(true)
player = try AVAudioPlayer(contentsOf: url)
//player?.delegate = self
guard let player = player else { return }
player.prepareToPlay()
player.play()
audioPlayerDidFinishPlaying(player)
print("play")
} catch let error {
print(error.localizedDescription)
}
}
}
extension Card: AVAudioPlayerDelegate {
func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer){
if let del = delegate{
del.isOn()
}else{
print("the delegate is not set")
}
}
}
The code for my ViewController that I am trying to communicate with is below. When the image tapped function is called, the sound plays and UserInteractions should be false until the AVAudioPlayer is finished (isOn function is called).
import UIKit
class SecondViewController: UIViewController , UIGestureRecognizerDelegate, isOnProtocol {
@IBAction func home(_ sender: Any) {
performSegue(withIdentifier: "home", sender: self)
}
@IBOutlet weak var imgPhoto: UIImageView!
var imageIndex: Int = 0
var itemList:[Card] = []
func addlist(list:[String])
{
for word in list
{
itemList.append(Card(image: UIImage(named: word)!, soundUrl: word))
}
}
override func viewDidLoad() {
super.viewDidLoad()
for i in 0..<11 {
let list: [String]
switch i {
case 0: list = ["lake", "lamb", "lamp", "lark", "leaf", "leash", "left", "leg", "lime", "lion", "lips", "list", "lock", "log", "look", "love", "lunch"]
case 1: list = ["ladder", "ladybug", "laughing", "lawnmower", "lemon", "leopard", "leprechaun", "letters", "licking", "lifesaver", "lifting", "lightbulb", "lightning",
"listen", "llama"]
case 2: list = ["alligator", "balance", "ballerina", "balloon", "bowling", "cello", "colors", "curlyhair", "dollar", "dolphin", "elephant", "eyelashes", "gasoline",
"goalie", "hula", "jellyfish", "olive", "pillow", "pilot", "polarbear", "rollerskate", "ruler", "silly", "telephone", "television", "tulip", "umbrella", "valentine",
"violin", "yellow", "xylophone"] //yellow xylophone
case 3: list = ["apple", "ball", "bell", "bubble", "castle", "fall", "fishbowl", "girl", "owl", "pail", "peel", "pool", "smile", "whale", "wheel"] //whale wheel
case 4: list = ["planet", "plank", "plant", "plate", "play", "plum", "plumber", "plus"]
case 5: list = ["black", "blanket", "blender", "blocks", "blond", "blood", "blow", "blue"]
case 6: list = ["flag", "flipflop", "float", "floor", "flower", "fluffy", "flute", "fly"]
case 7: list = ["glacier", "glad", "glasses", "glide", "glitter", "globe", "glove", "glue"]
case 8: list = ["clam", "clamp", "clap", "claw", "clean", "climb", "clip", "cloud"]
case 9: list = ["sled", "sleep", "sleeves", "slice", "slide", "slime", "slip", "slow"]
case 10: list = ["belt", "cold", "dolphin", "elf", "golf", "melt", "milk", "shelf"]
default: fatalError()
}
if UserDefaults.standard.value(forKey: "\(i)") as? Bool ?? true {
addlist(list:list)
}
}
print(itemList.count)
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(imageTapped(tapGestureRecognizer:)))
imgPhoto.isUserInteractionEnabled = true
imgPhoto.addGestureRecognizer(tapGestureRecognizer)
imgPhoto.image = itemList[0].image
// Do any additional setup after loading the view.
//imgPhoto.isUserInteractionEnabled = true
let leftSwipe = UISwipeGestureRecognizer(target: self, action: #selector(Swiped(gesture:)))
leftSwipe.cancelsTouchesInView = false
let rightSwipe = UISwipeGestureRecognizer(target: self, action: #selector(Swiped(gesture:)))
rightSwipe.cancelsTouchesInView = false
leftSwipe.direction = .left
rightSwipe.direction = .right
view.addGestureRecognizer(leftSwipe)
view.addGestureRecognizer(rightSwipe)
}
@IBAction func memoryButton(_ sender: Any) {
performSegue(withIdentifier: "memory", sender: self)
}
func imageTapped(tapGestureRecognizer: UITapGestureRecognizer)
{
imgPhoto.isUserInteractionEnabled = false
let card = itemList[imageIndex]
card.delegate = self
card.playSound()
}
internal func isOn() {
imgPhoto.isUserInteractionEnabled = true
}
func Swiped(gesture: UIGestureRecognizer) {
imgPhoto.isUserInteractionEnabled = true
if let swipeGesture = gesture as? UISwipeGestureRecognizer {
switch swipeGesture.direction {
case UISwipeGestureRecognizerDirection.right :
print("User swiped right")
// decrease index first
imageIndex -= 1
// check if index is in range
if imageIndex < 0 {
imageIndex = itemList.count - 1
}
UIImageView.transition(with: imgPhoto, duration: 0.3, options: .transitionFlipFromLeft, animations: nil, completion: nil)
imgPhoto.image = itemList[imageIndex].image
case UISwipeGestureRecognizerDirection.left:
print("User swiped Left")
// increase index first
imageIndex += 1
// check if index is in range
if imageIndex > itemList.count - 1 {
imageIndex = 0
}
UIImageView.transition(with: imgPhoto, duration: 0.3, options: .transitionFlipFromRight, animations: nil, completion: nil)
imgPhoto.image = itemList[imageIndex].image
default:
break //stops the code/codes nothing.
}
}
}
}