title: Swift: How to Display Parsed JSON Data in CollectionView inside a TableView?
body: <p>I'm trying to display my data as this <a href="https://i.stack.imgur.com/X6kmp.png" rel="nofollow noreferrer">image.</a></p>
  
  <p>My problem is that data displayed inside table view rows are all the same thing, while it should display all data of the array.</p>
  
  <p>This is the code I used to display the collectionView inside the tableView:</p>
  
  <pre><code>var onlineNews = ["local", "Economy", "Variety", "international", "sport"]
  
  var storedOffsets = [Int: CGFloat]()
  
  var tableIndexPath: IndexPath!
  
  @IBOutlet var listTableView: UITableView!
  
  var tableIndex: Int = 0
  
  var categoryResults = [JSON]() {
      didSet {
          listTableView.reloadData()
      }
  }
  
  let requestManager = RequestManager()
  
  
  override func viewWillAppear(_ animated: Bool) {
      super.viewWillAppear(animated)
  
      for i in onlineNews {
          requestManager.categoryList(sectionName: i)
      }
  }
  
  
  func numberOfSections(in tableView: UITableView) -&gt; Int {
      return 1
  }
  
  func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -&gt; Int {
      return onlineNews.count
  }
  
  func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -&gt; UITableViewCell {
      let cell = tableView.dequeueReusableCell(withIdentifier: "itemCell", for: indexPath) as! NewsTableViewCell
  
      tableIndex = indexPath.row
  
      return cell
  }
  
  func tableView(_ tableView: UITableView,
                 willDisplay cell: UITableViewCell,
                 forRowAt indexPath: IndexPath) {
          guard let tableViewCell = cell as? NewsTableViewCell else { return }
  
          tableViewCell.setCollectionViewDataSourceDelegate(dataSourceDelegate: self, forRow: (indexPath as NSIndexPath).row)
          tableViewCell.collectionViewOffset = storedOffsets[(indexPath as NSIndexPath).row] ?? 0
  }
  
  func tableView(_ tableView: UITableView,
                 didEndDisplaying cell: UITableViewCell,
                 forRowAt indexPath: IndexPath) {
  
          guard let tableViewCell = cell as? NewsTableViewCell else { return }
  
          storedOffsets[(indexPath as NSIndexPath).row] = tableViewCell.collectionViewOffset
  }
  
  func numberOfSections(in collectionView: UICollectionView) -&gt; Int {
      return 1
  }
  
  func collectionView(_ collectionView: UICollectionView,
                      numberOfItemsInSection section: Int) -&gt; Int {
  
      return categoryResults.count
  }
  
  func collectionView(_ collectionView: UICollectionView,
                      cellForItemAt indexPath: IndexPath) -&gt; UICollectionViewCell {
  
      let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ColCell",
                                                    for: indexPath) as! NewsCollectionViewCell
  
  
    cell.contentType.text = categoryResults[indexPath.row]["ContentType"].stringValue **// This is where I get the same values for all table view rows**
      cell.sectionName.text = onlineNews[tableIndex]
  
  
      return cell
  }
  </code></pre>
  
  <p>I'm sure someone can absolutely help me with this as I know that it takes only a small tweak to make it work, but not sure where.</p>
  
  <p><strong>Update:</strong></p>
  
  <p>I have followed a way that I believe should work, which is to declare the JSON array to be like this [[JSON]], and then use categoryResults[collection.tag][indexPath.item]["ContentType"].stringValue to get to the value. However, it gives me "index out of range" message. Do you have any clue how can I solve the issue?</p>
  
  <pre><code>var onlineNews = ["local", "Economy", "Variety", "international", "sport"]
  
  var storedOffsets = [Int: CGFloat]()
  
  @IBOutlet var listTableView: UITableView!
  
  var tableIndex: Int = 0
  
  var categoryResults = [[JSON]]() { // updated
      didSet {
          listTableView.reloadData()
      }
  }
  
  let requestManager = RequestManager()
  
  override func viewDidLoad() {
      super.viewDidLoad()
  
      requestManager.resetCategory()
  
      updateSearchResults()
  
      NotificationCenter.default.addObserver(self, selector: #selector(ViewController.updateSearchResults), name: NSNotification.Name(rawValue: "categoryResultsUpdated"), object: nil)
  
  
  }
  
  override func viewWillAppear(_ animated: Bool) {
      super.viewWillAppear(animated)
  
      for i in 0..&lt;onlineNews.count {
          requestManager.categoryList(sectionName: onlineNews[i])
  
  
      }
  
  }
  
  func updateSearchResults() {
      categoryResults = [requestManager.categoryResults] // updated
  }
  
  func numberOfSections(in tableView: UITableView) -&gt; Int {
      return 1
  }
  
  func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -&gt; Int {
      return onlineNews.count
  }
  
  func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -&gt; UITableViewCell {
      let cell = tableView.dequeueReusableCell(withIdentifier: "itemCell", for: indexPath) as! NewsTableViewCell
  
      tableIndex = indexPath.row
  
      return cell
  }
  
  func tableView(_ tableView: UITableView,
                 willDisplay cell: UITableViewCell,
                 forRowAt indexPath: IndexPath) {
          guard let tableViewCell = cell as? NewsTableViewCell else { return }
  
          tableViewCell.setCollectionViewDataSourceDelegate(dataSourceDelegate: self, forRow: (indexPath as NSIndexPath).row)
          tableViewCell.collectionViewOffset = storedOffsets[(indexPath as NSIndexPath).row] ?? 0
  
  }
  
  func tableView(_ tableView: UITableView,
                 didEndDisplaying cell: UITableViewCell,
                 forRowAt indexPath: IndexPath) {
  
          guard let tableViewCell = cell as? NewsTableViewCell else { return }
  
          storedOffsets[(indexPath as NSIndexPath).row] = tableViewCell.collectionViewOffset
  
  
  }
  
  func numberOfSections(in collectionView: UICollectionView) -&gt; Int {
      return 1
  }
  
  
  func collectionView(_ collectionView: UICollectionView,
                      numberOfItemsInSection section: Int) -&gt; Int {
      return categoryResults[collectionView.tag].count // updated
  }
  
  
  func collectionView(_ collectionView: UICollectionView,
                      cellForItemAt indexPath: IndexPath) -&gt; UICollectionViewCell {
  
      let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ColCell",
                                                    for: indexPath) as! NewsCollectionViewCell
  
  
      cell.contentType.text = categoryResults[collectionView.tag][indexPath.row]["ContentType"].stringValue // updated
  
  
  
      return cell
  }
  </code></pre>
  
  <p>This the content of RequestManager class (where I call the API):</p>
  
  <pre><code>var categoryResults = [JSON]()
  
  func categoryList(sectionName: String) {
  
      let url = "http://mobile.example.com/api/Content?MobileRequest=GetCategoryNews&amp;PageNo=1&amp;RowsPerPage=10&amp;Category=\(sectionName)&amp;IssueID=0&amp;Type=online"
      print("this is the url \(url)")
  
      Alamofire.request(url, method: .get).responseJSON{ response in
          if let results = response.result.value as? [String:AnyObject] {
              let items = JSON(results["Data"]?["OnlineCategoryNews"]! as Any).arrayValue
  
              self.categoryResults += items
  
              NotificationCenter.default.post(name: NSNotification.Name(rawValue: "categoryResultsUpdated"), object: nil)
  
          }
  
      }
  
  }
  
  func resetCategory() {
      categoryResults = []
  }
  
  deinit {
      NotificationCenter.default.removeObserver(self)
  }
  </code></pre>
  
  <p><strong>Update 2:</strong></p>
  
  <p>And here is the method where the collectionView.tag is assigned. This is added to the tableViewCell class:</p>
  
  <pre><code>func setCollectionViewDataSourceDelegate
      &lt;D: protocol&lt;UICollectionViewDataSource, UICollectionViewDelegate&gt;&gt;
      (dataSourceDelegate: D, forRow row: Int) {
  
      collectionView.delegate = dataSourceDelegate
      collectionView.dataSource = dataSourceDelegate
      collectionView.tag = row
      collectionView.bounds.size.width = self.bounds.size.width
      collectionView.reloadData()
  
  
  
  }
  </code></pre>