2
votes

Impossible d'externaliser UICollectionViewDatasource dans une classe supplémentaire

J'ai un ViewController avec un CollectionView et je voudrais placer le UICollectionViewDataSource dans une classe supplémentaire, afin qu'il puisse être réutilisé. (Je n'utilise pas le constructeur d'interface).

Par conséquent, j'ai créé une classe supplémentaire:

override func viewDidLoad() {
    super.viewDidLoad()

    collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "MYIDENTIFIER")

    let myDataSource = MyDataSource()
    collectionView.delegate = myDataSource
    collectionView.dataSource = myDataSource

}

Dans le ViewController avec CollectionView, je l'ai défini:

class MyDataSource:  NSObject, UICollectionViewDelegate, UICollectionViewDataSource {

        public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
            return 5
        }

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

        public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MYIDENTIFIER", for: indexPath)
            cell.backgroundColor = .blue
            return cell
        }

}

Cependant, la collectionView restera vide - il n'y a pas de cellules dessus.

Cependant, si je mets toutes les fonctions DataSource dans la classe ViewController elle-même et définissez le délégué et DataSource sur self , alors tout fonctionne.

N'est-il pas possible d'externaliser l'UICollectionViewDataSource dans d'autres fichiers, ou avez-vous autre chose à faire?


5 commentaires

Je pense que vous devez initier le dataSource avec une collectionView. Créez un init init (collectionView: UICollectionView) dans votre classe dataSource


@GaloTorresSevilla et comment est-il censé aider?


@AndreyChernukha, il lancera la source de données avec la collectionView. Ensuite, vous définissez le collectionView.dataSource = self dans la classe dataSource. Je l'ai fait de cette façon et cela a fonctionné.


@GaloTorresSevilla et quelle est la différence réelle entre ce qui est fait et ce que vous suggérez? dans les deux cas, la vue de collection reçoit la source de données


Vraiment pas sûr. C'est pourquoi je dis que je pense. Je vais essayer de le découvrir


3 Réponses :


0
votes

merci pour l'aide! J'ai essayé ce que Galo a suggéré, mais pour moi, cela n'a pas fonctionné. Cependant, j'ai trouvé la solution:

Vous devez initialiser le délégué en tant que propriété du ViewController, et pas dans sa fonction viewDidLoad! Alors tout fonctionne correctement!

let myDataSource = MyDataSource()
override func viewDidLoad() {
    super.viewDidLoad()

    collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "MYIDENTIFIER")

    collectionView.delegate = myDataSource
    collectionView.dataSource = myDataSource

}


0 commentaires

1
votes

Juste au cas où. Voici la raison pour laquelle je disais à propos de l'appel de la méthode init. @Andrey Chernukha, désolé si cela a semé la confusion. C'est pourquoi j'ai dit que cela fonctionne avec le init mais je suppose que c'est la même raison que Pascal

import UIKit

class ViewController: UIViewController {

    lazy var collectionView : UICollectionView = {
        let layout = UICollectionViewFlowLayout()
        let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
        cv.backgroundColor = .green
        return cv
    }()

    var dataSource : CustomDataSource!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        self.view.addSubview(collectionView)
        collectionView.frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height)
        dataSource = CustomDataSource(collectionView: collectionView)
    }

}

class CustomDataSource : NSObject, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout, UICollectionViewDelegate {

    let collectionView : UICollectionView

    init(collectionView: UICollectionView) {
        self.collectionView = collectionView
        super.init()
        self.collectionView.dataSource = self
        self.collectionView.delegate = self
        self.collectionView.register(Cell.self, forCellWithReuseIdentifier: "cell")
    }

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

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
        cell.backgroundColor = .red
        return cell
    }

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

}


class Cell : UICollectionViewCell {

    override init(frame: CGRect) {
        super.init(frame: frame)
        setupViews()
    }

    func setupViews() {
        self.backgroundColor = .red
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

}

Je l'ai testé et la raison est que dataSource est faible dans une collectionView, il est donc désalloué immédiatement après son instanciation s'il est déclaré dans viewDidLoad()


0 commentaires

0
votes

C'est un autre problème de portée souvent négligé.

  override func viewDidLoad() {
super.viewDidLoad()

collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "MYIDENTIFIER")

let myDataSource = MyDataSource(). //See the problem here?
collectionView.delegate = myDataSource
collectionView.dataSource = myDataSource

} //myDataSource will be released!


0 commentaires