SwiftKickMobile / SwiftMessages

A very flexible message bar for UIKit and SwiftUI.
MIT License
7.24k stars 741 forks source link

Lower or equal level window's views disappear upon hide #467

Closed twomonthsforany closed 3 years ago

twomonthsforany commented 3 years ago

Hello! First of all, my team and I are really overwhelmed by your library and would like to give a sincere word of appreciation. However, we have come across a bizarre situation as mentioned in the title of the issue.

To give a more concise and sufficient context, I will provide an example below.

Assuming we have two different instances of the SwiftMessages class

let a = SwiftMessages() let b = SwiftMessages()

the reproduced cases are as follows

  1. (a) shows a view with a presentationContext of .window(.normal) and (b) also shows a view with a presentationContext of .window(.normal). When (a) is hidden via a.hide(), both (a) AND (b) disappear. (Possible Error?)

  2. (a) shows a view with a presentationContext of .window(.statusBar) and (b) shows a view with a presentationContext of .window(.normal). When (a) is hidden via a.hide(), both (a) AND (b) disappear. (Also a possible error?)

  3. (a) shows a view with a presentationContext of .window(.normal) and (b) shows a view with a presentationContext of .window(.statusBar). When (a) is hidden via a.hide(), only (a) disappears. (This case seems to be the expected behavior however the cases 1 and 2 do not seems to behave this way.)

Also, when (b) disappears upon (a)'s hide, (b)'s didHide is not called. Furthermore, when trying to show a new view via using (b)'s show() function, the view seems to be enqueued and not shown visually.

This phenomenon is only occuring in iOS 14 and above.

Could I be missing some sort of fundamental swift knowledge? Or could the reproduced cases be unexpected errors? Either way I would really appreciate some insight on this. Thank you very much!

wtmoose commented 3 years ago

Sorry to hear you're having trouble. I attempted to reproduce your issue, but didn't have any luck. Maybe you could take a look at the sample project I attached and help me figure out how to reproduce?

The code looks like this and does scenario (1) when you tap the "Test" button. The project is on 9.0.2.

class ViewController: UIViewController {

    let a = SwiftMessages()
    let b = SwiftMessages()

    @IBAction func testTapped() {
        let aMessage = MessageView.viewFromNib(layout: .cardView)
        let bMessage = MessageView.viewFromNib(layout: .cardView)
        aMessage.configureContent(title: "A Message", body: "Lorem ipsum dolor sit amet, consectetur adipiscing elit")
        bMessage.configureContent(title: "B Message", body: "Lorem ipsum dolor sit amet, consectetur adipiscing elit")
        var aConfig = a.defaultConfig
        var bConfig = b.defaultConfig
        aConfig.presentationContext = .window(windowLevel: .normal)
        bConfig.presentationContext = .window(windowLevel: .normal)
        aConfig.duration = .forever
        bConfig.duration = .forever
        aConfig.presentationStyle = .top
        bConfig.presentationStyle = .bottom
        a.show(config: aConfig, view: aMessage)
        b.show(config: bConfig, view: bMessage)
        DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
            self.a.hide()
        }
    }
}

SwiftMessagesTest.zip

twomonthsforany commented 3 years ago

Hi Tim! (If it's alright to call you that..? ) Thank you for such a fast response. I forgot to mention that I am using SwiftMessages 9.0.1! If it's fine with you I would like to suggest steps to reproduce the bug. Could you remove the asyncAfter function and hide the shown message via any userInteractions? Such as swiping to dismiss or tapping outside the view area? The error (1) mentioned in my former comment can be seen when done so! Thank you! Look forward to hearing from you

wtmoose commented 3 years ago

Hi Tim! (If it's alright to call you that..? )

Yep.

I forgot to mention that I am using SwiftMessages 9.0.1!

The specific problem you're describing was fixed in 9.0.2

wtmoose commented 3 years ago

The specific problem you're describing was fixed in 9.0.2

No, that's wrong. It was 9.0.1. I'll take another look.

wtmoose commented 3 years ago

OK I can reproduce it now. I believe it's related to the keyWindow issue that was supposed to be fixed in 9.0.1, but slightly different since there are two instance of SwiftMessages in the mix.

455 #458 Restore key window after message is interacted with. When a message becomes the key window, such as if the user interacts with the message, iOS does not automatically restore the previous key window when the message is dismissed. SwiftMessages has some logic in WindowViewController to restore the key window. This change makes that logic more robust.

I'll look into it. I suspect that SwiftMessages should not rely on kewWindow being set in order to work.

wtmoose commented 3 years ago

@twomonthsforany I've been swamped at work and hadn't had time to go through my backlog of SwiftMessages issues. Apologies for keeping you waiting.

The problem was that SwiftMessages calls makeKeyAndVisible() on the previous key window if the message you're dismissing is in a key window. When you dismiss interactively, the message's window becomes the key window. It turns out that calling makeKeyAndVisible() on the app's main window causes all of the SwiftMessages windows to be removed by the system.

The fix is to only call makeKey() on the previous key window. There was no valid reason to tell the previous key window to be visible in the first place.

The fix is currently waiting on work/9.0.3 for verification if the issue is still of interest to you and you'd like to check.

wow-such-amazing commented 3 years ago

This change also fixes one of my issues 🤩 Thank you!

I've been displaying a custom "PIPWindow" (with normal window level) on top of the "MainWindow" (also with normal window level) in order to have a Picture in Picture logic. And the problem was that the SwiftMessages was calling MakeKeyAndVisible on the MainWindow cause it was the "previous" key window and this was leading to hiding my PIPWindow 💥

I also implemented a change on my side and assigned status bar level to PIPWindow and alert level to all SwiftMessages. This solved my bug even on 9.0.2 🌚

wtmoose commented 3 years ago

Released 9.0.3