Xamarin.ios의 이벤트, 프로토콜 및 대리자Events, Protocols and Delegates in Xamarin.iOS

Xamarin.ios는 컨트롤을 사용 하 여 대부분의 사용자 상호 작용에 대 한 이벤트를 노출 합니다.Xamarin.iOS uses controls to expose events for most user interactions. Xamarin.ios 응용 프로그램은 기존 .NET 응용 프로그램을 사용 하는 것과 거의 동일한 방식으로 이러한 이벤트를 사용 합니다.Xamarin.iOS applications consume these events in much the same way as do traditional .NET applications. 예를 들어 Xamarin.ios UIButton 클래스에는 TouchUpInside 라는 이벤트가 있으며이 클래스와 이벤트가 .NET 앱에 있는 것 처럼이 이벤트를 사용 합니다.For example, the Xamarin.iOS UIButton class has an event called TouchUpInside and consumes this event just as if this class and event were in a .NET app.

이 .NET 접근 방식 외에 Xamarin.ios는 보다 복잡 한 상호 작용 및 데이터 바인딩에 사용할 수 있는 다른 모델을 노출 합니다.Besides this .NET approach, Xamarin.iOS exposes another model that can be used for more complex interaction and data binding. 이 방법론은 Apple에서 대리자와 프로토콜을 호출 하는 것을 사용 합니다.This methodology uses what Apple calls delegates and protocols. 대리자는의 C#대리자와 비슷하지만, 단일 메서드를 정의 하 고 호출 하는 대신, 목표 C의 대리자는 프로토콜을 따르는 전체 클래스입니다.Delegates are similar in concept to delegates in C#, but instead of defining and calling a single method, a delegate in Objective-C is an entire class that conforms to a protocol. 프로토콜은의 C#인터페이스와 유사 합니다. 단, 해당 메서드는 선택 사항 일 수 있습니다.A protocol is similar to an interface in C#, except that its methods can be optional. 예를 들어 UITableView를 데이터로 채우려면 UITableView에서 자신을 채우기 위해 호출 하는 UITableViewDataSource 프로토콜에 정의 된 메서드를 구현 하는 대리자 클래스를 만들 수 있습니다.So for example, to populate a UITableView with data, you would create a delegate class that implements the methods defined in the UITableViewDataSource protocol that the UITableView would call to populate itself.

이 문서에서는 다음을 포함 하 여 Xamarin.ios에서 콜백 시나리오를 처리 하기 위한 견고한 토대를 제공 하는 모든 항목에 대해 알아봅니다.In this article you’ll learn about all these topics, giving you a solid foundation for handling callback scenarios in Xamarin.iOS, including:

  • 이벤트 – uikit 컨트롤과 함께 .Net 이벤트 사용.Events – Using .NET events with UIKit controls.
  • 프로토콜 – 프로토콜 및 사용 방법에 대해 배우고 맵 주석에 대 한 데이터를 제공 하는 예제를 만듭니다.Protocols – Learning what protocols are and how they are used, and creating an example that provides data for a map annotation.
  • 대리자 – 지도 예제를 확장 하 여 주석을 포함 하는 사용자 상호 작용을 처리 하 고, 강력 하 고 약한 대리자와 이러한 각 대리자를 사용 하는 경우의 차이를 파악 하 여 목표-C 대리자에 대해 학습 합니다.Delegates – Learning about Objective-C delegates by extending the map example to handle user interaction that includes an annotation, then learning the difference between strong and weak delegates and when to use each of these.

프로토콜과 대리자를 설명 하기 위해 다음과 같이 맵에 주석을 추가 하는 간단한 map 응용 프로그램을 빌드합니다.To illustrate protocols and delegates, we’ll build a simple map application that adds an annotation to a map as shown here:

이 앱을 주요 당면 하기 전에 UIKit에서 .NET 이벤트를 살펴보면 시작 하겠습니다.Before tackling this app, let’s get started by looking at .NET events under the UIKit.

UIKit를 사용 하는 .NET 이벤트.NET Events with UIKit

Xamarin.ios는 UIKit 컨트롤에서 .NET 이벤트를 노출 합니다.Xamarin.iOS exposes .NET events on UIKit controls. 예를 들어 UIButton에는 C# 람다 식을 사용 하는 다음 코드와 같이 일반적으로 .net에서와 같이 처리 하는 TouchUpInside 이벤트가 있습니다.For example, UIButton has a TouchUpInside event, which you handle as you normally would in .NET, as shown in the following code that uses a C# lambda expression:

aButton.TouchUpInside += (o,s) => {
    Console.WriteLine("button touched");
};

다음과 같이 2.0 스타일의 C# 무명 메서드를 사용 하 여이를 구현할 수도 있습니다.You could also implement this with a C# 2.0-style anonymous method like this one:

aButton.TouchUpInside += delegate {
    Console.WriteLine ("button touched");
};

위의 코드는 UIViewController의 ViewDidLoad 메서드에 연결 되어 있습니다.The preceding code is wired up in the ViewDidLoad method of the UIViewController. aButton 변수는 iOS 디자이너 또는 코드를 사용 하 여 추가할 수 있는 단추를 참조 합니다.The aButton variable references a button, which you could add either in the iOS Designer or with code. 다음 그림은 iOS 디자이너에 추가 된 단추를 보여 줍니다.The following figure shows a button that has been added in the iOS Designer:

또한 xamarin.ios는 컨트롤과 함께 발생 하는 상호 작용에 코드를 연결 하는 대상 작업 스타일을 지원 합니다.Xamarin.iOS also supports the target-action style of connecting your code to an interaction that occurs with a control. Hello 단추의 대상 작업을 만들려면 iOS 디자이너에서 해당 작업을 두 번 클릭 합니다.To create a target-action for the Hello button, double click it in the iOS Designer. UIViewController의 코드 숨겨진 파일이 표시 되 고 개발자는 연결 방법을 삽입할 위치를 선택 하 라는 메시지가 표시 됩니다.The UIViewController's code-behind file will be displayed and the developer will be asked to select a location to insert the connecting method:

위치를 선택 하면 새 메서드가 생성 되 고 컨트롤에 연결 됩니다.After a location is selected, a new method is created and wired-up to the control. 다음 예제에서는 단추를 클릭 하면 콘솔에 메시지가 기록 됩니다.In the following example, a message will be written to the console when the button is clicked:

IOS 대상 작업 패턴에 대 한 자세한 내용은 Apple iOS 개발자 라이브러리의 ios에 대 한 핵심 응용 프로그램 역량의 대상-작업 섹션을 참조 하세요.For more details about the iOS target-action pattern, see the Target-Action section of Core Application Competencies for iOS in Apple’s iOS Developer Library.

Xamarin.ios에서 iOS Designer를 사용 하는 방법에 대 한 자세한 내용은 Ios 디자이너 개요 설명서를 참조 하세요.For more information about how to use the iOS Designer with Xamarin.iOS, see the iOS Designer Overview documentation.

이벤트Events

UIControl에서 이벤트를 가로채는 경우 C# 람다 및 대리자 함수를 사용 하 여 하위 수준 목표-C api를 사용 하는 등의 다양 한 옵션을 사용할 수 있습니다.If you want to intercept events from UIControl, you have a range of options: from using the C# lambdas and delegate functions to using the low-level Objective-C APIs.

다음 섹션에서는 필요한 컨트롤의 양에 따라 단추에서 System.windows.uielement.touchdown> 이벤트를 캡처하는 방법을 보여 줍니다.The following section shows how you would capture the TouchDown event on a button, depending on how much control you need.

C#StyleC# Style

대리자 구문 사용:Using the delegate syntax:

UIButton button = MakeTheButton ();
button.TouchDown += delegate {
    Console.WriteLine ("Touched");
};

대신 람다를 사용할 경우:If you like lambdas instead:

button.TouchDown += () => {
   Console.WriteLine ("Touched");
};

여러 단추가 동일한 처리기를 사용 하 여 동일한 코드를 공유 하도록 하려면 다음을 수행 합니다.If you want to have multiple buttons use the same handler to share the same code:

void handler (object sender, EventArgs args)
{
   if (sender == button1)
      Console.WriteLine ("button1");
   else
      Console.WriteLine ("some other button");
}

button1.TouchDown += handler;
button2.TouchDown += handler;

여러 종류의 이벤트 모니터링Monitoring more than one kind of Event

UIControlEvent C# 플래그에 대 한 이벤트는 개별 플래그에 일 대 일 매핑을 포함 합니다.The C# events for UIControlEvent flags have a one-to-one mapping to individual flags. 동일한 코드 조각을 사용 하 여 두 개 이상의 이벤트를 처리 하려는 경우 UIControl.AddTarget 메서드를 사용 합니다.When you want to have the same piece of code handle two or more events, use the UIControl.AddTarget method:

button.AddTarget (handler, UIControlEvent.TouchDown | UIControlEvent.TouchCancel);

람다 구문 사용:Using the lambda syntax:

button.AddTarget ((sender, event)=> Console.WriteLine ("An event happened"), UIControlEvent.TouchDown | UIControlEvent.TouchCancel);

특정 개체 인스턴스에 연결 하 고 특정 선택기를 호출 하는 것 처럼 목표-C의 하위 수준 기능을 사용 해야 하는 경우 다음을 수행 합니다.If you need to use low-level features of Objective-C, like hooking up to a particular object instance and invoking a particular selector:

[Export ("MySelector")]
void MyObjectiveCHandler ()
{
    Console.WriteLine ("Hello!");
}

// In some other place:

button.AddTarget (this, new Selector ("MySelector"), UIControlEvent.TouchDown);

상속 된 기본 클래스에서 인스턴스 메서드를 구현 하는 경우 공용 메서드 여야 합니다.Please note, if you implement the instance method in an inherited base class, it must be a public method.

프로토콜Protocols

프로토콜은 메서드 선언 목록을 제공 하는 객관적인 C 언어 기능입니다.A protocol is an Objective-C language feature that provides a list of method declarations. 의 C#인터페이스와 비슷한 용도를 제공 합니다. 주요 차이점은 프로토콜이 선택적 메서드를 가질 수 있다는 것입니다.It serves a similar purpose to an interface in C#, the main difference being that a protocol can have optional methods. 프로토콜을 채택 하는 클래스가 이러한 메서드를 구현 하지 않는 경우에는 선택적 메서드가 호출 되지 않습니다.Optional methods are not called if the class that adopts a protocol does not implement them. 또한, 목표 C의 단일 클래스는 C# 클래스가 여러 인터페이스를 구현할 수 있는 것 처럼 여러 프로토콜을 구현할 수 있습니다.Also, a single class in Objective-C can implement multiple protocols, just as a C# class can implement multiple interfaces.

Apple은 iOS 전체에서 프로토콜을 사용 하 여 클래스에 대 한 계약을 정의 하는 동시에 호출자의 구현 클래스를 추상화 하므로 C# 인터페이스 처럼 작동 합니다.Apple uses protocols throughout iOS to define contracts for classes to adopt, while abstracting away the implementing class from the caller, thus operating just like a C# interface. 프로토콜은 비 대리자 시나리오 (예: 다음에 표시 되는 MKAnnotation 예제)에서 사용 되며 대리자 (이 문서의 뒷부분에 나오는 대리자 섹션)에서 사용 됩니다.Protocols are used both in non-delegate scenarios (such as with the MKAnnotation example shown next), and with delegates (as presented later in this document, in the Delegates section).

Xamarin.ios를 사용 하는 프로토콜Protocols with Xamarin.ios

Xamarin.ios에서 목표-C 프로토콜을 사용 하는 예를 살펴보겠습니다.Let’s take a look at an example using an Objective-C protocol from Xamarin.iOS. 이 예제에서는 MapKit 프레임 워크의 일부인 MKAnnotation 프로토콜을 사용 합니다.For this example, we’ll use the MKAnnotation protocol, which is part of the MapKit framework. MKAnnotation는이를 채택 하는 모든 개체가 맵에 추가할 수 있는 주석에 대 한 정보를 제공 하는 데 사용할 수 있는 프로토콜입니다.MKAnnotation is a protocol that allows any object that adopts it to provide information about an annotation that can be added to a map. 예를 들어 MKAnnotation를 구현 하는 개체는 주석의 위치와 연결 된 제목을 제공 합니다.For example, an object implementing MKAnnotation provides the location of the annotation and the title associated with it.

이러한 방식으로 MKAnnotation 프로토콜을 사용 하 여 주석과 함께 제공 되는 관련 데이터를 제공 합니다.In this way, the MKAnnotation protocol is used to provide pertinent data that accompanies an annotation. 주석 자체의 실제 뷰는 MKAnnotation 프로토콜을 채택 하는 개체의 데이터로 빌드됩니다.The actual view for the annotation itself is built from the data in the object that adopts the MKAnnotation protocol. 예를 들어 아래 스크린샷에서와 같이 사용자가 주석에서 탭 할 때 표시 되는 설명선의 텍스트는 프로토콜을 구현 하는 클래스의 Title 속성에서 제공 됩니다.For example, the text for the callout that appears when the user taps on the annotation (as shown in the screenshot below) comes from the Title property in the class that implements the protocol:

다음 섹션에 설명 된 대로 프로토콜 심층이해, xamarin.ios는 프로토콜을 추상 클래스에 바인딩합니다.As described in the next section, Protocols Deep Dive, Xamarin.iOS binds protocols to abstract classes. MKAnnotation 프로토콜의 경우 바인딩된 C# 클래스는 프로토콜의 이름을 모방 하기 위해MKAnnotation이름이 지정 되며 CocoaTouch에 대 한 루트 기본 클래스인NSObject의 서브 클래스입니다.For the MKAnnotation protocol, the bound C# class is named MKAnnotation to mimic the name of the protocol, and it is a subclass of NSObject, the root base class for CocoaTouch. 이 프로토콜을 사용 하려면 좌표에 대해 getter 및 setter를 구현 해야 합니다. 그러나 제목과 부제목은 선택 사항입니다.The protocol requires a getter and setter to be implemented for the coordinate; however, a title and subtitle are optional. 따라서 MKAnnotation 클래스에서 Coordinate 속성은 abstract로 설정 되어야 하며,이 속성을 구현 하 고 TitleSubtitle 속성을 가상으로 표시 하 여 아래와 같이 옵션을 선택 합니다.Therefore, in the MKAnnotation class, the Coordinate property is abstract, requiring it to be implemented and the Title and Subtitle properties are marked virtual, making them optional, as shown below:

[Register ("MKAnnotation"), Model ]
public abstract class MKAnnotation : NSObject
{
    public abstract CLLocationCoordinate2D Coordinate
    {
        [Export ("coordinate")]
        get;
        [Export ("setCoordinate:")]
        set;
    }

    public virtual string Title
    {
        [Export ("title")]
        get
        {
            throw new ModelNotImplementedException ();
        }
    }

    public virtual string Subtitle
    {
        [Export ("subtitle")]
        get
        {
            throw new ModelNotImplementedException ();
        }
    }
...
}

Coordinate 속성이 하나 이상 구현 되어 있으면 모든 클래스는 MKAnnotation에서 파생 하 여 주석 데이터를 제공할 수 있습니다.Any class can provide annotation data by simply deriving from MKAnnotation, as long as at least the Coordinate property is implemented. 예를 들어 다음은 생성자의 좌표를 사용 하 고 제목에 대 한 문자열을 반환 하는 샘플 클래스입니다.For example, here’s a sample class that takes the coordinate in the constructor and returns a string for the title:

/// <summary>
/// Annotation class that subclasses MKAnnotation abstract class
/// MKAnnotation is bound by Xamarin.iOS to the MKAnnotation protocol
/// </summary>
public class SampleMapAnnotation : MKAnnotation
{
    string title;

    public SampleMapAnnotation (CLLocationCoordinate2D coordinate)
    {
        Coordinate = coordinate;
        title = "Sample";
    }

    public override CLLocationCoordinate2D Coordinate { get; set; }

    public override string Title {
        get {
            return title;
        }
    }
}

클래스가 바인딩되는 프로토콜을 통해, 서브 클래스 MKAnnotation는 주석의 뷰를 만들 때 맵에서 사용할 관련 데이터를 제공할 수 있습니다.Through the protocol it is bound to, any class that subclasses MKAnnotation can provide relevant data that will be used by the map when it creates the annotation’s view. 맵에 주석을 추가 하려면 다음 코드와 같이 MKMapView 인스턴스의 AddAnnotation 메서드를 호출 하면 됩니다.To add an annotation to a map, simply call the AddAnnotation method of an MKMapView instance, as shown in the following code:

//an arbitrary coordinate used for demonstration here
var sampleCoordinate =
    new CLLocationCoordinate2D (42.3467512, -71.0969456); // Boston

//create an annotation and add it to the map
map.AddAnnotation (new SampleMapAnnotation (sampleCoordinate));

여기서 map 변수는 맵 자체를 나타내는 클래스인 MKMapView 인스턴스입니다.The map variable here is an instance of an MKMapView, which is the class that represents the map itself. MKMapViewSampleMapAnnotation 인스턴스에서 파생 된 Coordinate 데이터를 사용 하 여 주석 보기를 맵에 배치 합니다.The MKMapView will use the Coordinate data derived from the SampleMapAnnotation instance to position the annotation view on the map.

MKAnnotation 프로토콜은 구현 세부 정보를 알아야 하는 소비자 (이 경우 map) 없이 구현 하는 모든 개체에 대해 알려진 기능 집합을 제공 합니다.The MKAnnotation protocol provides a known set of capabilities across any objects that implement it, without the consumer (the map in this case) needing to know about implementation details. 이렇게 하면 다양 한 주석을 맵에 쉽게 추가할 수 있습니다.This streamlines adding a variety of possible annotations to a map.

프로토콜 심층 살펴보기Protocols Deep Dive

인터페이스 C# 는 선택적 메서드를 지원 하지 않으므로 xamarin.ios는 프로토콜을 추상 클래스에 매핑합니다.Since C# interfaces don’t support optional methods, Xamarin.iOS maps protocols to abstract classes. 따라서 목표-C에서 프로토콜을 채택 하는 것은 프로토콜에 바인딩되고 필요한 메서드를 구현 하는 추상 클래스에서 파생 하 여 Xamarin.ios에서 수행 됩니다.Therefore, adopting a protocol in Objective-C is accomplished in Xamarin.iOS by deriving from the abstract class that is bound to the protocol and implementing the required methods. 이러한 메서드는 클래스에서 추상 메서드로 노출 됩니다.These methods will be exposed as abstract methods in the class. 프로토콜의 선택적 메서드는 C# 클래스의 가상 메서드에 바인딩됩니다.Optional methods from the protocol will be bound to virtual methods of the C# class.

예를 들어 다음은 Xamarin.ios에서 바인딩되는 UITableViewDataSource 프로토콜의 일부입니다.For example, here is a portion of the UITableViewDataSource protocol as bound in Xamarin.iOS:

public abstract class UITableViewDataSource : NSObject
{
    [Export ("tableView:cellForRowAtIndexPath:")]
    public abstract UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath);
    [Export ("numberOfSectionsInTableView:")]
    public virtual int NumberOfSections (UITableView tableView){...}
...
}

클래스는 추상 클래스입니다.Note that the class is abstract. Xamarin.ios를 사용 하면 클래스를 추상화 하 여 프로토콜에서 선택적/필수 메서드를 지원할 수 있습니다.Xamarin.iOS makes the class abstract to support optional/required methods in protocols. 그러나 목적과 C# 인터페이스와 달리 클래스는 C# 다중 상속을 지원 하지 않습니다.However, unlike Objective-C protocols, (or C# interfaces), C# classes don’t support multiple inheritance. 이는 프로토콜을 사용 C# 하는 코드 디자인에 영향을 주며 일반적으로 중첩 된 클래스를 사용 합니다.This affects the design of C# code that uses protocols, and typically leads to nested classes. 이 문제에 대 한 자세한 내용은이 문서의 뒷부분에 있는 대리자 섹션에서 설명 합니다.More about this issue is covered later in this document, in the Delegates section.

GetCell(…)UITableViewDataSource 프로토콜의 필수 메서드인 tableView:cellForRowAtIndexPath: 목표-C 선택기에 바인딩된 추상 메서드입니다.GetCell(…) is an abstract method, bound to the Objective-C selector, tableView:cellForRowAtIndexPath:, which is a required method of the UITableViewDataSource protocol. Selector는 메서드 이름에 대 한 목표-C 용어입니다.Selector is the Objective-C term for method name. 필요에 따라 메서드를 적용 하기 위해 Xamarin.ios는 추상으로 선언 합니다.To enforce the method as required, Xamarin.iOS declares it as abstract. 다른 메서드인 NumberOfSections(…)numberOfSectionsInTableview:에 바인딩됩니다.The other method, NumberOfSections(…), is bound to numberOfSectionsInTableview:. 이 메서드는 프로토콜에서 선택 사항 이므로 Xamarin.ios는 가상으로 선언 하므로에서 C#재정의할 수 있습니다.This method is optional in the protocol, so Xamarin.iOS declares it as virtual, making it optional to override in C#.

Xamarin.ios는 모든 iOS 바인딩을 처리 합니다.Xamarin.iOS takes care of all iOS binding for you. 그러나 목표-C에서 수동으로 프로토콜을 바인딩해야 하는 경우에는 클래스를 ExportAttribute로 데코레이팅하 여 수행할 수 있습니다.However, if you ever need to bind a protocol from Objective-C manually, you can do so by decorating a class with the ExportAttribute. 이는 Xamarin.ios 자체에서 사용 되는 방법과 동일 합니다.This is the same method used by Xamarin.iOS itself.

Xamarin.ios에서 목표-C 형식을 바인딩하는 방법에 대 한 자세한 내용은 바인딩 목표-c 형식문서를 참조 하세요.For more information about how to bind Objective-C types in Xamarin.iOS, see the article Binding Objective-C Types.

그러나 아직 프로토콜을 사용 하는 것은 아닙니다.We’re not through with protocols yet, though. 또한이는 다음 섹션의 항목인 목표-C 대리자의 기반으로 iOS에서 사용 됩니다.They’re also used in iOS as the basis for Objective-C delegates, which is the topic of the next section.

대리자Delegates

iOS는 목표-C 대리자를 사용 하 여 한 개체가 다른 개체와 작업을 전달 하는 위임 패턴을 구현 합니다.iOS uses Objective-C delegates to implement the delegation pattern, in which one object passes work off to another. 작업을 수행 하는 개체는 첫 번째 개체의 대리자입니다.The object doing the work is the delegate of the first object. 개체는 특정 상황이 발생 한 후 메시지를 전송 하 여 해당 대리자에 게 작업을 수행 하도록 지시 합니다.An object tells its delegate to do work by sending it messages after certain things happen. 목표 C에서와 같이 메시지를 보내는 것은에서 C#메서드를 호출 하는 것과 기능적으로 동일 합니다.Sending a message like this in Objective-C is functionally equivalent to calling a method in C#. 대리자는 이러한 호출에 대 한 응답으로 메서드를 구현 하므로 응용 프로그램에 기능을 제공 합니다.A delegate implements methods in response to these calls, and so provides functionality to the application.

대리자를 사용 하면 서브 클래스를 만들 필요 없이 클래스의 동작을 확장할 수 있습니다.Delegates enable you to extend the behavior of classes without needing to create subclasses. IOS의 응용 프로그램은 중요 한 작업이 발생 한 후 한 클래스가 다른 클래스를 다시 호출 하는 경우 대리자를 사용 하는 경우가 많습니다.Applications in iOS often use delegates when one class calls back to another after an important action occurs. 예를 들어 사용자가 맵에 대 한 주석을 탭 할 때 MKMapView 클래스가 대리자를 다시 호출 하 여 대리자 클래스의 작성자에 게 응용 프로그램 내에서 응답할 수 있는 기회를 제공 합니다.For example, the MKMapView class calls back to its delegate when the user taps an annotation on a map, giving the author of the delegate class the opportunity to respond within the application. 이 문서의 뒷부분에 나오는 이러한 형식의 대리자 사용에 대 한 예제를 통해 작업할 수 있습니다. 예를 들어 Xamarin.ios에서 대리자를 사용 합니다.You can work through an example of this type of delegate usage later in this article, in Example Using a Delegate with Xamarin.iOS.

이 시점에서 클래스가 대리자에 대해 호출할 메서드를 결정 하는 방법을 궁금할 수 있습니다.At this point, you may be wondering how a class determines what methods to call on its delegate. 프로토콜을 사용 하는 다른 위치입니다.This is another place where you use protocols. 일반적으로 대리자에 사용할 수 있는 메서드는 채택 하는 프로토콜에서 제공 됩니다.Usually, the methods available for a delegate come from the protocols they adopt.

대리자에 프로토콜을 사용 하는 방법How Protocols are used with Delegates

이전에는 프로토콜을 사용 하 여 맵에 주석을 추가 하는 방법을 살펴보았습니다.We saw earlier how protocols are used to support adding annotations to a map. 프로토콜은 사용자가 맵에 대 한 주석을 탭 하거나 테이블의 셀을 선택 하는 경우와 같이 특정 이벤트가 발생 한 후에 호출 하는 클래스에 대 한 알려진 메서드 집합을 제공 하는 데도 사용 됩니다.Protocols are also used to provide a known set of methods for classes to call after certain events occur, such as after the user taps an annotation on a map or selects a cell in a table. 이러한 메서드를 구현 하는 클래스를 호출 하는 클래스의 대리자 라고 합니다.The classes that implement these methods are known as the delegates of the classes that call them.

위임을 지 원하는 클래스는 대리자를 구현 하는 클래스에 할당 되는 대리자 속성을 노출 하 여이 작업을 수행 합니다.Classes that support delegation do so by exposing a Delegate property, to which a class implementing the delegate is assigned. 대리자에 대해 구현 하는 메서드는 특정 대리자가 적용 하는 프로토콜에 따라 달라 집니다.The methods you implement for the delegate will depend upon the protocol that the particular delegate adopts. UITableView 메서드의 경우 UITableViewDelegate 프로토콜을 구현 합니다. UIAccelerometer 메서드에 대해 UIAccelerometerDelegate를 구현 하 고,이를 통해 모든 iOS에서 대리자를 노출할 다른 모든 클래스에 대해를 구현할 수 있습니다.For the UITableView method, you implement the UITableViewDelegate protocol, for the UIAccelerometer method, you would implement UIAccelerometerDelegate, and so on for any other classes throughout iOS for which you would want to expose a delegate.

이전 예제에서 본 MKMapView 클래스에는 다양 한 이벤트가 발생 한 후에 호출 하는 Delegate 라는 속성이 있습니다.The MKMapView class we saw in our earlier example also has a property called Delegate, which it will call after various events occur. MKMapView에 대 한 대리자는 MKMapViewDelegate형식입니다.The Delegate for MKMapView is of type MKMapViewDelegate. 이를 사용 하 여 선택한 후 주석에 응답 하는 것이 좋습니다. 하지만 먼저 강력 하 고 약한 대리자 간의 차이점에 대해 살펴보겠습니다.You’ll use this shortly in an example to respond to the annotation after it is selected, but first let’s discuss the difference between strong and weak delegates.

강력한 대리자 및 약한 대리자Strong Delegates vs. Weak Delegates

지금까지 살펴본 대리자는 강력 하 게 형식화 된 대리자입니다.The delegates we’ve looked at so far are strong delegates, meaning they are strongly typed. Xamarin.ios 바인딩은 iOS의 모든 대리자 프로토콜에 대 한 강력한 형식의 클래스와 함께 제공 됩니다.The Xamarin.iOS bindings ship with a strongly typed class for every delegate protocol in iOS. 그러나 iOS에는 약한 대리자의 개념도 있습니다.However, iOS also has the concept of a weak delegate. 특정 대리자에 대 한 목표-C 프로토콜에 바인딩된 클래스를 서브클래싱 하는 대신, iOS를 사용 하 여 NSObject에서 파생 되는 모든 클래스에서 직접 프로토콜 메서드를 바인딩하고, 메서드를 ExportAttribute로 데코레이팅하는 것을 선택할 수도 있습니다. 적절 한 선택기를 제공 합니다.Instead of subclassing a class bound to the Objective-C protocol for a particular delegate, iOS also lets you choose to bind the protocol methods yourself in any class you like that derives from NSObject, decorating your methods with the ExportAttribute, and then supplying the appropriate selectors. 이 방법을 사용 하는 경우 대리자 속성이 아닌 WeakDelegate 속성에 클래스의 인스턴스를 할당 합니다.When you take this approach, you assign an instance of your class to the WeakDelegate property instead of to the Delegate property. 약한 대리자는 대리자 클래스를 다른 상속 계층 구조에서 사용할 수 있는 유연성을 제공 합니다.A weak delegate offers you the flexibility to take your delegate class down a different inheritance hierarchy. 강력 하 고 약한 대리자를 모두 사용 하는 Xamarin.ios 예를 살펴보겠습니다.Let’s look at a Xamarin.iOS example that uses both strong and weak delegates.

Xamarin.ios에서 대리자를 사용 하는 예제Example Using a Delegate with Xamarin.iOS

예제에서 주석을 탭 하 여 사용자에 대 한 응답으로 코드를 실행 하기 위해 MKMapViewDelegate를 서브클래싱하 고 MKMapViewDelegate 속성에 인스턴스를 할당할 수 있습니다.To execute code in response to the user tapping the annotation in our example, we can subclass MKMapViewDelegate and assign an instance to the MKMapView’s Delegate property. MKMapViewDelegate 프로토콜에는 선택적 메서드만 포함 됩니다.The MKMapViewDelegate protocol contains only optional methods. 따라서 모든 메서드는 Xamarin.ios MKMapViewDelegate 클래스에서이 프로토콜에 바인딩된 가상입니다.Therefore, all the methods are virtual that are bound to this protocol in the Xamarin.iOS MKMapViewDelegate class. 사용자가 주석을 선택 하면 MKMapView 인스턴스가 대리자에 게 mapView:didSelectAnnotationView: 메시지를 보냅니다.When the user selects an annotation, the MKMapView instance will send the mapView:didSelectAnnotationView: message to its delegate. Xamarin.ios에서이를 처리 하려면 다음과 같이 MKMapViewDelegate 하위 클래스의 DidSelectAnnotationView (MKMapView mapView, MKAnnotationView annotationView) 메서드를 재정의 해야 합니다.To handle this in Xamarin.iOS, we need to override the DidSelectAnnotationView (MKMapView mapView, MKAnnotationView annotationView) method in the MKMapViewDelegate subclass like this:

public class SampleMapDelegate : MKMapViewDelegate
{
    public override void DidSelectAnnotationView (
        MKMapView mapView, MKAnnotationView annotationView)
    {
        var sampleAnnotation =
            annotationView.Annotation as SampleMapAnnotation;

        if (sampleAnnotation != null) {

            //demo accessing the coordinate of the selected annotation to
            //zoom in on it
            mapView.Region = MKCoordinateRegion.FromDistance(
                sampleAnnotation.Coordinate, 500, 500);

            //demo accessing the title of the selected annotation
            Console.WriteLine ("{0} was tapped", sampleAnnotation.Title);
        }
    }
}

위에 표시 된 SampleMapDelegate 클래스는 MKMapView 인스턴스를 포함 하는 컨트롤러에서 중첩 된 클래스로 구현 됩니다.The SampleMapDelegate class shown above is implemented as a nested class in the controller that contains the MKMapView instance. 목표-C에서는 컨트롤러가 클래스 내에서 직접 여러 프로토콜을 채택 하는 것을 볼 수 있습니다.In Objective-C, you’ll often see the controller adopt multiple protocols directly within the class. 그러나 프로토콜은 Xamarin.ios의 클래스에 바인딩되므로 강력한 형식의 대리자를 구현 하는 클래스는 일반적으로 중첩 클래스로 포함 됩니다.However, since protocols are bound to classes in Xamarin.iOS, the classes that implement strongly typed delegates are usually included as nested classes.

대리자 클래스 구현을 구현 하면 컨트롤러에서 대리자의 인스턴스를 인스턴스화하고 다음과 같이 MKMapViewDelegate 속성에 할당 하기만 하면 됩니다.With the delegate class implementation in place, you only need to instantiate an instance of the delegate in the controller and assign it to the MKMapView’s Delegate property as shown here:

public partial class Protocols_Delegates_EventsViewController : UIViewController
{
    SampleMapDelegate _mapDelegate;
    ...
    public override void ViewDidLoad ()
    {
        base.ViewDidLoad ();

        //set the map's delegate
        _mapDelegate = new SampleMapDelegate ();
        map.Delegate = _mapDelegate;
        ...
    }
    class SampleMapDelegate : MKMapViewDelegate
    {
        ...
    }
}

Weak 대리자를 사용 하 여 동일한 작업을 수행 하려면 NSObject에서 파생 되는 클래스에서 직접 메서드를 바인딩하고 MKMapViewWeakDelegate 속성에 할당 해야 합니다.To use a weak delegate to accomplish the same thing, you need to bind the method yourself in any class that derives from NSObject and assign it to the WeakDelegate property of the MKMapView. UIViewController 클래스는 궁극적으로는 NSObject에서 파생 되므로 (CocoaTouch의 모든 목표-C 클래스와 같이) 컨트롤러에서 직접 mapView:didSelectAnnotationView:에 바인딩된 메서드를 구현 하 고 컨트롤러를 MKMapViewWeakDelegate에 할당 하 여 추가 중첩 클래스입니다.Since the UIViewController class ultimately derives from NSObject (like every Objective-C class in CocoaTouch), we can simply implement a method bound to mapView:didSelectAnnotationView: directly in the controller and assign the controller to MKMapView’s WeakDelegate, avoiding the need for the extra nested class. 아래 코드에서는이 방법을 보여 줍니다.The code below demonstrates this approach:

public partial class Protocols_Delegates_EventsViewController : UIViewController
{
    ...
    public override void ViewDidLoad ()
    {
        base.ViewDidLoad ();
        //assign the controller directly to the weak delegate
        map.WeakDelegate = this;
    }
    //bind to the Objective-C selector mapView:didSelectAnnotationView:
    [Export("mapView:didSelectAnnotationView:")]
    public void DidSelectAnnotationView (MKMapView mapView,
        MKAnnotationView annotationView)
    {
        ...
    }
}

이 코드를 실행 하는 경우 응용 프로그램은 강력한 형식의 대리자 버전을 실행할 때와 정확히 동일 하 게 동작 합니다.When running this code, the application behaves exactly as it did when running the strongly typed delegate version. 이 코드의 혜택은 약한 대리자가 강력한 형식의 대리자를 사용할 때 생성 된 추가 클래스를 만들 필요가 없다는 것입니다.The benefit from this code is that the weak delegate doesn’t require the creation of the extra class that was created when we used the strongly typed delegate. 그러나이는 형식 안전성을 위해 제공 됩니다.However, this comes at the expense of type safety. ExportAttribute전달 된 선택기에서 실수를 수행 하는 경우 런타임이 될 때까지 찾을 수 없습니다.If you were to make a mistake in the selector that was passed to the ExportAttribute, you wouldn’t find out until runtime.

이벤트 및 대리자Events and Delegates

대리자는 .NET에서 이벤트를 사용 하는 방식과 유사 하 게 iOS의 콜백에 사용 됩니다.Delegates are used for callbacks in iOS similarly to the way .NET uses events. IOS Api와 이러한 대리자를 사용 하는 방식이 .NET 처럼 보이는 것 처럼 보일 때 Xamarin.ios는 iOS에서 대리자를 사용 하는 여러 위치에 .NET 이벤트를 노출 합니다.To make iOS APIs and the way they use Objective-C delegates seem more like .NET, Xamarin.iOS exposes .NET events in many places where delegates are used in iOS.

예를 들어, 선택 된 주석에 응답 하는 MKMapViewDelegate에 대 한 이전 구현은 .NET 이벤트를 사용 하 여 Xamarin.ios에서 구현 될 수도 있습니다.For example, the earlier implementation where the MKMapViewDelegate responded to a selected annotation could also be implemented in Xamarin.iOS by using a .NET event. 이 경우 이벤트는 MKMapView 정의 되 고 DidSelectAnnotationView 이라고 합니다.In that case, the event would be defined in MKMapView and called DidSelectAnnotationView. MKMapViewAnnotationEventsArgs형식의 EventArgs 서브 클래스가 있습니다.It would have an EventArgs subclass of type MKMapViewAnnotationEventsArgs. MKMapViewAnnotationEventsArgsView 속성은 다음과 같이 앞에서 설명한 것과 동일한 구현으로 진행할 수 있는 주석 보기에 대 한 참조를 제공 합니다.The View property of MKMapViewAnnotationEventsArgs would give you a reference to the annotation view, from which you could proceed with the same implementation you had earlier, as illustrated here:

map.DidSelectAnnotationView += (s,e) => {
    var sampleAnnotation = e.View.Annotation as SampleMapAnnotation;
    if (sampleAnnotation != null) {
        //demo accessing the coordinate of the selected annotation to
        //zoom in on it
        mapView.Region = MKCoordinateRegion.FromDistance (
            sampleAnnotation.Coordinate, 500, 500);

        //demo accessing the title of the selected annotation
        Console.WriteLine ("{0} was tapped", sampleAnnotation.Title);
    }
};

요약Summary

이 문서에서는 Xamarin.ios에서 이벤트, 프로토콜 및 대리자를 사용 하는 방법을 설명 했습니다.This article covered how to use events, protocols, and delegates in Xamarin.iOS. Xamarin.ios가 컨트롤에 대 한 일반적인 .NET 스타일 이벤트를 노출 하는 방법을 살펴보았습니다.We saw how Xamarin.iOS exposes normal .NET style events for controls. 다음에는 C# 인터페이스와 다른 방법 및 xamarin.ios를 사용 하는 방법을 포함 하 여 목표 C 프로토콜에 대해 알아보았습니다.Next we learned about Objective-C protocols, including how they are different from C# interfaces and how Xamarin.iOS uses them. 마지막으로, Xamarin.ios 관점에서 목표-C 대리자를 검사 했습니다.Finally, we examined Objective-C delegates from a Xamarin.iOS perspective. Xamarin.ios에서 강력 하 고 약한 형식의 대리자를 지 원하는 방법과 .NET 이벤트를 대리자 메서드에 바인딩하는 방법에 대해 살펴보았습니다.We saw how Xamarin.iOS supports both strongly and weakly typed delegates, and how to bind .NET events to delegate methods.