2

I am trying to create a flashcard app. I successfully got the app too the point where there were 11 different arrays of flashcards and all of these arrays added up to one final array which I could then swipe through. As you can see each group has "active: true" at the end of it. This is because I have a settings page to turn each word group on and off.

import UIKit

class SecondViewController: UIViewController , UIGestureRecognizerDelegate  {

@IBAction func home(_ sender: Any) {
performSegue(withIdentifier: "home", sender: self)
}

@IBOutlet weak var imgPhoto: UIImageView!

struct List {
let words: [String]
var active: Bool
}

let list1 = List(words:["lake", "lamb", "lamp", "lark", "leaf", "leash", "left", "leg", "lime", "lion", "lips", "list", "lock", "log", "look", "love", "lunch"], active: true)

let list2 = List(words: ["ladder", "ladybug", "laughing", "lawnmower", "lemon", "leopard", "leprechaun", "letters", "licking", "lifesaver", "lifting", "lightbulb", "lightning", "listen", "llama"], active: true)

let list3 = List(words: ["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", "xylophone", "yellow"], active: true)

let list4 = List(words: ["apple", "ball", "bell", "bubble", "castle", "fall", "fishbowl", "girl", "owl", "pail", "peel", "pool", "smile", "whale", "wheel"], active: true)

let list5 = List(words: ["planet", "plank", "plant", "plate", "play", "plum", "plumber", "plus"], active: true)

let list6 = List(words: ["black", "blanket", "blender", "blocks", "blond", "blood", "blow", "blue"], active: true)

let list7 = List(words: ["flag", "flipflop", "float", "floor", "flower", "fluffy", "flute", "fly"], active: true)

let list8 = List(words: ["glacier", "glad", "glasses", "glide", "glitter", "globe", "glove", "glue"], active: true)

let list9 = List(words: ["clam", "clamp", "clap", "claw", "clean", "climb", "clip", "cloud"], active: true)

let list10 = List(words:["sled", "sleep", "sleeves", "slice", "slide", "slime", "slip", "slow"], active: true)

let list11 = List(words: ["belt", "cold", "dolphin", "elf", "golf", "melt", "milk", "shelf"], active: true)

var imageIndex: Int = 0

var imageList: [String] {

let wordLists = [list1, list2, list3, list4, list5, list6, list7, list8, list9, list10, list11]



let active = wordLists.reduce([]) { (result:[String], list:List) in
    if list.active {
        return result + list.words

    } else {
        return result
    }
}

return active

}




override func viewDidLoad() {
super.viewDidLoad()

imgPhoto.image = UIImage(named: imageList[imageIndex])

// 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)

}

func Swiped(gesture: UIGestureRecognizer) {

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 = imageList.count - 1

        }

        imgPhoto.image = UIImage(named: imageList[imageIndex])

    case UISwipeGestureRecognizerDirection.left:
        print("User swiped Left")

        // increase index first

        imageIndex += 1

        // check if index is in range

        if imageIndex > imageList.count - 1 {

            imageIndex = 0

        }

        imgPhoto.image = UIImage(named: imageList[imageIndex])

    default:
        break //stops the code/codes nothing.
    }
}
}
}

but I needed to add a sound file to each flashcard so that whenever the card is tapped an audio file plays, so I changed the code so that each card in each group is coupled with an audio file. However, I have not been able to get this new code to run smooth, it is riddled with bugs. I have posted the bugs below. When I run the new code I should be able to swipe through all of the pictures just like my original code, however this is currently not possible (new code is below)

import UIKit

class SecondViewController: UIViewController , UIGestureRecognizerDelegate  {

var imageIndex: Int = 0
@IBAction func home(_ sender: Any) {
    performSegue(withIdentifier: "home", sender: self)
}

@IBOutlet weak var imgPhoto: UIImageView!

struct List {
    let words: [Card] /*Create array of cards*/
    var active: Bool
}



let firstList:[Card] = [
    Card(image: UIImage(named: "lake")!, soundUrl: "lake"),
    Card(image: UIImage(named: "river")!, soundUrl: "river"),
    Card(image: UIImage(named: "ocean")!, soundUrl: "ocean")
]

let secondList:[Card] = [
    Card(image: UIImage(named: "alligator")!, soundUrl: "alligator"),
    Card(image: UIImage(named: "apple")!, soundUrl: "apple"),
    Card(image: UIImage(named: "grape")!, soundUrl: "grape")
]

override func viewDidLoad() {


    var imageList: [String] {
        let list1 = List(words:firstList, active: true)
        let list2 = List(words:secondList, active: true)

        let wordLists = [list1, list2]

        let active = wordLists.reduce([]) { (result:[String], list:List) in
            if list.active {
                return result + list.words

            } else {
                return result
            }
        }

        return active

    }

    super.viewDidLoad()

    let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(imageTapped(tapGestureRecognizer:)))
    imgPhoto.isUserInteractionEnabled = true
    imgPhoto.addGestureRecognizer(tapGestureRecognizer)


    imgPhoto.image = (wordLists)[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)

}


func imageTapped(tapGestureRecognizer: UITapGestureRecognizer)
{

    itemList[imageIndex].playSound()
    // Your action
}
func Swiped(gesture: UIGestureRecognizer) {

    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

            }

            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

            }

            imgPhoto.image = itemList[imageIndex].image
        default:


            break //stops the code/codes nothing.
        }
    }
}
}

error

3
  • Could you upload your code onto some location and paste the link here? Would be easier to debug. Commented Aug 4, 2017 at 5:04
  • github.com/anthonyrubin/flashcardapp Commented Aug 4, 2017 at 17:15
  • the link above will take you to my git hub. secondViewController is where the problem is and the Card.swift file contains the framework for each "Card" contained in secondViewController Commented Aug 4, 2017 at 17:17

2 Answers 2

1
+50

I think you may have problem problem if you using List model regarding to playing sound of clicked Card one could be better is to modify the Card model with following way

import Foundation; import UIKit; import AVFoundation

var player: AVAudioPlayer?

class Card: NSObject
{
var image: UIImage
var soundUrl: String
var isActive: Bool


init(image: UIImage, soundUrl: String, isActive:Bool = true) {
    self.image = image
    self.soundUrl = soundUrl
    self.isActive = isActive 
}
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)
        guard let player = player else { return }
        player.prepareToPlay()
        player.play()
    print("play")
    } catch let error {
        print(error.localizedDescription)
    }
}
}

Usage Replace your viewController code with this

 import UIKit

class SecondViewController: UIViewController , UIGestureRecognizerDelegate  {





var imageIndex: Int = 0
  var itemList:[Card] = []

    func addlist(list:[String], flag:Bool)
    {
       for word in list
        {
         itemList.append(Card(image: UIImage(named: word)!, soundUrl: word,isActive:flag))
       }
    }
    override func viewDidLoad() {
      super.viewDidLoad()
    let list1 = ["lake", "lamb", "lamp", "lark", "leaf", "leash", "left", "leg", "lime", "lion", "lips", "list", "lock", "log", "look", "love", "lunch"]
    let list2 = ["ladder", "ladybug", "laughing", "lawnmower", "lemon", "leopard", "leprechaun", "letters", "licking", "lifesaver", "lifting", "lightbulb", "lightning",
                 "listen", "llama"]
    let list3 = ["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", "xylophone", "yellow"]
    let list4 = ["apple", "ball", "bell", "bubble", "castle", "fall", "fishbowl", "girl", "owl", "pail", "peel", "pool", "smile", "whale", "wheel"]
    let list5 = ["planet", "plank", "plant", "plate", "play", "plum", "plumber", "plus"]
    let list6 = ["black", "blanket", "blender", "blocks", "blond", "blood", "blow", "blue"]
    let list7 = ["flag", "flipflop", "float", "floor", "flower", "fluffy", "flute", "fly"]
    let list8 = ["glacier", "glad", "glasses", "glide", "glitter", "globe", "glove", "glue"]
    let list9 = ["clam", "clamp", "clap", "claw", "clean", "climb", "clip", "cloud"]
    let list10 = ["sled", "sleep", "sleeves", "slice", "slide", "slime", "slip", "slow"]
    let list11 = ["belt", "cold", "dolphin", "elf", "golf", "melt", "milk", "shelf"]
    addlist(list:list1,flag:true);
    addlist(list:list2,flag:true);
    addlist(list:list3,flag:true);
    addlist(list:list4,flag:true);
    addlist(list:list5,flag:true);
    addlist(list:list6,flag:true);
    addlist(list:list7,flag:true);
    addlist(list:list8,flag:true);
    addlist(list:list9,flag:true);
    addlist(list:list10,flag:true);
    addlist(list:list11,flag:true);

        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 home(_ sender: Any) {
    performSegue(withIdentifier: "home", sender: self)
}

@IBOutlet weak var imgPhoto: UIImageView!


func imageTapped(tapGestureRecognizer: UITapGestureRecognizer)
{

    itemList[imageIndex].playSound()
    // Your action
}
func Swiped(gesture: UIGestureRecognizer) {

    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

            }

            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

            }

            imgPhoto.image = itemList[imageIndex].image
        default:


            break //stops the code/codes nothing.
        }
    }
}
}
Sign up to request clarification or add additional context in comments.

Comments

1

I could find following mistakes with the code.

  1. imageList is declared in viewDidLoad and is accessed in imageTapped & Swiped method. This method can't see imageList. You can make imageList class variable or pass it to imageTapped method as an argument.
  2. Also super.viewDidLoad must be called first before any code in your case, var imageList: [Any] is initialized before calling super.viewDidLoad
  3. return active as! [String] always fail as you can't convert [Any] to String. Image list has to be a list of Cards i.e. [Card]
  4. Keeping 3 in mind, I rewrote imageList code as follows. Hope this helps
let list1 = List(words:firstList, active: true)
let list2 = List(words:secondList, active: true)
let wordLists = [list1, list2]

var imageList: [Card] = []

for list in wordLists {
  if list.active{
    imageList.append(contentsOf: list.words)
  }
}

2 Comments

so I should insert this after the super.viewDidLoad? also how would I write the return function?
Yes. Just declare var imageList: [Card] = [] as a class variable. And assign it a value as demoed in above code in the viewDidLoad method after super.viewDidLoad

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.