iOS 앱 아키텍처

Xamarin.iOS 애플리케이션은 Mono 실행 환경 내에서 실행되며 전체 AOT(Ahead of Time) 컴파일을 사용하여 C# 코드를 ARM 어셈블리 언어로 컴파일합니다. 런타임Objective-C 나란히 실행됩니다. 두 런타임 환경은 모두 UNIX와 유사한 커널( 특히 XNU)에서 실행되며 개발자가 기본 네이티브 또는 관리되는 시스템에 액세스할 수 있도록 사용자 코드에 다양한 API를 노출합니다.

아래 다이어그램은 이 아키텍처의 기본 개요를 보여줍니다.

This diagram shows a basic overview of the Ahead of Time (AOT) compilation architecture

네이티브 및 관리 코드: 설명

Xamarin용으로 개발할 때 네이티브 및 관리 코드라는 용어가 자주 사용됩니다. 관리 코드는 .NET Framework 공용 언어 런타임 또는 Xamarin의 경우 Mono 런타임에서 실행되는 코드입니다. 이것이 우리가 중간 언어라고 부르는 것입니다.

네이티브 코드는 특정 플랫폼(예 Objective-C : ARM 칩의 AOT 컴파일 코드)에서 기본적으로 실행되는 코드입니다. 이 가이드에서는 AOT가 관리 코드를 네이티브 코드로 컴파일하는 방법을 살펴보고 Xamarin.iOS 애플리케이션이 작동하는 방식을 설명하며, 바인딩을 사용하여 Apple의 iOS API를 최대한 활용하면서 액세스할 수도 있습니다. NET의 BCL 및 C#과 같은 정교한 언어.

AOT

Xamarin 플랫폼 애플리케이션을 컴파일하면 Mono C# (또는 F#) 컴파일러가 실행되고 C# 및 F# 코드를 MSIL(Microsoft Intermediate Language)로 컴파일합니다. 시뮬레이터 에서 Xamarin.Android, Xamarin.Mac 애플리케이션 또는 Xamarin.iOS 애플리케이션을 실행하는 경우 .NET CLR(공용 언어 런타임) 은 JIT(Just in Time) 컴파일러를 사용하여 MSIL을 컴파일합니다. 런타임 시 애플리케이션에 대한 올바른 아키텍처에서 실행할 수 있는 네이티브 코드로 컴파일됩니다.

그러나 디바이스에서 동적으로 생성된 코드의 실행을 허용하지 않는 Apple에서 설정한 iOS에 대한 보안 제한이 있습니다. 이러한 안전 프로토콜을 준수하기 위해 Xamarin.iOS는 대신 AOT(Ahead of Time) 컴파일러를 사용하여 관리 코드를 컴파일합니다. 이는 Apple의 ARM 기반 프로세서에 배포할 수 있는 디바이스용 LLVM으로 선택적으로 최적화된 네이티브 iOS 이진 파일을 생성합니다. 이를 함께 맞추는 방법에 대한 대략적인 다이어그램은 다음과 같습니다.

A rough diagram of how this fits together

AOT 사용에는 제한 사항 가이드에 자세히 설명된 여러 가지 제한 사항이 있습니다 . 또한 시작 시간 단축 및 다양한 성능 최적화를 통해 JIT에 대한 다양한 개선 사항을 제공합니다.

이제 코드가 소스에서 네이티브 코드로 컴파일되는 방법을 살펴보았습니다. Xamarin.iOS에서 완전히 네이티브 iOS 애플리케이션을 작성할 수 있는 방법을 알아보겠습니다.

선택기

Xamarin을 사용하면 최종 목표가 원활한 사용자 환경이 되도록 가능한 한 간소화된 것처럼 보이도록 함께 모아야 하는 .NET과 Apple이라는 두 개의 별도 에코시스템이 있습니다. 위의 섹션에서는 두 런타임이 통신하는 방법을 확인했으며, 네이티브 iOS API를 Xamarin에서 사용할 수 있는 '바인딩'이라는 용어에 대해 잘 들어보셨을 것입니다. 바인딩은 바인딩 설명서에 Objective-C 자세히 설명되어 있으므로, 이제 iOS가 내부적으로 작동하는 방식을 살펴보겠습니다.

먼저 선택기를 통해 수행되는 C#에 노출 Objective-C 하는 방법이 있어야 합니다. 선택기는 개체 또는 클래스로 전송되는 메시지입니다. Objective-C 이 작업은 objc_msgSend 함수를 통해 수행됩니다. 선택기 사용에 대한 자세한 내용은 선택기 가이드를 Objective-C 참조하세요. 관리 코드에 대해 아무것도 모르기 때문에 관리 코드를 노출하는 Objective-CObjective-C 방법도 있어야 합니다. 이 해결을 위해 사용합니다 Registrars. 이 내용은 다음 섹션에서 자세히 설명합니다.

Registrars

위에서 registrar 멘션 관리 코드를 노출하는 코드Objective-C입니다. NSObject에서 파생되는 모든 관리되는 클래스 목록을 만들어 이 작업을 수행합니다.

  • 기존 Objective-C 클래스를 래핑하지 않는 모든 클래스의 경우 [Export] 특성이 있는 모든 관리되는 멤버를 미러 멤버를 사용하여 새 Objective-C 클래스 Objective-C 를 만듭니다.

  • 각 Objective–C 멤버에 대한 구현에서 코드가 자동으로 추가되어 미러 관리되는 멤버를 호출합니다.

아래 의사 코드는 이 작업을 수행하는 방법의 예를 보여 줍니다.

C#(관리 코드)

 class MyViewController : UIViewController{
     [Export ("myFunc")]
     public void MyFunc ()
     {
     }
 }

Objective-C:

@interface MyViewController : UIViewController { }

    -(void)myFunc;
@end

@implementation MyViewController {}

    -(void) myFunc
    {
        /* code to call the managed MyViewController.MyFunc method */
    }
@end

관리 코드는 특성을 포함할 수 있으며[Export], [Register] 개체를 registrar 노출Objective-C해야 한다는 것을 알기 위해 사용합니다. [Register] 기본 생성된 이름이 적합하지 않은 경우 생성된 Objective-C 클래스의 이름을 지정하는 데 특성이 사용됩니다. NSObject에서 파생된 모든 클래스는 자동으로 .에 Objective-C등록됩니다. 필수 [Export] 특성에는 생성된 클래스에서 사용되는 선택기인 문자열이 포함됩니다 Objective-C .

Xamarin.iOS에는 동적 및 정적의 두 가지 유형 registrars 이 사용됩니다.

  • 동적 registrars – 동적 registrar 은 런타임에 어셈블리의 모든 형식을 등록합니다. 이 작업은 '런타임 API에서 제공하는 Objective-C함수를 사용하여 수행합니다. 따라서 동적 registrar 은 시작 속도가 느리지만 빌드 시간이 빨라집니다. iOS 시뮬레이터의 기본값입니다. 트램폴린이라고 하는 네이티브 함수(일반적으로 C)는 동적 registrars함수를 사용할 때 메서드 구현으로 사용됩니다. 아키텍처는 서로 다릅니다.

  • 정적 registrars – 정적 registrar 은 빌드 중에 코드를 생성 Objective-C 한 다음, 정적 라이브러리로 컴파일되고 실행 파일에 연결됩니다. 이렇게 하면 더 빠르게 시작할 수 있지만 빌드 시간 동안 더 오래 걸립니다. 디바이스 빌드에 기본적으로 사용됩니다. 아래와 같이 프로젝트의 빌드 옵션에서 특성으로 mtouch 전달 --registrar:static 하여 iOS 시뮬레이터와 함께 정적 registrar 을 사용할 수도 있습니다.

    Setting Additional mtouch arguments

Xamarin.iOS에서 사용하는 iOS 형식 등록 시스템의 세부 정보에 대한 자세한 내용은 형식 Registrar 가이드를 참조하세요.

애플리케이션 시작

모든 Xamarin.iOS 실행 파일의 진입점은 mono를 초기화하는 함수에서 xamarin_main제공됩니다.

프로젝트 유형에 따라 다음이 수행됩니다.

  • 일반 iOS 및 tvOS 애플리케이션의 경우 Xamarin 앱에서 제공하는 관리되는 Main 메서드가 호출됩니다. 그러면 관리되는 Main 메서드가 호출됩니다. 이 메서드 UIApplication.Main는 에 대한 Objective-C진입점입니다. UIApplication.Main은 's 메서드에 대한 Objective-C바인딩입니다 UIApplicationMain .
  • 확장의 경우 Apple 라이브러리에서 제공하는 네이티브 함수 NSExtensionMain (NSExtensionmain 또는 WatchOS 확장의 경우)가 호출됩니다. 이러한 프로젝트는 클래스 라이브러리이고 실행 가능한 프로젝트가 아니므로 실행할 관리되는 Main 메서드가 없습니다.

이 모든 시작 시퀀스는 정적 라이브러리로 컴파일된 다음, 최종 실행 파일에 연결되므로 앱이 지상에서 벗어나는 방법을 알 수 있습니다.

이 시점에서 앱이 시작되고 Mono가 실행 중이며 관리 코드에 있으며 네이티브 코드를 호출하고 다시 호출하는 방법을 알고 있습니다. 다음으로 해야 할 일은 실제로 컨트롤 추가를 시작하고 앱을 대화형으로 만드는 것입니다.

생성기

Xamarin.iOS에는 모든 단일 iOS API에 대한 정의가 포함되어 있습니다. MaciOS github 리포지토리에서 이러한 리포지토리를 탐색할 수 있습니다. 이러한 정의에는 특성이 있는 인터페이스와 필요한 메서드 및 속성이 포함됩니다. 예를 들어 다음 코드는 UIKit 네임스페이스에서 UIToolbar를 정의하는 데 사용됩니다. 다음과 같은 여러 메서드와 속성이 있는 인터페이스입니다.

[BaseType (typeof (UIView))]
public interface UIToolbar : UIBarPositioning {
    [Export ("initWithFrame:")]
    IntPtr Constructor (CGRect frame);

    [Export ("barStyle")]
    UIBarStyle BarStyle { get; set; }

    [Export ("items", ArgumentSemantic.Copy)][NullAllowed]
    UIBarButtonItem [] Items { get; set; }

    [Export ("translucent", ArgumentSemantic.Assign)]
    bool Translucent { [Bind ("isTranslucent")] get; set; }

    // done manually so we can keep this "in sync" with 'Items' property
    //[Export ("setItems:animated:")][PostGet ("Items")]
    //void SetItems (UIBarButtonItem [] items, bool animated);

    [Since (5,0)]
    [Export ("setBackgroundImage:forToolbarPosition:barMetrics:")]
    [Appearance]
    void SetBackgroundImage ([NullAllowed] UIImage backgroundImage, UIToolbarPosition position, UIBarMetrics barMetrics);

    [Since (5,0)]
    [Export ("backgroundImageForToolbarPosition:barMetrics:")]
    [Appearance]
    UIImage GetBackgroundImage (UIToolbarPosition position, UIBarMetrics barMetrics);

    ...
}

Xamarin.iOS에서 호출 btouch 된 생성기는 이러한 정의 파일을 사용하고 .NET 도구를 사용하여 임시 어셈블리로 컴파일합니다. 그러나 이 임시 어셈블리는 코드를 호출 Objective-C 하는 데 사용할 수 없습니다. 그런 다음 생성기는 임시 어셈블리를 읽고 런타임에 사용할 수 있는 C# 코드를 생성합니다. 따라서 예를 들어 정의 .cs 파일에 임의 특성을 추가하면 출력된 코드에 표시되지 않습니다. 생성기는 이를 알지 못하므로 btouch 생성기를 출력하기 위해 임시 어셈블리에서 찾을지 모릅니다.

Xamarin.iOS.dll 만들어지면 mtouch는 모든 구성 요소를 함께 묶습니다.

높은 수준에서 다음 작업을 실행하여 이를 달성합니다.

  • 앱 번들 구조를 만듭니다.
  • 관리되는 어셈블리에 복사합니다.
  • 연결을 사용하도록 설정한 경우 관리형 링커를 실행하여 사용하지 않는 파트를 리핑하여 어셈블리를 최적화합니다.
  • AOT 컴파일.
  • 네이티브 실행 파일에 연결된 일련의 정적 라이브러리(각 어셈블리에 대해 하나씩)를 출력하는 네이티브 실행 파일을 만들어 네이티브 실행 파일이 시작 관리자 코드, registrar 코드(정적인 경우) 및 AOT 컴파일러의 모든 출력으로 구성되도록 합니다.

링커 및 링커 사용 방법에 대한 자세한 내용은 링커 가이드를 참조하세요.

요약

이 가이드에서는 Xamarin.iOS 앱의 AOT 컴파일을 살펴보고 Xamarin.iOS와 Xamarin.iOS의 관계를 Objective-C 자세히 살펴보았습니다.