antoniocasero/Panels

Panel reopens after being dismissed

JordanCoin opened this issue · 7 comments

I have created a Panel and when it is called I call the show function on the panel. Everything works fine here.

lazy var panelManager = Panels(target: self)
let panel = UIStoryboard.instantiatePanel(identifier: "Timer")
var panelConfiguration = PanelConfiguration(size: .custom(230))
panelConfiguration.animateEntry = true
panelConfiguration.useSafeArea = false
panelConfiguration.respondToDrag = true
panelConfiguration.respondToTap = false
self.panelManager.show(panel: panel, config: panelConfiguration)

My issue arrises when I try to dismiss the panel using the panelManager.
self.panelManager.dismiss()
I'm calling the dismiss function when I Post to NotificationCenter that the timer was stopped. I'm using the PanelNotification to see when it is presented to begin observing when the timer will be stopped.

    func panelDidPresented() {
        isPannelOpen = true
        panelDismissed = false
        NotificationCenter.default.post(name: .CurrentSession, object: nil, userInfo: ["sessionInterval": sessionInterval,
                                                                                       "sessionClientName": sessionClientName])
        NotificationCenter.default.addObserver(self, selector: #selector(timeLeft(notification:)), name: .TimeLeft, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(stopTimer(notification:)), name: .StopTimer, object: nil)

        print("Did present")
    }
    @objc func stopTimer(notification: Notification) {
        self.panelManager.dismiss()
        self.timer?.invalidate()
        self.timer = nil
        NotificationCenter.default.removeObserver(self, name: .TimeLeft, object: nil)
        NotificationCenter.default.removeObserver(self, name: .StopTimer, object: nil)
        NotificationCenter.default.removeObserver(TimerViewController(), name: .CurrentSession, object: nil)
    }

Initially it works and the panel will be dismissed, but when I scroll up or down on the table view...
weirdgrandioseghostshrimp-size_restricted

I can't seem to figure out how to stop it from doing this. Does using NotificationCenter not work well with Panels?

Hi Jordan, just to be sure, when you scroll down/up the panel appear again without any animation, right? The use of Notifications should not be a problem.

We need a bit of debugging. Are you presenting the panel using notifications too? could you check the view hierarchy? could you add a breakpoint in the show method to monitor who is adding a panel?
I will try to reproduce it locally, but I need to know how are you presenting the panel. (I mean, the code above to present the panel is in -viewDidLoad() ?)

Yes with no animation it appears again. I'm presenting the panel using notifications and when I look at the view hierarchy after dismissing the panel it's removed from the hierarchy. Then a moment later when I scroll it is re-added.

So in my app, the panel will open whenever my database returns a session that's start and end date objects fall between the current date. So at start there's a chance it will run a timer that I pass the session data too.

    @objc func presentPannel(runningTimer: Timer) {
        guard let userInfo = runningTimer.userInfo as? [String: Any], let session = userInfo["Session"] as? Session else { return }
        
        if let currentSessionInterval = userInfo["currentSessionInterval"] as? TimeInterval {
            self.sessionInterval = currentSessionInterval
        } else {
            let sessionTimeInterval = session.endDate.timeIntervalSince(session.startDate)
            self.sessionInterval = sessionTimeInterval
        }
        
        guard let currentSessionName = session.clientName else { return }
        self.sessionClientName = currentSessionName
        self.runningSession = session
        
        let panel = UIStoryboard.instantiatePanel(identifier: "Timer")
        var panelConfiguration = PanelConfiguration(size: .custom(230))
        panelConfiguration.animateEntry = true
        panelConfiguration.useSafeArea = false
        panelConfiguration.respondToDrag = true
        
        self.panelManager.show(panel: panel, config: panelConfiguration)
    }

The other way you can present the panel is by clicking on a cell in the didSelectRow method. It's the same code as above but not in a notification.

Also when I placed breakpoints and a few print statements I noticed after I dismiss it and scroll as it reopens the panelDidCollapse() function is called. I don't know if that will help or not.

Let me know if you think you need some more info, I'm very confused at why it keeps showing after it's dismissed.

Well, if the view is deleted from the hierarchy, it seems you are re-adding the panel in the code, one of them (put breakpoints in the self.panelManager.show to know who is firing the event). The reason why panelDidCollapse() is called is that the panelManager is listening to the tap events in the superview (so it can be closed tapping outside the view), if this is giving you problems, you could disable it in the configuration.
Let me know your findings.

So after further investigation, I noticed when I dismissed the panel and before the Panel reappeared it's still in the view hierarchy (Bell.TimerViewController pictured below)

screen shot 2018-12-05 at 10 55 16 am

So even with it dismissed and not visible the ViewController which holds the Panel is still in the hierarchy. Here's a screenshot of the app when I was looking at the Hierarchy (of course if I move the table or go to another view and come back it pops back up as if it was never dismissed).

img_0268

I've put breakpoints in the places I'm showing the panel and it is only called once. Is there a workaround for removing the panel from the subview? Since it conforms to ViewController and Panels It won't let me attempt to do this.

It seems you have a retain cycle in your panel. I saw that you are working with Timers, if the timer is not properly invalidated, then it retain the timer target, in this case, your ViewController.
If this is the case, it is not related to Panels, this is a lifecycle issue.
Let me know if my thinking is right :)

So that was it! I was holding a retain cycle for many things actually 😅 and ended up having to remove the panelVC's reference - let panelVC = UIStoryboard(name: "Timer", bundle: nil).instantiateViewController(withIdentifier: "TimerViewController") as! TimerViewController
To do that all I did was call self.panelVC.view.removeFromSuperview() while dismissing the panel.

        self.panelManager.dismiss {
            self.isPannelOpen = false
            self.panelDismissed = true
            self.panelVC.view.removeFromSuperview()
            NotificationCenter.default.removeObserver(self)
        }

This did the job and now It's dismissing! Thanks so much for your help!

Happy to help! ✨