5

We are trying to set the AutomationId for UIAlertController using extensions in Xamarin.iOS. But the app is getting crashed inconsistently at var valuePtr = objc_getAssociatedObject(alertAction.Handle, DescriptiveName.Handle); under GetAccessibilityIdentifier method. Also no idea why it is crashing.

Below is the code sample:

public static class UIAlertControllerExtension
    {
        public static void ApplyAccessibilityIdentifiers(this UIAlertController alertController)
        {
            foreach (var action in alertController.Actions)
            {
                var lable = action.ValueForKey((NSString)"__representer");
                var view = lable as UIView;
                view.AccessibilityIdentifier = action.GetAccessibilityIdentifier();
            }
        }
    }

    public static class UIAlertActionExtension
    {

        private static readonly NSString DescriptiveName = new NSString("AccesabilityIdentifier" + nameof(UIAlertActionExtension));

        #region "Extension properties"

        enum AssociationPolicy
        {
            Assign = 0,
            RetainNonAtomic = 1,
            CopyNonAtomic = 3,
            Retain = 01401,
            Copy = 01403,
        }

        [DllImport("/usr/lib/libobjc.dylib")]
        static extern void objc_setAssociatedObject(
            IntPtr pointer, IntPtr key,
            IntPtr value, AssociationPolicy policy);

        [DllImport("/usr/lib/libobjc.dylib")]
        static extern IntPtr objc_getAssociatedObject(
            IntPtr pointer, IntPtr key);


        #endregion

        public static void SetAccessibilityIdentifier(this UIAlertAction alertAction, NSString accessabilityIdentifier)
        {
            objc_setAssociatedObject (alertAction.Handle, DescriptiveName.Handle, accessabilityIdentifier.Handle, AssociationPolicy.Retain);
        }

        public static NSString GetAccessibilityIdentifier(this UIAlertAction alertAction)
        {
            try
            {
                var valuePtr = objc_getAssociatedObject(alertAction.Handle, DescriptiveName.Handle); // App is crashed at this line.
                if (valuePtr != IntPtr.Zero)
                {
                    var result = ObjCRuntime.Runtime.GetNSObject(valuePtr);
                    if (result != null)
                        return (NSString)result;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }

            //var value = ObjCRuntime.Runtime.GetNSObject(valuePtr) as NSString;
            return new NSString("");
        }

    }

Created alert controller and setting AutomationId using above extension method as below.

private void ShowAlert()
{
    var alertController = UIAlertController.Create("Title", "Message", UIAlertControllerStyle.Alert);

    var action = UIAlertAction.Create("Ok", UIAlertActionStyle.Default, delegate
                {

                    // Do Somthing

                });

   action.SetAccessibilityIdentifier((NSString) accessibilityIdentifier);

   alertController.AddAction(action);

   this.PresentViewController(alertController, true, () => { alertController.ApplyAccessibilityIdentifiers(); });
}

We are calling this method from button click from the view controller and it is working fine for few times. But the app is getting crashed when show the alert 3rd or 4th time.

Please help me to resolve this issue.

Thanks in advance.

Ramesh Annadurai
  • 356
  • 1
  • 10

1 Answers1

2

AssociationPolicy.Retain maybe makes this property release at unexpected time, so your app crashes. You can change it to AssociationPolicy.RetainNonAtomic. NonAtomic will make your app run smoothly and faster.

If you just want to store a string and use it sometime later. Why not try NSUserDefaults or static instance?

Ax1le
  • 6,563
  • 2
  • 14
  • 61
  • Thank you so much @Land Lu - MSFT. App is not crashing now and also we are getting the expected result. We are using same AssociationPolicy in swift "objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN". Don't know why it was crashed only in Xamarin.iOS. However it is working now. Thank you once again. Identifier will be different for each Action and each AlertController. So we are using extension methods to set the AccessibilityIdentifier to alert actions for default UIAlertController. I think it is better than NSUserDefaults or static instance. – Ramesh Annadurai May 28 '18 at 06:03