0

I have a collectionView to which the data (String) is passed from another VC upon load. Now when I want to pass this data (String) to the UICollectionReusabelView. I am performing the following steps

CollectionViewVC:

class PhotoDetailVC: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout, PDHeaderViewDelegate {



// Following variables are the ones to which the data is passed to. 
var image : String!
var user: User!
var post: Posts!


@IBOutlet weak var collectionView: UICollectionView!


override func viewDidLoad() {
    super.viewDidLoad()

    print(post.imageURL)

    collectionView.delegate = self
    collectionView.dataSource = self

    setupCells()
    increaseView()
}


func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
    let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "mainImage", for: indexPath) as! PDHeader

    // I am setting the ReusableView properties through this section. Instead I just want to pass them to the header and then do stuff over there.

    header.post = self.post
    header.lol = post.postauthor
    header.label.text = post.caption
    header.label.sizeToFit()
    header.delegate = self
    let ref = URL(string: post.imageURL)
    Nuke.loadImage(with: ref!, into: header.mainPic)
    imageInHeaderForAuthor(author: post.postauthor, view: header.profilePic)

    return header
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {

    let size = CGSize(width: collectionView.frame.width, height: collectionView.frame.height - 15)
    return size
}


func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {

    let width = (collectionView.bounds.size.width/3) - 1
    let size = CGSize(width: width, height: width)
    return size

}

func collectionView(_ collectionView: UICollectionView,
                    layout collectionViewLayout: UICollectionViewLayout,
                    minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
    return 1.0
}

func collectionView(_ collectionView: UICollectionView, layout
    collectionViewLayout: UICollectionViewLayout,
                    minimumLineSpacingForSectionAt section: Int) -> CGFloat {
    return 1.0
}


func imageInHeaderForAuthor(author: String, view: UIImageView){
    FBDataservice.ds.REF_USERS.child(author).observeSingleEvent(of: .value, with: { (snapshot) in
        if let allData = snapshot.value as? Dictionary<String, Any> {
            if let cred = allData["credentials"] as? Dictionary<String, Any> {
                let postuser = User(userid: author, userData: cred)
                if postuser.userPic != nil {
                    let req = URL(string: postuser.userPic)
                    Nuke.loadImage(with: req!, into: view)
                }
            }
        }
    })
}

}

ReusableView:

class PDHeader: UICollectionReusableView, FloatyDelegate {

@IBOutlet weak var label: UILabel!
@IBOutlet weak var mainPic: UIImageView!
@IBOutlet weak var profilePic: UIImageView!

var image : String!
var post: Posts!
var lol: String!
var floaty = Floaty()
var isOwner : Bool!
var delegate: PDHeaderViewDelegate!



override func awakeFromNib() {
    super.awakeFromNib()

    //This returns nil every time.
    print(post.postauthor)

    layoutFAB()
    profilePic.makeCircle()
    label.addDropShadow(opacity: 3, radius: 8)

}




func setDelegate(delegate: PDHeaderViewDelegate) {
    self.delegate = delegate
}

func layoutFAB() {
    floaty.openAnimationType = .pop
    floaty.buttonImage = UIImage(named: "options")
    floaty.addItem("Report", icon: UIImage(named: "trash")) { item in
        self.delegate.fabReportClicked()
    }
    if isOwner{
        floaty.addItem("Edit Profile", icon: UIImage(named: "edit")) { item in
            self.delegate.fabEditClicked()
        }
        floaty.addItem("Delete", icon: UIImage(named: "trash")) { item in
            self.delegate.fabDeleteButton()
        }
    }

    floaty.fabDelegate = self
    floaty.buttonColor = UIColor.white
    floaty.hasShadow = true
    floaty.size = 45
    addSubview(floaty)
}

}

I have commented the code with the issues. TL;DR - The collections doesn't pass data to header and as a result I have to set them from viewForSupplementaryElementOfKind.

what is the actual issue here? Is the header being load before the data is passed to it? If not, how can I fix this?

Aakash Dave
  • 866
  • 1
  • 15
  • 30
  • 1) post data will alway nil in awakefromNib as variable is not set yet. 2) there is ambiguity **header.post = self.post header.post = post.postauthor**. you set twice to a variable.. its may cause post.postauthour is nil – Alizain Prasla Nov 16 '17 at 14:00
  • Edited my question. Was a mistake while pasting the code – Aakash Dave Nov 16 '17 at 14:09
  • You didn't mention what is actual problem? is image is not loading? – Alizain Prasla Nov 16 '17 at 14:19
  • The problem is that `awakeForNib()` is being called before you're setting all those values in `collectionView:viewForSupplementaryElementOfKind:at:`, so all the layout logic is done with the wrong data. – Guy Kogus Nov 16 '17 at 14:20
  • Yes, I mentioned in the end. The image is not passed and so does the string. I have to set it up from the delegate method, can set it up internally. It alwasy returns nil – Aakash Dave Nov 16 '17 at 14:21
  • print your string in viewdidload. is it nil? so it may passing nil to header – Alizain Prasla Nov 16 '17 at 14:27
  • Nope! Its not nill when i print it. It just doesnt pass it. And that the question why. – Aakash Dave Nov 16 '17 at 14:28

1 Answers1

2

If I have understood you can try with this option:

class PDHeader: UICollectionReusableView, FloatyDelegate {

    @IBOutlet weak var label: UILabel!
    @IBOutlet weak var mainPic: UIImageView!
    @IBOutlet weak var profilePic: UIImageView!

    var image : String!
    var lol: String!
    var floaty = Floaty()
    var isOwner : Bool!
    var delegate: PDHeaderViewDelegate!

    var post: Posts!{
        didSet {
           lol = post.postauthor
           label.text = post.caption
           // etc ...
        }

Then:

func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
    let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "mainImage", for: indexPath) as! PDHeader

    header.post = self.post
    header.delegate = self

    return header
}
Francesco Deliro
  • 3,899
  • 2
  • 19
  • 24
  • Hey, appreciate the help. This solution works quite fine, but as soon as I try to access the `lol` out of `didSet` scope, it returns nil – Aakash Dave Nov 16 '17 at 15:13
  • 1
    Hi, if you need to use your lol value outside post didSet, for example in a function, you can do the same and call it in lol didSet. You are getting nil because you don't have the value set at the moment you are calling it. But if you want to reuse your header variables in your ViewController, after you have set the header post you can retrieve all your values. – Francesco Deliro Nov 16 '17 at 15:19
  • Fantastic! That does my job! – Aakash Dave Nov 16 '17 at 15:22
  • @FrancescoDeliro, I have the same issue, I done have a delegate such the above code as I built it using a CollectionviewController, I have done exactly the same steps you have recommended apart from the header.delegate = self line. I am still getting nil. Do I need the delegate? – captain_haddock Dec 06 '19 at 18:30
  • 1
    @captain_haddock Yes, sure. You need to set the delegate for the header and make your view controller conforms to it. – Francesco Deliro Dec 06 '19 at 18:42
  • @FrancescoDeliro: how does one set the delegate for the header, especially when I have used a UICollectionView controller? as when I try to drag the header view to the Collectionview, it doesn't give me a delegate option and i don't know how to do it programmatically, sorry I'm a noob at this. your help is appreciated. – captain_haddock Dec 09 '19 at 22:48
  • 1
    @captain_haddock I see what you mean now, the header in this example is a custom one, that’s why it has a delegate property. Without checking your code, the simplest solution I can think of is that you can handle in your view controller the actions you need. Anyway, if you want, you can send me a link to your project with an explanation of the problem you are facing :) – Francesco Deliro Dec 10 '19 at 07:10
  • @FrancescoDeliro Thanks dude, I will send you a link. Once again thanks for the support! – captain_haddock Dec 10 '19 at 19:08