1

I am trying to display Data in a UICollectionView which worked perfectly exactly like i did in the whole app but for some reason, its not working in this case :

Here is the code needed to understand the issue :

SomeController :

func showContactsView(sender: RoundButton) -> Void {
        DispatchQueue.main.async {
            self.someView = SomeView()
            self.view.addSubview(self.someView)
            self.someView.setSomeViewViewConstraints(container: 
    self.view)
            self.someView.alpha = 0.0
            self.someView.contactsCollectionView.delegate = self
            self.someView.contactsCollectionView.dataSource = self
            self.someView.tabControlCallbacks["contacts"] = self.searchContacts
        }
    }

The controller init the view which contains the UICollectionView. This part is handled by autolayout and constraints, i have no issue whit it. It also inherits from UIColleCtionViewDelegate and UICollectionViewDataSource. :

class SomeController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate

The view init the collectionView and is displayed by a SegmentedControl which works perfectly :

private func initCollectionViews() {
        let layout = UICollectionViewFlowLayout()
        layout.sectionInset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
        layout.itemSize = CGSize(width: 50, height: 50)

        contactsCollectionView = UICollectionView(frame: CGRect.zero, collectionViewLayout: layout)
        contactsCollectionView.backgroundColor = UIColor.black.withAlphaComponent(0.6)
        contactsCollectionView.showsVerticalScrollIndicator = false
        contactsCollectionView.showsHorizontalScrollIndicator = false
        contactsCollectionView.register(AModelCollectionViewCell.self, forCellWithReuseIdentifier: "ContactsSelectModelCell")
        contactsCollectionView.translatesAutoresizingMaskIntoConstraints = false


        // Constraints to add when view is set dynamically
        contactsCollectionViewConstraints["leading"] = NSLayoutConstraint(item: contactsCollectionView, attribute: .leading, relatedBy: .equal, toItem: self, attribute: .leading, multiplier: 1.0, constant: 0.0)
        contactsCollectionViewConstraints["trailing"] = NSLayoutConstraint(item: self, attribute: .trailing, relatedBy: .equal, toItem: contactsCollectionView, attribute: .trailing, multiplier: 1.0, constant: 0.0)
        contactsCollectionViewConstraints["top"] = NSLayoutConstraint(item: tabControl, attribute: .bottom, relatedBy: .equal, toItem: contactsCollectionView, attribute: .top, multiplier: 1.0, constant: 0.0)
        contactsCollectionViewConstraints["bottom"] = NSLayoutConstraint(item: self, attribute: .bottom, relatedBy: .equal, toItem: contactsCollectionView, attribute: .bottom, multiplier: 1.0, constant: 0.0)
    }

and the display by the segmented Control on value changed :

func cleanViews() {
        if self.contactsCollectionView.superview != nil {
            self.contactsCollectionView.removeFromSuperview()
        }
        if self.favoritesCollectionView.superview != nil {
            self.favoritesCollectionView.removeFromSuperview()
        }
    }

func bounce() {
        self.cleanViews()
        switch self.actualControl {
        case -1:
            break
        case 0:
            // Some code
        case 1:
            self.addSubview(self.contactsCollectionView)
            for constraint in self.contactsCollectionViewConstraints {
                self.addConstraint(constraint.value)
            }
            if let callback = self.tabControlCallbacks["contacts"]! {
                callback()
            }
        default:
            fatalError("Unknown control")
        }
    }

    // Selectors UISegmentedControl
    func valueChanged(sender: UISegmentedControl) {
        if sender.selectedSegmentIndex == actualControl {
            tabControl.isMomentary = true
            sender.selectedSegmentIndex = -1
            tabControl.isMomentary = false
        }
        actualControl = sender.selectedSegmentIndex


        DispatchQueue.main.async {
            self.bounce()
        }
    }

As you can see i am setting a callback from the controller to the view in order to execute an action to my network and get the data to display on the collectionView. Here are the methods in the controller :

  //Collection Views Actions/Callbacks for selectContactsView
    func searchContacts() -> Void {
        let params : [String:Any] = [
            "id" : "-1",
            "name_begin" : ""
        ]

        self.network?.get(......, callback: afterSearchContacts)
    }

    func afterSearchContacts() -> Void {

        DispatchQueue.main.async {

            self.contactsSearchResults.removeAll()
            let usersData : [[String:Any]] = self.network?.lastResponse!["users"] as! [[String:Any]]
            let groupsData : [[String:Any]] = self.network?.lastResponse!["groups"] as! [[String:Any]]

            for userData in usersData {
                self.contactsSearchResults.append(User(fromData: userData))
            }
            for groupData in groupsData {
                self.contactsSearchResults.append(Group(fromData: groupData))
            }
            self.contactsView.contactsCollectionView.reloadData()
        }
    }

The reloadData is not working. Here are the methods of delegates and datasource before explaining which part is working and which is not :

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


        switch self.contactsView.actualControl {
        case 1:

            if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ContactsSelectModelCell", for: indexPath) as? AModelCollectionViewCell {
                cell.model = contactsSearchResults[indexPath.item]
                cell.fillCell()
                return cell
            }
        case 0:
                //some Code
                return cell
            }
        default:
            print("Unknown cell type")
        }
        fatalError("Unknown cell type")
    }

    func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 1
    }

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        let count = collectionView == contactsView.contactsCollectionView ? contactsSearchResults.count : favoritesSearchResults.count

        return count
    }

    //MARK: - UICollectionViewFlowLayoutDelegate
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return CGSize(width: 50.0, height: 50.0)
    }

I have a custom collection view cell which is working on other collectionViews so no problem with that. I also take care of differentiate the identifiers for all the different CollectionViews when i do the register. In this case, when i use breakpoints, the number of items in section is > 0 but when i do the reloadData in the main thread after my network set the contactsSearchResult, it never go through the collectionView cellForItemAt.

Any idea?

Poulpy
  • 134
  • 8
  • When you say not working, what is exactly is happening? Is it going to the data source methods? Can you print contactsCollectionView and see if it is not nil. Also check if its datasource is not nil – adev Jul 09 '17 at 19:42
  • When i say not working, i mean that collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath) is never executed in this case. ContactsCollectionView is obviously not nil, same for datasource. – Poulpy Jul 09 '17 at 19:49
  • Are you sure it is calling this line `self.contactsView.contactsCollectionView.reloadData()`? After that is it calling `numberOfSections` if you put breakpoint there? – adev Jul 09 '17 at 20:10
  • I have tested this before and just tested again now. Unfortunately yes this is the case. I don't understand why collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath) is not called just after numberOfSections been updated. Also count in numberOfSections is exactly 6 after reloadData been called. – Poulpy Jul 09 '17 at 20:16
  • Put breakpoint in swift self line and see if it is going there. Otherwise check if the datasource name is not misspelled. Also what is number of sections and what is number of items in each section? Is it correct? – adev Jul 09 '17 at 20:18
  • I am sorry swift self line ? Can you be more precise – Poulpy Jul 09 '17 at 20:21
  • I have checked datasource name and other parameters. Everything is fine – Poulpy Jul 09 '17 at 20:54
  • Sorry i meant `switch self.contactsView.actualControl {`. Put a breakpoint here. – adev Jul 09 '17 at 21:50
  • Just tried and had what i expected. Nothing happens because collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath) is never executed – Poulpy Jul 09 '17 at 22:15
  • We obviously can say that the problem comes from datasource. – Poulpy Jul 09 '17 at 22:16
  • Are you sure `numberOfItemsInSection` is returning 6? I doubt that is happening. If it is 6, you would have definitely got a call to line `switch self.contactsView.actualControl {` – adev Jul 09 '17 at 23:31
  • I know it is really weird and yes i am 10000% sure. For you to be sure about that i can make screenshot but believe me this is not normal. I know what i am doing, this exact code is working on other views in my app. I tried litteraly everything -> moving the delegate, adding a reference of the controller as a delegate and a datasource in the view etc... I cant figure out why i have this issue. Since i have posted this issue i am trying to debug this and believe me i am not a newcomer in the development world... Thanks for your help by the way – Poulpy Jul 09 '17 at 23:35
  • http://imageshack.com/a/img923/6613/LaAFnR.png – Poulpy Jul 09 '17 at 23:44
  • I have even tried to fire reloadData with a button on the UI after everything was set, the problem is still the same so it is not a thread issue. – Poulpy Jul 09 '17 at 23:54
  • Can you once check the frame of the collection view when reloading it? – bestiosdeveloper Jul 11 '17 at 15:46
  • I have already done that my view is displayed correctly, frame is ok. As i said, i have done my own collection view i do not have any more issues. Also i have done it by carefully checking the memory usage, it uses less memory than the built in one. – Poulpy Jul 12 '17 at 11:10

1 Answers1

-1

For those who read this post, i have ended up by coding my own CollectionView. Working like a charm.

Poulpy
  • 134
  • 8