Trying to display on a collectionview cell.

I'm trying to display different information from an api but all the values are nil. How do I unwrap them?


func update(with item: CurrentPlayer) {

firstName?.text = item.firstName

lastName?.text = item.lastName

team?.text = item.team

position?.text = item.positionCategory

playImg?.image = UIImage(named: "Grey")

imageController.fetchItemArtwork(url: item.photoUrl) {

(image) in

if let image = image {

DispatchQueue.main.async {

self.playImg?.image = image

}

}

}

}

Replies

How do your know all the values are nil ?


How do I unwrap them?


You cannot unwrap nils, unless you want to crash your app.


What is `imageController`? What is `fetchItemArtwork(url:)`? What is `CurrentPlayer`?

I guess any of them are malfunctioning and you may need to fix them so that you can get non-nil values.

I know they are nil because I tried to debug them and saw the values were nil so that was why they are not displaying. How can I display them then?


ImageController is constant that takes the function fetchItemArtwork which takes a url and turns it into a UIImage. CurrentPlayer is my class with the values for update. This is my ViewController


class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {


@IBOutlet weak var collections: UICollectionView!

@IBOutlet weak var theSearch: UISearchBar!

var cPlayerArr = [CurrentPlayer]()



override func viewDidLoad() {

super.viewDidLoad()

let layout = UICollectionViewLayout()

downloadJSON {

self.collections.reloadData()

//print("***\(self.cPlayerArr)***")

}

self.collections.register(CurrentPlayerCell.self, forCellWithReuseIdentifier: "playercell")

self.collections.delegate = self

self.collections.dataSource = self

}

func downloadJSON(completed: @escaping () -> ()) {

let url = URL(string: "https://api.sportsdata.io/v3/nba/scores/json/Players?key=apiKey")

URLSession.shared.dataTask(with: url!) {

(data, response, error) in

if error == nil {

do {

//put data in here

self.cPlayerArr = try JSONDecoder().decode([CurrentPlayer].self, from: data!)

DispatchQueue.main.async {

completed()

}

} catch {

print("JSON Error")

}

}

} .resume()

}


func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {

print(cPlayerArr.count)

return cPlayerArr.count


}

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

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

let item = cPlayerArr[indexPath.row]

cell.update(with: item)

return cell

}

saw the values were nil

Where did you see that? It is important because Xcode has some bug that it shows fake nil in some occasions.

Inspector of the debug area? Have typed some debugging command? Or some other way?


ImageController is constant that takes the function fetchItemArtwork which takes a url and turns it into a UIImage.

Please show the code.


CurrentPlayer is my class with the values for update.

Please show the code.


This is my ViewController

I cannot find anything obviously wrong in your ViewController. Please show other parts of your code.

my text labels for example all have UILabel? nil. Part of my func update in the first question.




Code 1: ImageController


class FetchImage {


func fetchItemArtwork(url: URL, completion: @escaping (UIImage?) -> Void) {
    let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
        if let data = data,
            let image = UIImage(data: data) {
            completion(image)
        } else {
            completion(nil)
        }
    }

    task.resume()
}
}


Code 2: CurrentPlayer class

import Foundation

struct CurrentPlayer: Codable, Hashable {
    let photoUrl: URL
    let firstName: String
    let lastName: String
    let positionCategory: String
    let team: String
   
    enum CodingKeys: String, CodingKey {
        case photoUrl = "PhotoUrl"
        case firstName = "FirstName"
        case lastName = "LastName"
        case positionCategory = "PositionCategory"
        case team = "Team"
    }
   
    init(from decoder: Decoder) throws {
    let values = try decoder.container(keyedBy: CodingKeys.self)
    photoUrl = try values.decode(URL.self, forKey: CodingKeys.photoUrl)
    firstName = try values.decode(String.self, forKey: CodingKeys.firstName)
    lastName = try values.decode(String.self, forKey: CodingKeys.lastName)
    positionCategory =  try values.decode(String.self, forKey: CodingKeys.positionCategory)
    team = try values.decode(String.self, forKey: CodingKeys.team)

    }
}

Using the same identifier (such as firstNamle) for multiple purposes is really confusing.


Where is firstName, as UILabel, defined ?


It seems that firstName (as UILabel, not the String) is nil.

Thanks for showing your code. I thought `image` given to the closure was nil reading all the values are nil. It seems I was wrong.

(Please notice that you have not clarified what all the values are in your first post.)


Now you say all have UILabel? nil, you should better check some other things first.


I need to guess and assume one more things,

- The method `update(with:)` is defined in your custom cell class `CurrentPlayerCell`


So, how do you declare the text labels, how do you initialized them?


- If they are declared as IBOutlets, check the storyboard if all the IBOutlets are properly connected in the prototype cell

- If not, check your code if you properly instantiate UILabels and add them as a subview of the cell