0

I am trying to make a simple flashcard app.

OVERVIEW - To give you the basic run down of the app, all of the flashcards contain an object that has the letter l. Sometimes the word starts with the letter l, sometimes there is a double ll, sometimes the word starts with pl or kl, or sl, etc...

SO FAR - I have made the app so that there is a home page and from the home page you press Go and then it takes you too a second view controller. From there you can swipe left and right through the flash cards. I did this by creating an array with all of the images and then adding a swipe gesture (code below)

//
//  SecondViewController.swift
//  firstapp
//
//  Created by Anthony Rubin on 6/20/17.
//  Copyright © 2017 rubin. All rights reserved.
//

import UIKit

class SecondViewController: UIViewController , UIGestureRecognizerDelegate  {



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


@IBOutlet weak var imgPhoto: UIImageView!





var imageList:[String] = ["alligator", "apple", "balance", "ball", "ballerina", "balloon", "bell", "belt", "black", "blanket", "blender", "blocks", "blond", "blood", "blow", "blue", "bowling", "bubble", "bully", "calendar", "castle", "cello", "clam", "clamp", "clap", "claw", "clean", "climb", "clip", "cloud", "cold", "colors", "crawl", "curlyhair", "dollar", "dolphin", "elephant", "elf", "eyelashes", "fall", "fishbowl", "flag", "flipflop", "float", "floor", "flower", "fluffy", "flute", "fly", "gasoline", "girl", "glacier", "glad", "glasses", "glide", "glitter", "globe", "glove", "glue", "goalie", "golf", "hula", "jellyfish", "ladder", "ladybug", "lake", "lamb", "lamp", "lark", "laughing", "lawnmower", "leaf", "leash", "left", "leg", "lemon", "leopard", "leprechaun", "letters", "licking", "lifesaver", "lifting", "lightbulb", "lightning", "lime", "lion", "lips", "list", "listen", "llama", "lock", "log", "look", "love", "lunch", "melt", "milk", "olive", "owl", "pail", "peel", "pillow", "pilot", "planet", "plank", "plant", "plate", "play", "plum", "plumber", "plus", "polarbear", "pool", "rollerskate", "ruler", "shelf", "silly", "sled", "sleep", "sleeves", "slice", "slide", "slime", "slip", "slow", "smile", "telephone", "television", "tulip", "umbrella", "valentine", "violin", "whale", "wheel", "xylophone", "yellow"]
 let maxImages = 135
 var imageIndex: NSInteger = 0


override func viewDidLoad() {
    super.viewDidLoad()

    // 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 = maxImages

            }

            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 > maxImages {

                imageIndex = 0

            }

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




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


        }
    }
}










override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}
}


/*
// MARK: - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    // Get the new view controller using segue.destinationViewController.
    // Pass the selected object to the new view controller.
}
*/

THE PROBLEM - I want to create a settings page. This settings page will have a basic on and off switch for each group of words. So lets say I do not want any words that have the initial letter l, I would turn the button too the off position and then when I swipe through the images there will be no flashcards with the initial letter l.

settings page

MY IDEA - I imagine that i will have to connect each on and off switch too its corresponding array of words and then code up if, then statements for each button. Then add all of the arrays together. However im not sure at all how to begin doing this. I have made a Table view with all the different on and off switches but have not yet added any functionality. I am also not sure how I am going to send the information from my table view to the second view controller.

I know this is alot to ask in one question but any help would be much appreciated. Thank you

Anthony Rubin
  • 69
  • 1
  • 1
  • 14

2 Answers2

0

You can use Delegation Pattern to send message from one view controller to another. For delegation pattern you make your SecondViewController as delegate of SettingsViewController and set up communication between both classes.

If you have to pass data from SettingsViewController To SecondViewController

Create protocol in SettingsViewController as

protocol SettingsViewControllerDelegate {
    func settingDidFinished(data : [String])
}

Create an id in SettingsViewController , so that you can assign any class as its delegate class.

class SettingsViewController : UIViewController {

// MARK:- Delegate
     var SettingsViewControllerDelegate ?

Call protocol method in SettingsViewController on submit button or wherever required.

 @IBAction private func doneTapped(_ sender: AnyObject) {
        delegate?.settingDidFinished(data : yourSettingsArray)
     }

Create an object of SettingsViewController in SecondViewController and assign SecondViewController as delegate of SettingsViewController as

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let settingsVc = segue.destinationViewController as? SettingsViewController {
    settingsVc .delegate = self
    }
}

Implement required protocol methods of SettingsViewController in SecondViewController

 extension SecondViewController: SettingsViewControllerDelegate {
     // # 4: "SecondViewController" implements "SettingsViewControllerDelegate " protocols:
     func settingDidFinished(data : [String]) {
         print("Settings finished")  // use settings Array here. Access your settings here and add/substract array as per your requirements.
     }
 }

Hope it helps.. Happy Coding..:)

luckyShubhra
  • 2,731
  • 1
  • 12
  • 19
  • I appreciate you imput. Can you recommend any way to differentiate between the different word groups? I still have not implemented a successful solution for that. – Anthony Rubin Jul 08 '17 at 21:55
0

There's a lot here, but you seem to have made a good start.

If the words and the categories are fairly fixed then the first thing I'd do is split the word list up into the different categories, then you can combine the ones you want for you images using:

let list1 = ["Bat", "Cow"]
let list2 = ["Frog", "Rabbit"]
let list3 = ["Parrot", "Tiger"]

var imageList: [String] {
  return list1+list2
}

You could keep an array of activeLists and then use a reduce function to return the final array:

var activeLists = [list1, list2]
var imageList: [String] {
    return activeLists.reduce([], {$0 + $1})
}

But you'll probably end up needing a more manageable data source than a simple String Array to store the information perhaps:

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

Then you could have:

let list1 =  List(words: ["Bat", "Cow"], active: true)
let list2 =  List(words: ["Frog", "Rabbit"], active: true)
let list3 =  List(words: ["Parrot", "Tiger"], active: true)
var wordLists = [list1, list2, list3]

var imageList: [String] {

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

    return active

}

Note: I wouldn't use maxImages as a constant as that will need to change, you can use imageList.count instead.

Regarding sending information, there's a few ways of doing this. One way is to use prepareForSegue to send the information to the new viewController. Something like this:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
  if let vc = segue.destination as? SettingsViewController {
    vc.wordLists = wordLists
  }
}

Then within Settings you can toggle individual word lists with:

wordLists[1].active = false

An easy way to match up switches to the array reference is to give each UISwitch a Tag within the Storyboard that matches its index in the wordLists Array, hook all of the UISwitches to the same IBAction then when it is triggered use:

@IBAction func switchAction(_ sender: UISwitch) {
  wordList[sender.tag].active = rollIntoLoanSwitch.isOn
}

Then you could use a Delegate to send the information back on each toggle or when you leave the view. Alternatively you can define your word lists in a separate Class, with a singleton and reference it from everywhere, it depends on how many different views you're going to need access to the word lists.

svarrall
  • 8,545
  • 2
  • 27
  • 32
  • Hello, ive split up the words into different lists as you recommended. But i am getting a few errors. where do I put struct List { let words: [String] var active: Bool } also how do i declare imagelist.count instead of max images? I am getting an error for that aswell saying there is an expected declaration. – Anthony Rubin Jul 08 '17 at 16:40
  • i am just having trouble implementing var imageList: [String] { let active = wordLists.reduce([]) { (result:[String], list:List) in if list.active { return result + list.words } else { return result } } return active } – Anthony Rubin Jul 08 '17 at 18:34
  • could you tell me what the secondviewcontroller should look like? It wont let me post all of the code here, however i think i might be close to cracking this but there are a few errors that i cant seem to fix – Anthony Rubin Jul 08 '17 at 20:34