0

I've been working on a side project in swift that is basically a word of the day app. I've stored 30 words and content into an array and have been trying to update the word each day. I've tried a few fixes but to no avail. I can only ever get the first array to show even if I change the date on my phone.

Are the wordNumber and wordOfDay in conflict? How can I adapt this so a new word pops up each day?

let wordList =
[
    Words(word: "aaa", pronounciation: "bbbb", type: "noun", definition:"blah"),
    Words(word: "bbb", pronounciation: "cccc", type: "adjective", definition:"blah")
]

var wordNumber = 0;


class ViewController: UIViewController {

    @IBOutlet weak var wordLabel: UILabel!
    @IBOutlet weak var pronounciationLabel: UILabel!
    @IBOutlet weak var wordTypeLabel: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()

        updateWord()
    }

    @IBAction func prepareForUnwind (segue: UIStoryboardSegue){}

    func updateWord()
    {
        let date = Date()
        let dateIndex = Int(date.timeIntervalSince1970) / (60*60*24)
        let wordOfDay = wordList[dateIndex % wordList.count]


        wordLabel.text = wordList[wordNumber].word
        pronounciationLabel.text = wordList[wordNumber].pronounciation

    }

}
4
  • you want random word to come up every day. right? Commented Jan 7, 2020 at 19:23
  • 1
    You get fill wordOfDay with the proper number and then use wordNumber which stays 0... Commented Jan 7, 2020 at 19:32
  • "I can only ever get the first array to show even if I change the date on my phone" - what do you mean by first array? Commented Jan 7, 2020 at 19:42
  • sorry, I can see how that was confusing. I only get the 0 position in the array. Commented Jan 7, 2020 at 21:37

4 Answers 4

3

An easy way is to get the index of the current day from Calendar.

As day of month starts with 1 and array indices are zero-based you have to decrement the value. Consider that a couple of months have 31 days.

func updateWord()
{
    let day = Calendar.current.component(.day, from: Date())
    let wordOfDay = wordList[day - 1]

    wordLabel.text = wordList[wordNumber].word
    pronounciationLabel.text = wordList[wordNumber].pronounciation
}

However if you want a random word once each day you have to save the current day number and the current random index in UserDefaults. Load it in viewDidLoad and compare the day with the current value. If both values are equal get the word by the saved index. If they are not equal get a random number between 1 and 31 and save the current day number and index.

Sign up to request clarification or add additional context in comments.

1 Comment

So if I wanted today to be the first position in the array I would [day - 8]?
2

I would say store 31 values in your array as there can be 31 days max. Then according to current day, show your word of the day.

func updateWord() {
  let currentDay = Calendar.current.component(.day, from: Date()) // this would return the current day in Int, like today is 8th Jan, so it would return 8
  let wordOfDay = wordList[currentDay-1] // -1 because array index starts from 0 
  wordLabel.text = wordOfDay.word
  pronounciationLabel.text = wordOfDay.pronounciation
}

3 Comments

Thank you! What if I wanted more than 30 days?
Also wordOfDay.word basically would replace [wordNumber] correct?
@jjdthompson exactly. and the above case is valid for 31 days. what do you mean by more than 30 days?
1

I would try a couple things:

Unless there is a specific reason why you are manually calculating dateIndex, use:

let calendar = Calendar.current
calendar.component(.day, from: Date()) 

Where calendar.component(.day, from: Date()) returns Int

Also, I see that wordList has only two values. It might be that the date index you are submitting is out of range for wordList. To test this, try manual input like below. This should work if array index was the problem.

wordLabel.text = wordList[0].word

Finally for readability, it might make sense to do something like:

let firstWord = Words(word: "aaa", pronounciation: "bbbb", type: "noun", definition:"blah")
let secondWord = Words()
let wordList =
[
    firstWord, secondWord, etc.
]

5 Comments

Thank you! I have 30 values with the potential to add additional 30 days or additional "months". Is there a more efficient or formal way to add all those words in rather than just writing them all into the code? Say even for a year of content
1. If you are considering months, you would consider "switch case" to organize which month/day combination should populate which word. 2. If you have to hard code this into swift, you may be able to use a for loop to make the process quicker. However, this sounds like something you may want to store in a table and populate after querying through that table, rather than putting in values as hard code. That being said, I would suggest you ask a separate question so that someone can answer in more detail. Hope this helps!
Thank you! Very helpful!
Ok great! Please remember to mark this question as answered.
@jjdthompson You could store words as a JSON file inside your app's bundle, make your Word struct conform to Codable and then use a JSONDecoder for a relatively straightforward way to read your database of words/info into an array.
1

While the app is running, there's nothing in your code that would actually tell the view controller to refresh itself, or to check the date again and pick another word.

One way to solve this might be to start a timer in viewDidLoad(), either repeating in a short interval or repeating every 24hours starting from midnight.

A different method might be to check the date and present a new word only when the user opens/activates/switches back to the app. This might be done by adding an observer, something like the following:

NotificationCenter.default.addObserver(self, selector: #selector(didEnterBackground), name: UIApplication.didBecomeActiveNotification, object: nil)

or as follows if your app has a UIWindowSceneDelegate:

if #available(iOS 13.0, *) {
    NotificationCenter.default.addObserver(self, selector: #selector(didBecomeActive), name: UIScene.didActivateNotification, object: nil)
} else {
    NotificationCenter.default.addObserver(self, selector: #selector(didBecomeActive), name: UIApplication.didBecomeActiveNotification, object: nil)
}

Inside your didBecomeActive function (or equivalent) you could then check the date and fetch another random word.

2 Comments

ah okay interesting. So if the app doesn't close, and remains "running" in the background even tomorrow it wouldn't update unless I implemented one of the methods you suggest.
Yep, probably other ways to do it too – the gist is your existing updateWord function is only executed once unless the app's been in the background a very long time, or the user removes your app from their app switcher. Also edited my answer as I confusingly had a nonsensical method name didEnterBackground instead of didBecomeActive 😅

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.