iOS 앱 아키텍처iOS App Architecture

Xamarin.ios 응용 프로그램은 Mono 실행 환경에서 실행 되며 AOT (전체 시간) 컴파일을 사용 하 여 코드를 ARM 어셈블리 C# 언어로 컴파일합니다.Xamarin.iOS applications run within the Mono execution environment, and use full Ahead of Time (AOT) compilation to compile C# code to ARM assembly language. 이는 목표-C 런타임과side-by-side 방식으로 실행 됩니다.This runs side-by-side with the Objective-C Runtime. 두 런타임 환경은 모두 UNIX와 유사한 커널, 특히 Xnu에서 실행 되며 개발자가 기본 네이티브 또는 관리 되는 시스템에 액세스할 수 있도록 하는 다양 한 api를 사용자 코드에 노출 합니다.Both runtime environments run on top of a UNIX-like kernel, specifically XNU, and expose various APIs to the user code allowing developers to access the underlying native or managed system.

아래 다이어그램은이 아키텍처의 기본 개요를 보여 줍니다.The diagram below shows a basic overview of this architecture:

네이티브 및 관리 코드: 설명Native and Managed code: An Explanation

Xamarin 용으로 개발 하는 경우 네이티브 코드와 관리 코드를 사용 하는 경우가 많습니다.When developing for Xamarin the terms native and managed code are often used. 관리 코드.NET Framework 공용 언어 런타임에서실행 되는 코드 또는 Xamarin의 경우 Mono 런타임입니다.Managed code is code that has its execution managed by the .NET Framework Common Language Runtime, or in Xamarin’s case: the Mono Runtime. 중간 언어 라고 하는 것입니다.This is what we call an intermediate language.

네이티브 코드는 특정 플랫폼에서 기본적으로 실행 되는 코드입니다 (예: AOT 또는 ARM 칩에서 컴파일된 코드).Native code is code that will run natively on the specific platform (for example, Objective-C or even AOT compiled code, on an ARM chip). 이 가이드에서는 AOT이 관리 코드를 네이티브 코드로 컴파일하는 방법에 대해 설명 하 고, Xamarin.ios 응용 프로그램이 작동 하는 방식에 대해 설명 하 고 바인딩을 사용 하 여 Apple iOS Api를 완전히 활용 하는 동시에에도 액세스할 수 있도록 합니다. 순의 BCL 및와 C#같은 고급 언어입니다.This guide explores how AOT compiles your managed code to native code, and explains how a Xamarin.iOS application works, making full use of Apple’s iOS APIs through the use of bindings, while also having access to .NET’s BCL and a sophisticated language such as C#.

AOTAOT

Xamarin 플랫폼 C# 응용 프로그램을 컴파일할 때 Mono (또는 F#) 컴파일러는를 실행 하 고 C# 및 F# 코드를 MSIL (Microsoft 중간 언어)로 컴파일합니다.When you compile any Xamarin platform application, the Mono C# (or F#) compiler will run and will compile your C# and F# code into Microsoft Intermediate Language (MSIL). Xamarin Android, Xamarin.ios 응용 프로그램 또는 시뮬레이터에서 Xamarin.ios 응용 프로그램을 실행 하는 경우 .NET CLR (공용 언어 런타임) 은 JIT (just-in-time) 컴파일러를 사용 하 여 MSIL을 컴파일합니다.If you are running a Xamarin.Android, a Xamarin.Mac application, or even a Xamarin.iOS application on the simulator, the .NET Common Language Runtime (CLR) compiles the MSIL using a Just in Time (JIT) compiler. 런타임에는 응용 프로그램에 대 한 올바른 아키텍처에서 실행 될 수 있는 네이티브 코드로 컴파일됩니다.At runtime this is compiled into a native code, which can run on the correct architecture for your application.

그러나 Apple에 의해 설정 된 iOS에는 장치에서 동적으로 생성 된 코드를 실행할 수 없도록 하는 보안 제한 사항이 있습니다.However, there is a security restriction on iOS, set by Apple, which disallows the execution of dynamically generated code on a device. 이러한 안전 프로토콜을 준수 하도록 하기 위해 Xamarin.ios는 대신 AOT (사전) 컴파일러를 사용 하 여 관리 코드를 컴파일합니다.To ensure that we adhere to these safety protocols, Xamarin.iOS instead uses an Ahead of Time (AOT) compiler to compile the managed code. 이렇게 하면 Apple의 ARM 기반 프로세서에 배포할 수 있는 기본 iOS 이진 파일이 생성 되 고, 선택적으로 LLVM을 사용 하 여 장치에 최적화 됩니다.This produces a native iOS binary, optionally optimized with LLVM for devices, that can be deployed on Apple’s ARM-based processor. 이에 대 한 대략적인 다이어그램은 아래에 나와 있습니다.A rough diagram of how this fits together is illustrated below:

AOT를 사용 하는 경우 제한 사항 가이드에 자세히 설명 된 여러 가지 제한 사항이 있습니다.Using AOT has a number of limitations, which are detailed in the Limitations guide. 또한 시작 시간을 줄이고 다양 한 성능 최적화를 통해 JIT에 비해 많은 향상 된 기능을 제공 합니다.It also provides a number of improvements over JIT through a reduction in the startup time, and various performance optimizations

이제 소스 코드에서 네이티브 코드로 코드를 컴파일하는 방법에 대해 살펴보았습니다. 이제 Xamarin.ios를 사용 하 여 완전 한 네이티브 iOS 응용 프로그램을 작성 하는 방법을 살펴보겠습니다.Now that we have explored how the code is compiled from source to native code, let’s take a look under the hood to see how Xamarin.iOS allows us to write fully native iOS applications

선택기Selectors

Xamarin을 사용 하는 경우 두 개의 개별 에코 시스템 .NET 및 Apple이 있습니다 .이를 통해 최대한 간소화 된 것으로 표시 하 여 최종 목표가 원활한 사용자 환경을 보장 해야 합니다.With Xamarin, we have two separate ecosystems, .NET and Apple, that we need to bring together to seem as streamlined as possible, to ensure that the end goal is a smooth user experience. 위의 섹션에는 두 런타임이 통신 하는 방법에 대 한 내용이 나와 있으며, Xamarin에서 네이티브 iOS Api를 사용할 수 있도록 하는 용어 ' 바인딩 '을 매우 잘 들었습니다.We have seen in the section above how the two runtimes communicate, and you may very well have heard of the term ‘bindings’ which allows the native iOS APIs to be used in Xamarin. 바인딩은 목표-C 바인딩 설명서에 자세히 설명 되어 있으므로 이제 iOS가 내부적으로 작동 하는 방식을 살펴보겠습니다.Bindings are explained in depth in our Objective-C binding documentation, so for now let’s explore how iOS works under the hood.

첫째, 선택기를 통해 수행 되는 목표-C를에 C#노출 하는 방법이 있어야 합니다.First, there has to be a way to expose Objective-C to C#, which is done via Selectors. 선택기는 개체 또는 클래스로 전송 되는 메시지입니다.A selector is a message which is sent to an object or class. Objc_msgSend 함수를 통해이 작업을 수행할 수 있습니다.With Objective-C this is done via the objc_msgSend functions. 선택기 사용에 대 한 자세한 내용은 목표-C 선택기 가이드를 참조 하세요.For more information on using Selectors, refer to the Objective-C Selectors guide. 또한 관리 코드를 목표 c에 노출 하는 방법이 있어야 합니다 .이는 목표-C가 관리 코드에 대 한 정보를 알 수 없기 때문에 더 복잡 합니다.There also has to be a way to expose managed code to Objective-C, which is more complicated due to the fact that Objective-C doesn’t know anything about the managed code. 이 문제를 해결 하려면 등록 기관를 사용 합니다.To get around this, we use Registrars. 이러한 내용은 다음 섹션에서 자세히 설명 합니다.These are explained in more detail in the next section.

등록 기관Registrars

위에서 언급 했 듯이 등록자는 관리 코드를 목표 C에 노출 하는 코드입니다.As mentioned above, the registrar is code that exposes managed code to Objective-C. NSObject에서 파생 되는 모든 관리 되는 클래스 목록을 만들어이 작업을 수행 합니다.It does this by creating a list of every managed class that derives from NSObject:

  • 기존 목표-C 클래스를 래핑하는 모든 클래스의 경우,이 클래스는 [Export] 특성이 있는 모든 관리 되는 멤버를 사용 하 여 새 목표 c 클래스를 만듭니다.For all classes that are not wrapping an existing Objective-C class, it creates a new Objective-C class with Objective-C members mirroring all the managed members that have an [Export] attribute.

  • 각 목표 – C 멤버에 대 한 구현에서는 미러된 관리 되는 멤버를 호출 하기 위해 코드가 자동으로 추가 됩니다.In the implementations for each Objective–C member, code is added automatically to call the mirrored managed member.

아래 의사 코드는 이러한 작업을 수행 하는 방법의 예를 보여 줍니다.The pseudo-code below shows an example of how this is done:

C#(관리 코드)C# (Managed Code)

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

목표-C:Objective-C:

@interface MyViewController : UIViewController { }

    -(void)myFunc;
@end

@implementation MyViewController {}

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

관리 코드에는 개체를 목표 C에 노출 해야 한다는 것을 알 수 있도록 등록 자가 사용 하는 [Register][Export]특성이 포함 될 수 있습니다.The managed code can contain the attributes, [Register] and [Export], that the registrar uses to know that the object needs to be exposed to Objective-C. [Register] 특성은 생성 된 기본 이름이 적절 하지 않은 경우 생성 된 목표-C 클래스의 이름을 지정 하는 데 사용 됩니다.The [Register] attribute is used to specify the name of the generated Objective-C class in case the default generated name is not suitable. NSObject에서 파생 된 모든 클래스는 목표-C에 자동으로 등록 됩니다.All classes derived from NSObject are automatically registered with Objective-C. 필수 [Export] 특성에는 생성 된 목표-C 클래스에서 사용 되는 선택기 인 문자열이 포함 되어 있습니다.The required [Export] attribute contains a string, which is the selector used in the generated Objective-C class.

Xamarin.ios에서 사용 되는 등록 기관에는 동적 및 정적 이라는 두 가지 유형이 있습니다.There are two types of registrars used in Xamarin.iOS – dynamic and static:

  • 동적 등록 기관 – 동적 등록자는 런타임에 어셈블리의 모든 형식에 대해 등록을 수행 합니다.Dynamic registrars – The dynamic registrar does the registration of all types in your assembly at runtime. 이는 목표-C의 런타임 API에서 제공 하는 함수를 사용 하 여 수행 합니다.It does this by using functions provided by Objective-C’s runtime API. 따라서 동적 등록자는 시작 속도가 느리고 빌드 시간을 단축 합니다.The dynamic registrar therefore has a slower startup, but a faster build time. 이는 iOS 시뮬레이터에 대 한 기본값입니다.This is default for the iOS Simulator. Trampolines 라고 하는 네이티브 함수 (일반적으로 C)는 동적 등록 기관를 사용할 때 메서드 구현으로 사용 됩니다.Native functions (usually in C), called trampolines, are used as method implementations when using the dynamic registrars. 아키텍처는 서로 다릅니다.They vary between different architectures.

  • 정적 등록 기관 – 정적 등록자는 빌드 중에 목표 C 코드를 생성 합니다 .이 코드는 정적 라이브러리로 컴파일되고 실행 파일에 연결 됩니다.Static registrars – The static registrar generates Objective-C code during the build, which is then compiled into a static library and linked into the executable. 이렇게 하면 더 빨리 시작할 수 있지만 빌드 시간 동안 시간이 오래 걸립니다.This allows for a quicker startup, but takes longer during build time. 이는 기본적으로 장치 빌드에 사용 됩니다.This is used by default for device builds. 정적 등록자는 다음과 같이 프로젝트의 빌드 옵션에서 mtouch 특성으로 --registrar:static를 전달 하 여 iOS 시뮬레이터에서 사용할 수도 있습니다.The static registrar can also be used with the iOS simulator by passing --registrar:static as an mtouch attribute in your project’s build options, as shown below:

Xamarin.ios에서 사용 하는 iOS 유형 등록 시스템의 세부 정보에 대 한 자세한 내용은 등록자 유형 가이드를 참조 하세요.For more information on the specifics of the iOS Type Registration system used by Xamarin.iOS, refer to the Type Registrar guide.

응용 프로그램 시작Application Launch

모든 Xamarin.ios 실행 파일의 진입점은 mono를 초기화 하는 xamarin_main이라는 함수에서 제공 됩니다.The entry point of all Xamarin.iOS executables is provided by a function called xamarin_main, which initializes mono.

프로젝트 형식에 따라 다음이 수행 됩니다.Depending on the project type, the following is done:

  • 일반 iOS 및 tvOS 응용 프로그램의 경우 Xamarin 앱에서 제공 하는 관리 되는 Main 메서드를 호출 합니다.For regular iOS and tvOS applications, the managed Main method, provided by the Xamarin app is called. 그런 다음이 관리 되는 Main 메서드는 목표-C의 진입점인 UIApplication.Main를 호출 합니다.This managed Main method then calls UIApplication.Main, which is the entry point for Objective-C. UIApplication. Main은 목표-C의 UIApplicationMain 메서드에 대 한 바인딩입니다.UIApplication.Main is the binding for Objective-C's UIApplicationMain method.
  • 확장의 경우 Apple 라이브러리에서 제공 하는 네이티브 함수 – NSExtensionMain 또는 (WatchOS 확장에 대 한NSExtensionmain)가 호출 됩니다.For extensions, the native function – NSExtensionMain or (NSExtensionmain for WatchOS extensions) – provided by Apple libraries is called. 이러한 프로젝트는 실행 프로젝트가 아닌 클래스 라이브러리 이기 때문에 실행할 관리 되는 기본 메서드가 없습니다.Since these projects are class libraries and not executable projects, there are no managed Main methods to execute.

이 시작 시퀀스는 모두 정적 라이브러리로 컴파일되며 최종 실행 파일에 연결 됩니다. 그러면 앱에서 그라운드를 끄는 방법을 알 수 있습니다.All of this launch sequence is compiled into a static library, which is then linked into your final executable so your app knows how to get off the ground.

앱이 시작 되 고 Mono가 실행 되 고 있으며,이 시점에서 관리 코드를 실행 하 고 네이티브 코드를 호출 하 고 다시 호출 하는 방법을 알고 있습니다.At this point our app has started up, Mono is running, we are in managed code and we know how to call native code and be called back. 다음으로 수행 해야 하는 작업은 실제로 컨트롤 추가를 시작 하 고 앱을 대화형으로 만드는 것입니다.The next thing we need to do is to actually start adding controls and make the app interactive.

GeneratorGenerator

Xamarin.ios에는 모든 단일 iOS API에 대 한 정의가 포함 되어 있습니다.Xamarin.iOS contains definitions for every single iOS API. Macios github리포지토리에서 이러한 중 하나를 탐색할 수 있습니다.You can browse through any of these on the MaciOS github repo. 이러한 정의에는 특성이 포함 된 인터페이스 뿐만 아니라 필요한 메서드 및 속성도 포함 됩니다.These definitions contain interfaces with attributes, as well as any necessary methods and properties. 예를 들어 다음 코드는 UIKit 네임 스페이스에서 UIToolbar를 정의 하는 데 사용 됩니다.For example, the following code is used to define a UIToolbar in the UIKit namespace. 이 인터페이스는 여러 메서드 및 속성을 포함 하는 인터페이스입니다.Notice that it is an interface with a number of methods and properties:

[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 도구를 사용 하 여 임시 어셈블리로 컴파일합니다.The Generator, called btouch in Xamarin.iOS, takes these definition files and uses .NET tools to compile them into a temporary assembly. 그러나이 임시 어셈블리는 목표-C 코드를 호출할 수 없습니다.However, this temporary assembly is not useable to call Objective-C code. 그러면 생성기에서 임시 어셈블리를 읽고 런타임에 사용할 C# 수 있는 코드를 생성 합니다.The generator then reads the temporary assembly and generates C# code that can be used at runtime. 예를 들어, 사용자가 정의 .cs 파일에 임의 특성을 추가 하면 출력 코드에 표시 되지 않습니다.This is why, for example, if you add a random attribute to your definition .cs file, it won’t show up in the outputted code. 생성기는이에 대해 알지 않으므로 임시 어셈블리에서이를 검색 하 여 출력을 btouch 알 수 없습니다.The generator doesn’t know about it and therefore btouch doesn't know to look for it in the temporary assembly to output it.

Xamarin.ios를 만든 후에는 mtouch에서 모든 구성 요소를 함께 번들로 만듭니다.Once the Xamarin.iOS.dll has been created, mtouch will bundle all the components together.

개략적인 수준에서 다음 작업을 실행 하 여이 작업을 수행 합니다.At a high level, it achieves this by executing the following tasks:

  • 앱 번들 구조를 만듭니다.Create an app bundle structure.
  • 관리 되는 어셈블리를 복사 합니다.Copy in your managed assemblies.
  • 링크를 사용 하는 경우 관리 되는 링커를 실행 하 여 사용 되지 않은 부분을 복사 하 여 어셈블리를 최적화 합니다.If linking is enabled, run the managed linker to optimize your assemblies by ripping unused parts out.
  • AOT 컴파일AOT compilation.
  • 네이티브 실행 파일에 연결 된 일련의 정적 라이브러리 (각 어셈블리에 대해 하나씩)를 출력 하는 네이티브 실행 파일을 만듭니다. 기본 실행 파일은 시작 관리자 코드, 등록자 코드 (정적) 및 AOT의 모든 출력으로 구성 됩니다. 컴파일러나Create a native executable, which outputs a series of static libraries (one for each assembly) that are linked into the native executable, so that the native executable consists of the launcher code, the registrar code (if static), and all the outputs from the AOT compiler

링커에 대 한 자세한 내용 및 사용 방법에 대 한 자세한 내용은 링커 가이드를 참조 하세요.For more detailed information on the linker and how it is used, refer to the Linker guide.

요약Summary

이 가이드에서는 Xamarin.ios 앱을 AOT 하 고 Xamarin.ios와 목적과 관련 된 관계를 자세히 살펴보았습니다.This guide looked at AOT compilation of Xamarin.iOS apps, and explored Xamarin.iOS and its relationship to Objective-C in depth.