Xamarin.iOS에 대한 형식 registrar
이 문서에서는 Xamarin.iOS에서 사용하는 형식 등록 시스템에 대해 설명합니다.
관리되는 클래스 및 메서드 등록
시작하는 동안 Xamarin.iOS는 다음을 등록합니다.
- [Register] 특성을 클래스로 Objective-C 사용하는 클래스입니다.
- [Category] 특성을 범주로 사용하는 Objective-C 클래스입니다.
- [Protocol] 특성을 프로토콜로 사용하는 Objective-C 인터페이스입니다.
- [내보내기]가 있는 멤버를 사용하여 Objective-C 액세스할 수 있습니다.
예를 들어 Xamarin.iOS 애플리케이션에서 일반적인 관리 Main
되는 메서드를 고려합니다.
UIApplication.Main (args, null, "AppDelegate");
이 코드는 애플리케이션의 Objective-C 대리자 클래스로 호출 AppDelegate
된 형식을 사용하도록 런타임에 지시합니다. 런타임이 Objective-C C# AppDelegate
클래스의 인스턴스를 만들 수 있도록 하려면 해당 클래스를 등록해야 합니다.
Xamarin.iOS는 런타임(동적 등록) 또는 컴파일 시간(정적 등록)에서 자동으로 등록을 수행합니다.
동적 등록은 시작 시 리플렉션을 사용하여 등록할 모든 클래스와 메서드를 찾아 런타임에 Objective-C 전달합니다. 동적 등록은 시뮬레이터 빌드에 기본적으로 사용됩니다.
정적 등록은 컴파일 시 애플리케이션에서 사용하는 어셈블리를 검사합니다. 등록 Objective-C 할 클래스와 메서드를 결정하고 이진 파일에 포함된 맵을 생성합니다. 그런 다음 시작 시 런타임에 맵을 Objective-C 등록합니다. 정적 등록은 디바이스 빌드에 사용됩니다.
범주
Xamarin.iOS 8.10부터 C# 구문을 사용하여 범주를 만들 Objective-C 수 있습니다.
범주를 만들려면 특성을 사용하고 [Category]
확장할 형식을 지정합니다. 예를 들어 다음 코드는 다음을 확장합니다.NSString
[Category (typeof (NSString))]
각 범주의 메서드에는 특성이 [Export]
있으므로 런타임에 Objective-C 사용할 수 있습니다.
[Export ("today")]
public static string Today ()
{
return "Today";
}
모든 관리되는 확장 메서드는 정적이어야 하지만 확장 메서드에 표준 C# 구문을 사용하여 인스턴스 메서드를 만들 Objective-C 수 있습니다.
[Export ("toUpper")]
public static string ToUpper (this NSString self)
{
return self.ToString ().ToUpper ();
}
확장 메서드에 대한 첫 번째 인수는 메서드가 호출된 인스턴스입니다.
[Category (typeof (NSString))]
public static class MyStringCategory
{
[Export ("toUpper")]
static string ToUpper (this NSString self)
{
return self.ToString ().ToUpper ();
}
}
이 예제에서는 클래스에 네이티브 toUpper
인스턴스 메서드를 추가합니다 NSString
. 이 메서드는 다음에서 호출할 수 있습니다.Objective-C
[Category (typeof (UIViewController))]
public static class MyViewControllerCategory
{
[Export ("shouldAutoRotate")]
static bool GlobalRotate ()
{
return true;
}
}
프로토콜
Xamarin.iOS 8.10부터 특성이 있는 [Protocol]
인터페이스는 프로토콜로 내보 Objective-C 냅니다.
[Protocol ("MyProtocol")]
interface IMyProtocol
{
[Export ("method")]
void Method ();
}
class MyClass : IMyProtocol
{
void Method ()
{
}
}
이 코드는 IMyProtocol
프로토콜을 구현하는 Objective-C 호출 MyProtocol
된 프로토콜 및 호출 MyClass
된 클래스로 내보냅니다.
새 등록 시스템
안정적인 6.2.6 버전 및 베타 6.3.4 버전부터 새 정적 registrar을 추가했습니다. 7.2.1 버전에서는 새 registrar 버전을 기본값으로 설정했습니다.
이 새로운 등록 시스템은 다음과 같은 새로운 기능을 제공합니다.
프로그래머 오류의 컴파일 시간 검색:
- 동일한 이름으로 등록되는 두 클래스입니다.
- 동일한 선택기에서 응답하도록 둘 이상의 메서드를 내보냅니다.
사용되지 않는 네이티브 코드 제거:
- 새 등록 시스템은 정적 라이브러리에 사용되는 코드에 대한 강력한 참조를 추가하여 네이티브 링커가 결과 이진 파일에서 사용되지 않는 네이티브 코드를 제거할 수 있도록 합니다. Xamarin의 샘플 바인딩에서 대부분의 애플리케이션은 300k 이상 작아집니다.
의
NSObject
제네릭 서브클래스에 대한 지원은 NSObject 제네릭을 참조 하세요 . 또한 새 등록 시스템은 이전에 런타임에 임의 동작을 발생시킨 지원되지 않는 제네릭 구문을 catch합니다.
새 오류로 인한 오류 registrar
다음은 새 registrar오류에 의해 catch된 오류의 몇 가지 예입니다.
동일한 클래스에서 동일한 선택기를 두 번 이상 내보냅니다.
[Register] class MyDemo : NSObject { [Export ("foo:")] void Foo (NSString str); [Export ("foo:")] void Foo (string str) }
이름이 같은 Objective-C 관리되는 클래스를 둘 이상 내보냅니다.
[Register ("Class")] class MyClass : NSObject {} [Register ("Class")] class YourClass : NSObject {}
제네릭 메서드 내보내기:
[Register] class MyDemo : NSObject { [Export ("foo")] void Foo<T> () {} }
새 기능의 제한 사항 registrar
새 registrar항목에 대해 염두에 두어야 할 몇 가지 사항은 다음과 같습니다.
일부 타사 라이브러리는 새 등록 시스템에서 작동하도록 업데이트해야 합니다. 자세한 내용은 아래의 필수 수정 사항을 참조하세요.
단기적인 단점은 Accounts 프레임워크를 사용하는 경우 Clang를 사용해야 한다는 것입니다(Apple의 accounts.h 헤더는 Clang에서만 컴파일할 수 있기 때문입니다). Xcode 4.6 이하를 사용하는 경우 Clang를 사용하기 위해 추가 mtouch 인수에 추가
--compiler:clang
합니다(Xamarin.iOS는 Xcode 5.0 이상에서 Clang를 자동으로 선택합니다.)Xcode 4.6(또는 이전 버전)을 사용하는 경우 내보낸 형식 이름에 ASCII가 아닌 문자가 포함된 경우 GCC/G++를 선택해야 합니다(Xcode 4.6과 함께 제공되는 Clang 버전은 코드의 식별자 Objective-C 내에서 ASCII가 아닌 문자를 지원하지 않기 때문입니다). GCC를 사용하기 위해 추가 mtouch 인수에 추가
--compiler:gcc
합니다.
선택 registrar
프로젝트의 iOS 빌드 설정에서 추가 mtouch 인수에 다음 옵션 중 하나를 추가하여 다른 registrar 옵션을 선택할 수 있습니다.
--registrar:static
– 디바이스 빌드의 기본값--registrar:dynamic
– 시뮬레이터 빌드의 기본값
참고 항목
Xamarin의 클래식 API는 다음과 같은 --registrar:legacystatic
다른 옵션을 지원합니다 --registrar:legacydynamic
. 그러나 이러한 옵션은 통합 API에서 지원되지 않습니다.
이전 등록 시스템의 단점
이전 등록 시스템에는 다음과 같은 단점이 있습니다.
- 타사 네이티브 라이브러리에는 클래스 및 메서드에 Objective-C 대한 (네이티브) 정적 참조가 없었기 때문에 네이티브 링커에게 실제로 사용되지 않은 타사 네이티브 코드를 제거하도록 요청할 수 없습니다(모든 것이 제거되기 때문). 이는 모든 타사 바인딩이
-force_load libNative.a
수행해야 하는 이유입니다(또는 특성에[LinkWith]
해당ForceLoad=true
). - 경고 없이 이름이 같은 Objective-C 관리되는 두 형식을 내보낼 수 있습니다. 드문 시나리오는 서로 다른 네임스페이스의 두
AppDelegate
클래스로 끝나는 것이었습니다. 런타임에는 완전히 무작위로 선택되었습니다(사실, 다시 빌드되지 않은 앱의 실행 간에 다양하여 매우 수수께끼같고 실망스러운 디버깅 환경을 만들었습니다). - 동일한 Objective-C 서명으로 두 메서드를 내보낼 수 있습니다. 그러나 이 버그를 실제로 경험할 수 Objective-C 있는 유일한 방법은 불운한 관리되는 방법을 재정의하는 것이었기 때문에 이 문제는 무작위였습니다(그러나 이 문제는 이전 문제만큼 일반적이지 않았습니다).
- 내보낸 메서드 집합은 동적 빌드와 정적 빌드 간에 약간 달랐습니다.
- 제네릭 클래스를 내보낼 때 제대로 작동하지 않습니다(런타임에 실행되는 정확한 제네릭 구현은 임의로 실행되어 결정되지 않은 동작이 효과적으로 발생).
새로 만들기 registrar: 바인딩에 필요한 변경 내용
이 섹션에서는 새 registrar작업을 위해 수행해야 하는 바인딩 변경 내용에 대해 설명합니다.
프로토콜에는 [Protocol] 특성이 있어야 합니다.
이제 프로토콜에 특성이 [Protocol]
있어야 합니다. 이렇게 하지 않으면 다음과 같은 네이티브 링커 오류가 발생합니다.
Undefined symbols for architecture i386: "_OBJC_CLASS_$_ProtocolName", referenced from: ...
선택기에는 유효한 개수의 매개 변수가 있어야 합니다.
모든 선택기는 매개 변수 수를 올바르게 나타내야 합니다. 이전에는 이러한 오류가 무시되어 런타임 문제가 발생할 수 있었습니다.
즉, 콜론 수는 매개 변수 수와 일치해야 합니다.
- 매개 변수 없음:
foo
- 하나의 매개 변수:
foo:
- 두 매개 변수:
foo:parameterName2:
다음은 잘못된 용도입니다.
// Invalid: export takes no arguments, but function expects one
[Export ("apply")]
void Apply (NSObject target);
// Invalid: exported as taking an argument, but the managed version does not have one:
[Export ("display:")]
void Display ();
내보내기에서 IsVariadic 매개 변수 사용
Variadic 함수는 특성에 IsVariadic
인수를 [Export]
사용해야 합니다.
[Export ("variadicMethod:", IsVariadic = true)]
void VariadicMethod (NSObject first, IntPtr subsequent);
기존 기호에 연결해야 합니다.
네이티브 라이브러리에 없는 클래스를 바인딩하는 것은 불가능합니다. 네이티브 라이브러리에서 클래스가 제거되거나 이름이 변경된 경우 바인딩을 일치하도록 업데이트해야 합니다.