0

i am new in swift. i have make a collectionview in nib file and i have a subview of that in main view controller. i want show array in collectionview but i could not. first i make a model of day:

struct Days {    
    let day: String
    let Image: String
    let temp: Double
}

then in daycell:

class DayCell: UICollectionViewCell {
    @IBOutlet weak var lblDay: UILabel!
    @IBOutlet weak var imgWeather: KBImageView!
    @IBOutlet weak var lblTemp: UILabel!    
    func updateViews(day: Days) {
        lblDay.text = day.day
        imgWeather.setImageWithKingFisher(url: day.Image)
        lblTemp.text = String(day.temp)
    }
}

then in public class, i get json data with alamofire and decode that and put them in my model:

public class Publics {
    static let instance = Publics()  

func showInfo(code: String, completion: @escaping ([Days]) -> Void)  {


    let DaysUrl = "http://api.openweathermap.org/data/2.5/forecast?id=\(code)&appid=3e28385cde03f6ee26c83b629ca274cc"
       Alamofire.request(DaysUrl, method: .get, parameters: nil, encoding: URLEncoding.httpBody).responseJSON { response in
            if let data = response.data {
                do {
                    self.myJson = try JSONDecoder().decode(JsonForecast.Response.self, from: data)                   

                    let counter = (self.myJson?.list.count)! - 1

                    let myDay1 = self.myJson?.list[counter-32]
                    let myDay2 = self.myJson?.list[counter-24]
                    let myDay3 = self.myJson?.list[counter-16]                   

                    let weekDay1 = self.getDate(date: self.getDayOfWeek((myDay1?.dt_txt)!)!)
                    let weekDay2 = self.getDate(date: self.getDayOfWeek((myDay2?.dt_txt)!)!)
                    let weekDay3 = self.getDate(date: self.getDayOfWeek((myDay3?.dt_txt)!)!)

                   let DaysArray = [
                        Days(day: weekDay1, Image: (myDay1?.weather[0].icon)!, temp: (myDay1?.main?.temp)!) ,
                        Days(day: weekDay2, Image: (myDay2?.weather[0].icon)!, temp: (myDay2?.main?.temp)!) ,
                        Days(day: weekDay3, Image: (myDay3?.weather[0].icon)!, temp: (myDay3?.main?.temp)!)
                    ]
                    completion(DaysArray)
                } catch {
                    print(error)
                }
            }
        }
    }

till here i do not have problem but now i want to show DaysArray in collectionview but i can not and my collectionview class is below:

class DayCollection: UIView, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {

    @IBOutlet var contentView: UIView!
    @IBOutlet weak var collectionDay: UICollectionView!
    var days = [Days]()


    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "DayCell", for: indexPath) as! DayCell

        Publics.instance.showInfo(code: "112931") { result in
            self.days = result
            print(self.days)
            DispatchQueue.main.async {
                self.collectionDay.reloadData()
            }
        }
        let day = days[indexPath.item]
        cell.updateViews(day: day)

            return cell

    }

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return days.count
    }

    override func awakeFromNib() {
        super.awakeFromNib()

        self.collectionDay.dataSource = self
        self.collectionDay.delegate = self
        self.collectionDay.register(UINib(nibName: "DayCell", bundle: nil), forCellWithReuseIdentifier: "DayCell")

    }
}

what should i do in mainVC class? (maybe i should i use from protocol delegate or no?)

1

1 Answer 1

2

First of all if you want to have constants in a struct declare them as constants. private(set) is horrible.

struct Days {    
    let day: String
    let dImage: String
    let temp: Double 
}

And never ever declare struct members as implicit unwrapped optionals which are initialized with non-optional values in an init method. The init method in a struct is not needed anyway.


You have to add a completion handler

public func showInfo(code: String, completion: @escaping ([Days]) -> Void)  {

...

let daysArray = [
   Days(day: weekDay1, Image: (myDay1?.weather[0].icon)!, temp: (myDay1?.main?.temp)!) ,
   Days(day: weekDay2, Image: (myDay2?.weather[0].icon)!, temp: (myDay2?.main?.temp)!) ,
   Days(day: weekDay3, Image: (myDay3?.weather[0].icon)!, temp: (myDay3?.main?.temp)!)
]
completion(daysArray)
}

Then in the class of the collection view add a data source array

var days = [Days]() 

and get the data

Publics.instance.showInfo(code: "Foo") { result in
   self.days = result
   DispatchQueue.main.async {
       self.collectionDay.reloadData()
    }
}

and return days.count in numberOfItemsInSection

Further force unwrap the cell

let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "DayCell", for: indexPath) as! DayCell

If the code crashes you made a design mistake. With the optional binding the code doesn't crash but you don't see anything and you don't know why

and get a day

let day = days[indexPath.item]
cell.updateViews(day)
Sign up to request clarification or add additional context in comments.

4 Comments

thank you from your perfect answer, but i have little problem. i made my collection in nib file and its class is ui view. i did your answer but i did not get answer. i update my post with your guide. but nothing show. please help me what should i do in main viewcontroller? #vadian
and why private(set) is horrible and when should i use from that?
No, no, you have to put the code to receive the data into viewDidLoad. In cellForItem put only the lines to dequeue the cell, get the day from the data source array and configure the cell
private(set) smells objective-c-ish and is pretty cumbersome in terms of Swift. In Objective-C there are no constants.

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.