Instagram / IGListKit

A data-driven UICollectionView framework for building fast and flexible lists.
https://instagram.github.io/IGListKit/
MIT License
12.88k stars 1.54k forks source link

IGListKit Not Reloading When New Notifications Comes in #1118

Closed Smiller193 closed 6 years ago

Smiller193 commented 6 years ago

So I have a notification screen in my app similar to Instagram which will let a user view whether people are interacting with them, new followers, etc. Currently, things are loading however whenever a new notification comes in the collectionView doesn't seem to update. I have implemented a similar screen in my commentsViewController but it isn't working the same way when I mirror the implementation. Ive added some of my code just to see if anything is going wrong any help would be appreciated.

import UIKit
import IGListKit
import Firebase

private let reuseIdentifier = "Cell"

class NotificationsViewController: UIViewController,NotificationsSectionDelegate {

    var emptyLabel: UILabel?
    //array of notifications which will be loaded by a service function
    var notifs = [Notifications]()
    var messagesRef: DatabaseReference?

    //This creates a lazily-initialized variable for the IGListAdapter. The initializer requires three parameters:
    //1 updater is an object conforming to IGListUpdatingDelegate, which handles row and section updates. IGListAdapterUpdater is a default implementation that is suitable for your usage.
    //2 viewController is a UIViewController that houses the adapter. This view controller is later used for navigating to other view controllers.
    //3 workingRangeSize is the size of the working range, which allows you to prepare content for sections just outside of the visible frame.

    lazy var adapter: ListAdapter = {
        return ListAdapter(updater: ListAdapterUpdater(), viewController: self)
    }()

    // 1 IGListKit uses IGListCollectionView, which is a subclass of UICollectionView, which patches some functionality and prevents others.
    let collectionView: UICollectionView = {
        // 2 This starts with a zero-sized rect since the view isn’t created yet. It uses the UICollectionViewFlowLayout just as the ClassicFeedViewController did.
        let view = UICollectionView(frame: CGRect.zero, collectionViewLayout: UICollectionViewFlowLayout())
        // 3 The background color is set to white
        view.backgroundColor = UIColor.white
        return view
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        //add line seperator to distance collectionView from top tab bar
        let lineSeparatorView = UIView()
        lineSeparatorView.backgroundColor = UIColor.black
        view.addSubview(lineSeparatorView)
         lineSeparatorView.anchor(top:view.topAnchor, left: view.leftAnchor, bottom: nil, right: view.rightAnchor, paddingTop: 2.5, paddingLeft: 0, paddingBottom: 0, paddingRight: 0, width: 0, height: 0.5)
        //will add the collectionView for the iglistkit 
        collectionView.frame = CGRect.init(x: 0, y: 5, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height-40)
        view.addSubview(collectionView)
        collectionView.alwaysBounceVertical = true
        adapter.collectionView = collectionView
        adapter.dataSource = self
        collectionView.register(NotificationCell.self, forCellWithReuseIdentifier: "NotificaationCell")
    }

    override func viewWillAppear(_ animated: Bool) {
        self.fetchNotifs()
    }

    fileprivate func fetchNotifs(){
        NotificationService.fetchUserNotif { (currentUserNotifs) in
            print("user has \(currentUserNotifs.count) notifications")
            self.notifs = currentUserNotifs
            self.notifs = self.sortNotifs(notifArray: self.notifs)
            self.adapter.performUpdates(animated: true)
        }
    }

    //will sort the notifications based off of timeStamp
    fileprivate func sortNotifs(notifArray: [Notifications]) -> [Notifications]{
        var tempNotifArray = notifArray
        tempNotifArray.sort(by: { (reply1, reply2) -> Bool in
            return reply1.timeStamp?.compare(reply2.timeStamp!) == .orderedDescending
        })
        return tempNotifArray
    }

    func NotificationsSectionUpdared(sectionController: NotificationsSectionController) {
        self.adapter.performUpdates(animated: true)

    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

extension NotificationsViewController: ListAdapterDataSource {
    // 1 objects(for:) returns an array of data objects that should show up in the collection view. loader.entries is provided here as it contains the journal entries.
    func objects(for listAdapter: ListAdapter) -> [ListDiffable] {
        let items:[ListDiffable] = notifs
        //print("comments = \(comments)")
        return items
    }

    // 2 For each data object, listAdapter(_:sectionControllerFor:) must return a new instance of a section controller. For now you’re returning a plain IGListSectionController to appease the compiler — in a moment, you’ll modify this to return a custom journal section controller.
    func listAdapter(_ listAdapter: ListAdapter, sectionControllerFor object: Any) -> ListSectionController {
        //the comment section controller will be placed here but we don't have it yet so this will be a placeholder
        let sectionController = NotificationsSectionController()
        sectionController.delegate = self

        return sectionController
    }

    // 3 emptyView(for:) returns a view that should be displayed when the list is empty. NASA is in a bit of a time crunch, so they didn’t budget for this feature.
    func emptyView(for listAdapter: ListAdapter) -> UIView? {
        let view = UIView()
        let emptyLabel = UILabel(frame: CGRect(x: 0, y: 0, width: self.view.bounds.size.width, height: self.view.bounds.size.height))
        let paragraph = NSMutableParagraphStyle()
        paragraph.lineBreakMode = .byWordWrapping
        paragraph.alignment = .center

        let attributes: [NSAttributedStringKey: Any] = [NSAttributedStringKey(rawValue: NSAttributedStringKey.font.rawValue): UIFont.systemFont(ofSize: 14.0), NSAttributedStringKey(rawValue: NSAttributedStringKey.foregroundColor.rawValue): UIColor.lightGray, NSAttributedStringKey(rawValue: NSAttributedStringKey.paragraphStyle.rawValue): paragraph]
        let myAttrString = NSAttributedString(string:  "No Notifications to Show", attributes: attributes)
        emptyLabel.attributedText = myAttrString
        emptyLabel.textAlignment = .center
        view.addSubview(emptyLabel)
        view.backgroundColor = UIColor.white
        return view
    }
}

//This is my section controller import Foundation import IGListKit import Firebase protocol NotificationsSectionDelegate: class { func NotificationsSectionUpdared(sectionController: NotificationsSectionController) } class NotificationsSectionController: ListSectionController { weak var delegate: NotificationsSectionDelegate? = nil weak var notif: Notifications?

    override init() {
        super.init()
        // supplementaryViewSource = self
        //sets the spacing between items in a specfic section controller
        inset = UIEdgeInsets(top: 5, left: 0, bottom: 0, right: 0)
    }

    // MARK: IGListSectionController Overrides
    override func numberOfItems() -> Int {
        return 1
    }

    override func sizeForItem(at index: Int) -> CGSize {
        let frame = CGRect(x: 0, y: 0, width: collectionContext!.containerSize.width, height: 50)
        var dummyCell = NotificationCell(frame: frame)
        dummyCell.notification = notif
        dummyCell.layoutIfNeeded()
        let targetSize =  CGSize(width: collectionContext!.containerSize.width, height: 55)
        let estimatedSize = dummyCell.systemLayoutSizeFitting(targetSize)
        let height = max(40+8+8, (estimatedSize.height))
        return  CGSize(width: collectionContext!.containerSize.width, height: height)
    }

    override func cellForItem(at index: Int) -> UICollectionViewCell {
        guard let cell = collectionContext?.dequeueReusableCell(of: NotificationCell.self, for: self, at: index) as? NotificationCell else {
            fatalError()
        }
        //  print(comment)
        cell.notification = notif
      //cell.delegate = self
        return cell
    }

    override func didUpdate(to object: Any) {
        notif = object as? Notifications
    }

    func NotificationsSectionUpdared(sectionController: NotificationsSectionController){
       print("Tried to update")
        delegate?.NotificationsSectionUpdared(sectionController: self)
    }

    override var minimumLineSpacing: CGFloat {
        get {
            return 0.0
        }
        set {
            self.minimumLineSpacing = 0.0
        }
    }

    deinit {
        print("NotifSectionController class removed from memory")
    }

}
Smiller193 commented 6 years ago

Wait sorry I realize what I did wrong. It was my database call as usual nothing to do with IGListKit lol