Xamarin.ios에서 UI 스레드 사용Working with the UI Thread in Xamarin.iOS

응용 프로그램 사용자 인터페이스는 다중 스레드 장치 에서도 항상 단일 스레드입니다. 즉, 화면에 대 한 표현이 하나 뿐 이며 표시 되는 항목에 대 한 변경 내용은 단일 ' 액세스 지점 '을 통해 조정 해야 합니다.Application user interfaces are always single-threaded, even in multi-threaded devices – there’s only one representation of the screen and any changes to what is displayed need to be coordinated through a single ‘access point’. 이렇게 하면 여러 스레드가 동시에 동일한 픽셀을 업데이트 하려고 시도 하지 않습니다 (예:).This prevents multiple threads from trying to update the same pixel at the same time (for example).

코드는 주 (또는 UI) 스레드의 사용자 인터페이스 컨트롤만 변경 해야 합니다.Your code should only make changes to user interface controls from the main (or UI) thread. 다른 스레드에서 발생 한 모든 UI 업데이트 (예: 콜백 또는 백그라운드 스레드)가 화면에 렌더링 되지 않거나 충돌을 일으킬 수 있습니다.Any UI updates that occur on a different thread (such as a callback or background thread) may not get rendered to the screen, or could even cause a crash.

UI 스레드 실행UI Thread Execution

뷰에서 컨트롤을 만들거나 터치와 같이 사용자가 시작한 이벤트를 처리 하는 경우 코드는 UI 스레드의 컨텍스트에서 이미 실행 되 고 있습니다.When you are creating controls in a view, or handling a user-initiated event such as a touch, the code is already executing in the context of the UI thread.

코드가 백그라운드 스레드에서 실행 중인 경우 작업이 나 콜백에서 주 UI 스레드에서 실행 되 고 있지 않을 수 있습니다.If code is executing on a background thread, in a task or a callback then it is likely NOT executing on the main UI thread. 이 경우 InvokeOnMainThread에 대 한 호출에서 코드를 래핑하고 다음과 같이 BeginInvokeOnMainThread 합니다.In this case you should wrap the code in a call to InvokeOnMainThread or BeginInvokeOnMainThread like this:

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

InvokeOnMainThread 메서드는 NSObject에서 정의 되므로 모든 UIKit 개체 (예: 뷰 또는 뷰 컨트롤러)에 정의 된 메서드 내에서 호출할 수 있습니다.The InvokeOnMainThread method is defined on NSObject so it can be called from within methods defined on any UIKit object (such as a View or View Controller).

Xamarin.ios 응용 프로그램을 디버깅 하는 동안 코드에서 잘못 된 스레드의 UI 컨트롤에 액세스 하려고 하면 오류가 throw 됩니다.While debugging Xamarin.iOS applications, an error will be thrown if your code attempts to access a UI control from the wrong thread. 이렇게 하면 InvokeOnMainThread 메서드를 사용 하 여 이러한 문제를 추적 하 고 해결할 수 있습니다.This helps you to track down and fix these problems with the InvokeOnMainThread method. 이 오류는 디버깅 하는 동안에만 발생 하며 릴리스 빌드에서 오류를 throw 하지 않습니다.This only occurs while debugging and does not throw an error in release builds. 오류 메시지는 다음과 같이 표시 됩니다.The error message will appear like this:

백그라운드 스레드 예제Background Thread Example

다음은 간단한 스레드를 사용 하 여 백그라운드 스레드에서 사용자 인터페이스 컨트롤 (UILabel)에 액세스 하려고 시도 하는 예제입니다.Here is an example that attempts to access a user interface control (a UILabel) from a background thread using a simple thread:

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

이 코드는 디버깅 하는 동안 UIKitThreadAccessException을 throw 합니다.That code will throw the UIKitThreadAccessException while debugging. 문제를 해결 하 고 (사용자 인터페이스 컨트롤이 주 UI 스레드에서만 액세스할 수 있는지 확인 하려면) InvokeOnMainThread 식 내에서 UI 컨트롤을 참조 하는 코드를 다음과 같이 래핑합니다.To fix the problem (and ensure that the user interface control is only accessed from the main UI thread), wrap any code that references UI controls inside an InvokeOnMainThread expression like this:

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

이 문서의 나머지 예제에서는이를 사용할 필요가 없지만, 앱에서 네트워크 요청을 할 때, 알림 센터 또는 다른 방법으로 실행 되는 완료 처리기를 필요로 하는 다른 방법을 사용 하는 경우 기억해 야 할 중요 한 개념입니다. 스레드.You won’t need to use this for the remainder of the examples in this document, but it is an important concept to remember when your app makes network requests, uses the notification center or other methods that require a completion-handler that will run on another thread.

Async/Wait 예Async/Await Example

대기 작업이 완료 C# 될 때 호출 스레드에서 메서드가 계속 실행 되기 때문에 5 개의 async/wait 키워드를 사용 하는 경우InvokeOnMainThread필요 하지 않습니다.When using the C# 5 async/await keywords InvokeOnMainThread is not required because when an awaited task completes the method continues on the calling thread.

이 예제 코드 (데모용 으로만 사용 되는 지연 메서드 호출에 기다립니다)는 UI 스레드에서 호출 되는 비동기 메서드 (TouchUpInside 처리기)를 보여 줍니다.This example code (which awaits on a Delay method call, purely for demonstration purposes) shows an async method that is called on the UI thread (it is a TouchUpInside handler). 포함 하는 메서드는 UI 스레드에서 호출 되기 때문에 UILabel 텍스트를 설정 하거나 UIAlertView를 표시 하는 것과 같은 UI 작업을 백그라운드 스레드에서 완료 된 후에 안전 하 게 호출할 수 있습니다.Because the containing method is called on the UI thread, UI operations like setting the text on a UILabel or showing a UIAlertView can be safely called after asynchronous operations have completed on background threads.

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";
}

비동기 메서드가 주 UI 스레드가 아닌 백그라운드 스레드에서 호출 된 경우에는 InvokeOnMainThread 필요 합니다.If an async method is called from a background thread (not the main UI thread) then InvokeOnMainThread would still be required.