Xamarin.iOS에 대한 형식 registrar

이 문서에서는 Xamarin.iOS에서 사용하는 형식 등록 시스템에 대해 설명합니다.

관리되는 클래스 및 메서드 등록

시작하는 동안 Xamarin.iOS는 다음을 등록합니다.

예를 들어 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);

네이티브 라이브러리에 없는 클래스를 바인딩하는 것은 불가능합니다. 네이티브 라이브러리에서 클래스가 제거되거나 이름이 변경된 경우 바인딩을 일치하도록 업데이트해야 합니다.