UIAlertView: wait_fences: failed to receive reply:

2019-03-01 11:10发布

问题:

I'm running a web request in the background and I want the user to be able to cancel this request. I use a UIActionSheet with a Cancel button while the web request is running. When the web request returns an error, I close the UIActionSheet by calling DismissWithClickedButtonIndex(0, true). Then I show a UIAlertView with an error message and the option to cancel or retry the web request.

Everything works fine most of the time, but sometimes I get the "wait_fences: failed to receive reply: 10004003" message in the console output window and incidentally there is some strange UI-behaviour.

I did some searching and found out that this is caused by something like the underlaying view cannot get control before the control is transferred to the UIAlertView. Some people suggested to delay showing the AlertView by using PerformSelector. Is this the right solution? If so, how do I transfer the Show method of the UIAlertView to the first parameter of the PerformSelector method?

Currently I use this solution for the delay:

private void StartAfterParentViewUpdate(NSAction action)
{
    NSAction delayedAction = () => BeginInvokeOnMainThread(action);
    NSTimer.CreateScheduledTimer(new TimeSpan(0, 0, 0, 0, 200), delayedAction);
}

This way I can call StartAfterParentViewUpdate(_alertView.Show) and I guess it will run on the main UI thread as soon as the thread can handle it. Is this correct or is there a better way to solve this problem?

回答1:

To answer my own question: the solution works good, I never saw the wait_fences message again. I made a static helper to use from any class:

public static class UIHelper
{
    public static void StartAfterParentViewUpdate(NSObject parent, NSAction action)
    {
        NSTimer.CreateScheduledTimer(new TimeSpan(0, 0, 0, 0, 100), () => parent.BeginInvokeOnMainThread(action));
    }

    // Use this helper method only when action is a non-static member of an object.
    public static void StartAfterParentViewUpdate(NSAction action)
    {
        StartAfterParentViewUpdate((NSObject)action.Target, action);
    }
}

If you need to delay the call to a method with parameters, use an anonymous delegate. Example:

    NSAction action = () => { viewController.NavigationController.PopViewControllerAnimated(true); };
    UIHelper.StartAfterParentViewUpdate(viewController, action);