LuckyDucko / Mopups

Popups For MAUI
BSD 3-Clause "New" or "Revised" License
274 stars 49 forks source link

[iOS] App crash when an element is removed from its parent layout #97

Open Santiago5050 opened 11 months ago

Santiago5050 commented 11 months ago

Exception "MauiContext should have been set on parent" when removing a child from its parent layout on iOS

Description: When a child is removed from its parent layout on iOS, an exception "MauiContext should have been set on parent" is thrown. Upon investigation, it seems that the issue arises during the cleanup process by Maui when attempting to clean a child that has already been cleaned by Mopups.

Proposed Solution: To address this issue, I suggest stopping listening the 'DescendantRemoved' event and the child handler cleanup in the iOS implementation of IPopupPlatform. By doing so, Maui will be able to properly handle the cleanup of the removed view.

Environment:

Repro ReproMopups.zip

Steps to reproduce

  1. Run the solution in an iOS device.
  2. Tap the 'Open popup' button.
  3. Tap the 'Add/Remove label' button. A label will be added with the first tap, but after the second the app will crash trying to remove the label from its parent layout.
Tamilarasan-Paranthaman commented 7 months ago

Are there any updates regarding this issue?

microspaze commented 6 months ago

The same issue in RGPopup.Maui: https://github.com/microspaze/RGPopup.Maui/issues/6

The fix commits: https://github.com/microspaze/RGPopup.Maui/commit/a64a99db191b0432e41b9ce5cd8aba61d5e10038 https://github.com/microspaze/RGPopup.Maui/commit/62ac001409208ccd7035ff80123ac4cf993914f5

rbev commented 1 month ago

is this issue getting any attention at all? i'd prefer not to have to rip mopups out but as mentioned here the Maui team aren't gonna fix this one for you

rbev commented 1 month ago

For anyone stumbling upon this issue the workaround is to modify the mappers thusly (from here)

//Workaround for: https://github.com/LuckyDucko/Mopups/issues/97
#if IOS
    Mopups.Platforms.iOS.PopupPageHandler.Mapper.AppendToMapping("FixingMopupCrash", (handler, view) =>
    {
        (view as Page).Appearing += (s, e) =>
        {
            var eventName = "DescendantRemoved";
            var eventInfo = typeof(Element).GetEvent(eventName);
            var descendantRemovedEvent = typeof(Element).GetField(eventName, BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
            if (descendantRemovedEvent.GetValue(view) is not Delegate eventDelegate)
            {
                return;
            }

            foreach (var d in eventDelegate.GetInvocationList())
            {
                eventInfo.RemoveEventHandler(view, d);
            }
        };
    });
#endif