Xamarin.iOS'ta Kullanıcı Arabirimi İş Parçacığıyla Çalışma

Uygulama kullanıcı arabirimleri, çok iş parçacıklı cihazlarda bile her zaman tek iş parçacıklıdır; ekranın yalnızca bir gösterimi vardır ve görüntülenen öğelerde yapılan tüm değişikliklerin tek bir 'erişim noktası' üzerinden koordine edilmesi gerekir. Bu, birden çok iş parçacığının aynı pikseli aynı anda (örneğin) güncelleştirmeye çalışmasını önler.

Kodunuz yalnızca ana (veya UI) iş parçacığından kullanıcı arabirimi denetimlerine değişiklik yapmalıdır. Farklı bir iş parçacığında (geri çağırma veya arka plan iş parçacığı gibi) gerçekleşen kullanıcı arabirimi güncelleştirmeleri ekrana işlenmeyebilir, hatta kilitlenmeye neden olabilir.

UI İş Parçacığı Yürütme

Görünümde denetimler oluştururken veya dokunma gibi kullanıcı tarafından başlatılan bir olayı işlerken, kod kullanıcı arabirimi iş parçacığı bağlamında zaten yürütülüyordur.

Kod bir arka plan iş parçacığında, bir görevde veya geri çağırmada yürütülüyorsa, büyük olasılıkla ana kullanıcı arabirimi iş parçacığında YÜRÜTÜLMEDİR. Bu durumda kodu şuna bir çağrıya InvokeOnMainThread sarmalamanız gerekir BeginInvokeOnMainThread :

InvokeOnMainThread ( () => {
    // manipulate UI controls
});

yöntemi InvokeOnMainThread üzerinde NSObject tanımlanır, böylece herhangi bir UIKit nesnesinde (Görünüm veya Görünüm Denetleyicisi gibi) tanımlanan yöntemlerin içinden çağrılabilir.

Xamarin.iOS uygulamalarında hata ayıklanırken kodunuz yanlış iş parçacığından kullanıcı arabirimi denetimine erişmeye çalışırsa hata oluşur. Bu, InvokeOnMainThread yöntemiyle bu sorunları izlemenize ve çözmenize yardımcı olur. Bu yalnızca hata ayıklama sırasında oluşur ve yayın derlemelerinde hata oluşturmaz. Hata iletisi şu şekilde görünür:

UI İş Parçacığı Yürütme

Arka Plan İş Parçacığı Örneği

Basit bir iş parçacığı kullanarak arka plan iş parçacığından bir kullanıcı arabirimi denetimine (a UILabel) erişmeye çalışan bir örnek aşağıda verilmiştir:

new System.Threading.Thread(new System.Threading.ThreadStart(() => {
    label1.Text = "updated in thread"; // should NOT reference UILabel on background thread!
})).Start();

Bu kod hata ayıklama sırasında öğesini UIKitThreadAccessException oluşturur. Sorunu çözmek için (ve kullanıcı arabirimi denetimine yalnızca ana ui iş parçacığından erişildiğinden emin olmak için), ui denetimlerine başvuran tüm kodları şöyle bir InvokeOnMainThread ifade içinde sarmalayın:

new System.Threading.Thread(new System.Threading.ThreadStart(() => {
    InvokeOnMainThread (() => {
        label1.Text = "updated in thread"; // this works!
    });
})).Start();

Bu belgedeki örneklerin geri kalanı için bunu kullanmanız gerekmez, ancak uygulamanızın ağ isteklerinde bulunduğunu, bildirim merkezini veya başka bir iş parçacığında çalışacak tamamlama işleyicisi gerektiren diğer yöntemleri kullandığını anımsamak önemli bir kavramdır.

Async/Await Örneği

C# 5 async/await anahtar sözcükleri InvokeOnMainThread kullanıldığında, beklenen bir görev tamamlandığında yöntemi çağıran iş parçacığında devam ettiğinden gerekli değildir.

Bu örnek kod (yalnızca tanıtım amacıyla bir Delay yöntemi çağrısında bekler) UI iş parçacığında çağrılan zaman uyumsuz bir yöntemi gösterir (bir TouchUpInside işleyicisi). İçeren yöntem ui iş parçacığında çağrıldığından, metni bir UILabel üzerinde ayarlama veya gösterme UIAlertView gibi ui işlemleri arka plan iş parçacıklarında zaman uyumsuz işlemler tamamlandıktan sonra güvenli bir şekilde çağrılabilir.

async partial void button2_TouchUpInside (UIButton sender)
{
    textfield1.ResignFirstResponder ();
    textfield2.ResignFirstResponder ();
    textview1.ResignFirstResponder ();
    label1.Text = "async method started";
    await Task.Delay(1000); // example purpose only
    label1.Text = "1 second passed";
    await Task.Delay(2000);
    label1.Text = "2 more seconds passed";
    await Task.Delay(1000);
    new UIAlertView("Async method complete", "This method", 
               null, "Cancel", null)
        .Show();
    label1.Text = "async method completed";
}

Zaman uyumsuz bir yöntem arka plan iş parçacığından (ana ui iş parçacığından değil) çağrılırsa InvokeOnMainThread yine de gerekli olacaktır.