0

I made a SearchViewController with tableView. I put some data in tableView from server (pictures of cats). But now I want to show not only all pictures, but also filtered by certain categories images. For this I suppose I need to push my second array with category's images into the tableView. I guess that to achieve this goal I need to reload tableView and change its dataSource, but how to realize it correctly I don't understand.

enter image description here

  1. Here is the method to get all pictures of cats

     func fetchData() {
     guard let endPoint = // myEndpoint else { return }
    
     endpoint.queryItems = queryParameters.map({ (key, value) in
         URLQueryItem(name: key, value: value) // some parameters
     })
    
     guard let url = endpoint.url else {
         return
     }
    
     var request = URLRequest(url: url)
     request.setValue(ApiClient.Identifiers.apiKey, forHTTPHeaderField: "x-api-key")
    
     let task = URLSession.shared.dataTask(with: request) { data, response, error in
         DispatchQueue.main.async {
             if error != nil {
                 print(error.debugDescription)
             } else {
                 do {
                     let myData = try JSONDecoder().decode([CatModel].self, from: data!)
                     self.catsModel = myData // catsModel is an array with struct with cats info (breed, category, id, etc.)
                     self.tableView.dataSource = myData as? any UITableViewDataSource
                     self.tableView.reloadData()
                 } catch let error {
                     print(error)
                 }
             }
         }
     }
     task.resume()
    

}

  1. Here is the method for filter by categories id :

    func fetchCategoryData(categoryID: Int) {
         let endpoint = URLComponents // url components
         guard let url = endpoint?.url else {
             return
         }
         var request = URLRequest(url: url)
         request.setValue(ApiClient.Identifiers.apiKey, forHTTPHeaderField: "x-api-key")
    
         let task = URLSession.shared.dataTask(with: request) { data, response, error in
             DispatchQueue.main.async {
                 if error != nil {
                     print(error.debugDescription)
                 } else {
                     do {
                         let myData = try JSONDecoder().decode([CatModel].self, from: data!)
                         self.catsModel = myData
                         self.tableView.reloadData()
                     } catch let error {
                         print(error)
                     }
                 }
             }
         }
         task.resume()
    
     }
    
    
  2. In CategoryViewController I made this method:

    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { let searchViewController = SearchViewController() let cat = catsModel[indexPath.row] searchViewController.fetchCategoryData(categoryID: cat.id) // this line works, but in fetchCategoryData doesn't happenings the reload of tableView with new data

    }

Thank you very much!

4
  • You don't need two data sources. You need to use a UICollectionView to add your category filters Commented Nov 27, 2022 at 1:57
  • @LeoDabus can you explain a little bit detailed, please? Commented Nov 27, 2022 at 14:40
  • @maytime Please clarify more about your problem, please explain current state and expected state briefly Commented Nov 28, 2022 at 11:33
  • @maytime can you add some screenshots of what you want to achieve? Commented Nov 28, 2022 at 12:56

2 Answers 2

2
+25

There are various ways to filter data - but the code you posted doesn't make much sense.

You say:

"self.catsModel = myData // catsModel is an array with struct with cats info"

and:

"self.tableView.dataSource = myData as? any UITableViewDataSource"

but, you cannot assign an Array as a table view data source.

One approach is to do this:

var allCats: [CatModel] = []
var filteredCats: [CatModel] = []

then set self as the data source:

self.tableView.dataSource = self

To start, download / retrieve ALL Cats data and "store" it in allCats.

When the user selects a "filter," fill filteredCats:

self.filteredCats = self.allCats.filter({ $0.id == selectedFilterID })

Now your data source funcs can look something like this:

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    if selectedFilterID == nil {
        return allCats.count
    }
    return filteredCats.count
}

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

    var thisCat: CatModel!

    if selectedFilterID == nil {
        thisCat = allCats[indexPath.row]
    } else {
        thisCat = filteredCats[indexPath.row]
    }

    // set the cell's values / properties

    return cell
}

IF your API has a database of lots and lots of Cats (such as 50,000), or you ALWAYS have a Filter selected, you may not want to download all of the data.

In that case, you don't need a filteredCats array...

Instead, when a Filter is selected, fill allCats by requesting only the matching records from your API and call reload data on the table view.

Your data source funcs are then simpler:

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return allCats.count
}

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

    let thisCat = allCats[indexPath.row]

    // set the cell's values / properties

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

Comments

0

I'm not sure but issue may get fixed with one line change

Instead of this -

self.tableView.dataSource = myData as? any UITableViewDataSource

Try writing this -

self.tableView.dataSource = self

Comments

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.