1

I have a UIViewController that has a UICollectionView with 4 custom cells. In one of the cells I have a UIButton that when tapped needs to access another one of the cells, to update an UIImage. How do I reference the collectionView reference in my UIViewController to pass it to the other NIB's?

//CollectionView
@IBOutlet weak var collectionView: UICollectionView!

Do I put something in my override func awakeFromNib() in order to reference the other cells?

Example:

let myCell = collectionView!.cellForItem(at: myIndexPath) as! MainCollectionViewCell

How do I reference collectionView from other NIB's?

Thanks

Paul S.
  • 1,342
  • 4
  • 22
  • 43
  • Three things I can quickly thing of: (1. delegation pattern 2. notification center 3. RxSwift observers) The cell shouldn't know about the collection view so the observers could be the other cells. Just be careful of strong reference cycles. – D. Greg Oct 13 '17 at 00:45
  • Thanks for the response. I was hoping to not use a delegate but will give it a go, unless there is another way around this. – Paul S. Oct 13 '17 at 01:19

1 Answers1

0

From an architectural perspective, the answer is "you don't."

The correct answer is to have a Model class, probably with properties that represent different parts of the model. When the user taps the button, it affects the model in some way (the button action should call a method on a model object. The method's name would be something that would make sense to the user of the app.)

When the model changes state, it should notify any Observers. Look up the Observer pattern, but basically, it's like an array of delegates.

The cell with the UIImage should be set up to observe the model and react to changes in the model which in this case happened to be due to the button tap, but could have occurred through other means as well.

First you need a model class:

class MyModel {
    typealias Observer = (MyModel) -> Void

    func add(observer: @escaping Observer) {
        observers.append(observer)
    }

    func updateImage() {
        // do what you need to do to update `myImage`
        // then call:
        update()
    }

    private (set) var image: UIImage?
    private var observers = [Observer]()

    private func update() {
        for each in observers {
            each(self)
        }
    }
}

Then make an instance of this model in your view controller:

let model = MyModel()

Now pass your view controller's model to each of the cells inside the cellForItemAt method.

cell.model = model

In the cell that has the image, you give it a model property like this:

var model: MyModel! {
    didSet {
        model.add(observer: { [weak self] updated in 
            self?.imageView.image = updated.image
        })
    }
}

The cell that has the button would have a normal model property and in the IBAction for the button, you would call model.updateImage().

var model: MyModel!

@IBAction func buttonTapped(_ sender: Any) {
    model.updateImage()
}
Daniel T.
  • 32,821
  • 6
  • 50
  • 72