iPhone equivalent of Application.DoEvents();

2019-05-22 08:35发布

问题:

iPHone: We use MonoTouch, but Obj-C answers are ok.

My singleton domain object takes a while to get all the data so it runs internally parts of the fetch in a thread.

I need to inform the UI that the domain is done. Currently I do this. Is there a better way? In WinForms I would call Application.DoEvents() instead of Thread Sleep.

PlanDomain domain = PlanDomain.Instance ();
while (domain.IsLoadingData)
{
    Thread.Sleep (100);  //this is the main UI thread
}

TableView.Hidden = false;
TableView.Source = new TableSource (this);
TableView.ReloadData ();

回答1:

Generally speaking you want to avoid DoEvents. The iPhone equivilant in objective-c looks something like this:

[[NSRunLoop currentRunLoop] runUntilDate:[NSDate date]];


回答2:

Just to follow-up on Lounges answer, here is a C# code example:

NSRunLoop.Current.RunUntil(DateTime.Now.AddMilliseconds(2000));

This will pause 2000 milliseconds, but ensure that the UI updates. I just used this in some test code.



回答3:

It would be better to have something derived from AlertView (a loading dialog), unless you want to perform background loading.

This then runs the task in a separate Thread which you Join and then close the dialog. There's an example here, but doesn't feature any threading however it's trivial to add:

public class LoadingView : UIAlertView
{
    private UIActivityIndicatorView _activityView;

    public void Show(string title)
    {
        Title = title;
        Show();

        // Spinner - add after Show() or we have no Bounds.
        _activityView = new UIActivityIndicatorView(UIActivityIndicatorViewStyle.WhiteLarge);
        _activityView.Frame = new RectangleF((Bounds.Width / 2) - 15, Bounds.Height - 50, 30, 30);
        _activityView.StartAnimating();
        AddSubview(_activityView);

        // I haven't tested this, it should display the dialog still.
        Thread thread = new Thread(DoWork);
        thread.Start();
        thread.Join();

        Hide();
    }

    private void DoWork()
    {
        PlanDomain domain = PlanDomain.Instance ();
        while (domain.IsLoadingData)
        {
            // Maybe replace domain.IsLoadingData with an Event for when it finishes.
            // And then use a Mutex (WaitHandle) to communicate back
        }
    }

    public void Hide()
    {
        DismissWithClickedButtonIndex(0, true);
    }
}


回答4:

I'd see if you can use performSelectorOnMainThread : move your Tableview code to its own method and call back to that when you are done with the loading data.

Delegates are also useful in this scenario - get your PlanDomain to callback to a delegate function when its done.

Simlarly, if you want something more detached, look at using NSNotification s. These are most useful when the code you write doesn't need to know or care what is going to happen when its finished - it just needs to announce to the world that its done its job. (Most useful where there is potentially more than one thing that may be interested in acting when its complete.

In any of these, you don't want sleeps - just let the runloop handle it.