-1

hey I have trouble to access my global array, because it's empty. I know this question I already ask in this link How to access global array in Swift 4?

but they not show it in a code, so I don't understand how to implement it. can anyone show me how to do it? this is my code

var prayers = [Prayer]() //This is my global array

func fetchPrayer() {
    guard let city = self.city else { return}

    self.prayers = []
    APIServices.shared.fetchPrayer(name: city) { (results) in
        results.datetime.forEach({ (time) in
            let shubuh = Prayer(prayerName: "Shubuh", prayerIcon: #imageLiteral(resourceName: "PartlyCloudyNight"), prayerTime: time.times.Fajr)
            let dzuhur = Prayer(prayerName: "Dzuhur", prayerIcon: #imageLiteral(resourceName: "Sunny"), prayerTime: time.times.Dhuhr)
            let ashar = Prayer(prayerName: "Ashar", prayerIcon: #imageLiteral(resourceName: "PartlyCloudyDay"), prayerTime: time.times.Asr)
            let maghrib = Prayer(prayerName: "Maghrib", prayerIcon: #imageLiteral(resourceName: "Overcast"), prayerTime: time.times.Maghrib)
            let isya = Prayer(prayerName: "Isya", prayerIcon: #imageLiteral(resourceName: "Clear"), prayerTime: time.times.Isha)
            self.prayers.append(contentsOf: [shubuh, dzuhur, ashar, maghrib, isya])

        })
        DispatchQueue.main.async {
            self.updateUI()
            self.tableView.reloadData()
        }
    }
}

This is my table view code, I put the func setupTableView in viewDidLoad

extension PrayerController: UITableViewDelegate, UITableViewDataSource {
func setupTableView() {
    tableView.delegate = self
    tableView.dataSource = self
    tableView.register(PrayerTimeViewCell.self, forCellReuseIdentifier: self.cellId)
    tableView.separatorColor = .clear
    tableView.backgroundColor = .clear
    tableView.rowHeight = 53
}

//MARK:- TableView
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return prayers.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as! PrayerTimeViewCell

    let prayer = prayers[indexPath.row]
    cell.prayer = prayer

    return cell
  }
}

This is where the code is have an error index out of range

func updateUI() {
    let prayer0 = prayers[0].prayerTime
    let prayer1 = prayers[1].prayerTime
    let prayer2 = prayers[2].prayerTime
    let prayer3 = prayers[3].prayerTime
    let prayer4 = prayers[4].prayerTime
}
ferryawijayanto
  • 569
  • 4
  • 18
  • 1
    You should [edit] your question to include all relevant code in the form of a [mcve]. How's `updateUI` defined? Are your `tableView` `dataSource` methods set up correctly? You should include those as well. – Dávid Pásztor Nov 27 '18 at 09:20
  • @DávidPásztor okey I already fix my question, thank you to remind me :) – ferryawijayanto Nov 27 '18 at 09:30
  • How can you be sure that there are five elements in the `prayers` array? Please show the call stack. – Andreas Oetjen Nov 27 '18 at 09:37

1 Answers1

1

First, how will you ever be sure that there are five prayers in the prayers array when up call updateUI?

Second, you should avoid possible concurrent access of the global variables. I would suggest to modify your code the following way:

APIServices.shared.fetchPrayer(name: city) { (results) in
    var newPrayers = [Prayer]()
    results.datetime.forEach({ (time) in
        let shubuh = Prayer(prayerName: "Shubuh", prayerIcon: #imageLiteral(resourceName: "PartlyCloudyNight"), prayerTime: time.times.Fajr)
        let dzuhur = Prayer(prayerName: "Dzuhur", prayerIcon: #imageLiteral(resourceName: "Sunny"), prayerTime: time.times.Dhuhr)
        let ashar = Prayer(prayerName: "Ashar", prayerIcon: #imageLiteral(resourceName: "PartlyCloudyDay"), prayerTime: time.times.Asr)
        let maghrib = Prayer(prayerName: "Maghrib", prayerIcon: #imageLiteral(resourceName: "Overcast"), prayerTime: time.times.Maghrib)
        let isya = Prayer(prayerName: "Isya", prayerIcon: #imageLiteral(resourceName: "Clear"), prayerTime: time.times.Isha)
        newPrayers.append(contentsOf: [shubuh, dzuhur, ashar, maghrib, isya])

    })
    DispatchQueue.main.async {
        self.prayers = newPrayers
        self.updateUI()
        self.tableView.reloadData()
    }
}

Here, you create a local newPrayers array in the fetchPrayer closure. You fill the array, and after finished, in the main thread, you then "publish" your results by assigning self.prayers to the new array.

Nevertheless, in updateUI you should definitly check if you have the correct amount of elements in the array.

Andreas Oetjen
  • 9,889
  • 1
  • 24
  • 34
  • hey for your first question actually I always think that when I append in the completion block the value will store in my global array, but that's where the problem is I don't know that the async need to finish first. for the second question, I need to grab a value in a certain object so that's why I need use concurrent. is there another way to grab a value in a certain object? – ferryawijayanto Nov 27 '18 at 09:56
  • To get an element out of the array, you first should check the `count` of the array to make sure the index is within a valid range. – Andreas Oetjen Nov 27 '18 at 12:50