Xamarin.Mac 작동 방법How Xamarin.Mac works

대부분의 경우 개발자는 Xamarin.ios의 내부 "매직"에 대해 걱정 하지 않아도 되지만, 내부적으로 작동 하는 방식을 대략적으로 이해 하는 것은 기존 설명서를 사용 하 여 C# 렌즈 및 디버깅 하는 데 도움이 됩니다. 문제가 발생할 때 발생 합니다.Most of the time the developer will never have to worry about the internal "magic" of Xamarin.Mac, however, having a rough understanding of how things works under the hood will help in both interpreting existing documentation with a C# lens and debugging issues when they arise.

Xamarin.ios에서 응용 프로그램은 두 가지 환경을 연결 합니다. 네이티브 클래스의 인스턴스를 포함 하는 목표 C 기반NSString런타임 ( NSApplication, 등)이 있으며 관리 되는 클래스 C# (System.String, HttpClient등)의 인스턴스를 포함 하는 런타임이 있습니다.In Xamarin.Mac, an application bridges two worlds: There is the Objective-C based runtime containing instances of native classes (NSString, NSApplication, etc) and there is the C# runtime containing instances of managed classes (System.String, HttpClient, etc). 이러한 두 가지 환경 사이에서 xamarin.ios는 두 가지 방식으로 연결 되므로 앱에서 목표-c (예: NSApplication.Init)의 메서드 (선택기)를 호출 하 고, 목표-c는 앱의 C# 메서드 (예: 앱 대리자의 메서드)를 호출할 수 있습니다.In between these two worlds, Xamarin.Mac creates a two way bridge so an app can call methods (selectors) in Objective-C (such as NSApplication.Init) and Objective-C can call the app's C# methods back (like methods on an app delegate). 일반적으로 목표 C에 대 한 호출은 P/invoke 를 통해 투명 하 게 처리 되 고 일부 런타임 코드는 Xamarin에서 제공 합니다.In general, calls into Objective-C are handled transparently via P/Invokes and some runtime code Xamarin provides.

클래스 C# /메서드를 목표에 노출-CExposing C# classes / methods to Objective-C

그러나 목표 C가 앱의 C# 개체로 다시 호출 되 게 하려면 목표에서 이해할 수 있는 방식으로 노출 해야 합니다.However, for Objective-C to call back into an app's C# objects, they need to be exposed in a way that Objective-C can understand. 이 작업은 RegisterExport 특성을 통해 수행 됩니다.This is done via the Register and Export attributes. 다음 예제를 참조하세요.Take the following example:

[Register ("MyClass")]
public class MyClass : NSObject
{
   [Export ("init")]
   public MyClass ()
   {
   }

   [Export ("run")]
   public void Run ()
   {
   }
}

이 예제에서 목표-C 런타임은 이제 및 MyClass run라는 init 선택기를 사용 하 여 호출 된 클래스에 대해 알 수 있습니다.In this example, the Objective-C runtime will now know about a class called MyClass with selectors called init and run.

대부분의 경우, 앱이 수신 하는 base 대부분의 콜백은 클래스 (예 AppDelegate:,, DataSources) 또는 동작 에서 재정의 된 메서드를 Delegates통해 수신 되므로 개발자는 무시할 수 있는 구현 세부 정보입니다. Api에 전달 됩니다.In most cases, this is an implementation detail that the developer can ignore, as most callbacks an app receives will be either via overridden methods on base classes (such as AppDelegate, Delegates, DataSources) or on Actions passed into APIs. 이러한 모든 경우 Export 에는 C# 코드에 특성이 필요 하지 않습니다.In all of those cases, Export attributes are not necessary in the C# code.

실행 생성자Constructor runthrough

대부분의 경우 개발자는 응용 프로그램의 C# 클래스 생성 API를 목표-C 런타임에 노출 하 여 STORYBOARD 또는 XIB 파일에서 호출 되는 경우와 같은 위치에서 인스턴스화할 수 있도록 해야 합니다.In many cases, the developer will need to expose the app's C# classes construction API to the Objective-C runtime so it can be instantiated from places such as when called in Storyboard or XIB files. 다음은 Xamarin.ios 앱에서 사용 되는 가장 일반적인 5 개의 생성자입니다.Here are the five most common constructors used in Xamarin.Mac apps:

// Called when created from unmanaged code
public CustomView (IntPtr handle) : base (handle)
{
   Initialize ();
}

// Called when created directly from a XIB file
[Export ("initWithCoder:")]
public CustomView (NSCoder coder) : base (coder)
{
   Initialize ();
}

// Called from C# to instance NSView with a Frame (initWithFrame)
public CustomView (CGRect frame) : base (frame)
{
}

// Called from C# to instance NSView without setting the frame (init)
public CustomView () : base ()
{
}

// This is a special case constructor that you call on a derived class when the derived called has an [Export] constructor.
// For example, if you call init on NSString then you don’t want to call init on NSObject.
public CustomView () : base (NSObjectFlag.Empty)
{
}

일반적으로 개발자는 사용자 지정 IntPtr NSViews 만 같은 일부 NSCoder 형식을 만들 때 생성 되는 및 생성자를 그대로 두어야 합니다.In general, the developer should leave the IntPtr and NSCoder constructors that are generated when creating some types such as custom NSViews alone. Xamarin.ios가 목표-C 런타임 요청에 대 한 응답으로 이러한 생성자 중 하나를 호출 해야 하 고 제거 하면 앱이 네이티브 코드 내에서 충돌 하 고 문제를 정확 하 게 파악 하기가 어려울 수 있습니다.If Xamarin.Mac needs to call one of these constructors in response to an Objective-C runtime request and you’ve removed it, the app will crash inside native code and it may be difficult to figure out exactly the issue.

메모리 관리 및 주기Memory management and cycles

Xamarin.ios의 메모리 관리는 Xamarin.ios와 매우 비슷한 여러 가지 방식으로 진행 됩니다.Memory management in Xamarin.Mac is in many ways very similar to Xamarin.iOS. 이 문서의 범위를 벗어나는 복잡 한 토픽 이기도 합니다.It also is a complex topic, one beyond the scope of this document. 메모리 및 성능 모범 사례를 참조 하세요.Please read the Memory and Performance Best Practices.

컴파일 시간 미리Ahead of time compilation

일반적으로 .NET 응용 프로그램은 빌드될 때 기계어 코드로 컴파일되지 않으며, 대신 앱이 시작 될 때 기계어 코드로 컴파일된 JIT ( just-in-time )를 가져오는 IL 코드 라는 중간 계층으로 컴파일됩니다.Typically, .NET applications do not compile down to machine code when they are built, instead they compile to an intermediate layer called IL code that gets Just-In-Time (JIT) compiled to machine code when the app is launched.

이 기계어 코드를 JIT 컴파일하는 데 사용 하는 시간에는 필요한 기계어 코드를 생성 하는 데 시간이 걸리기 때문에 최대 20%까지 Xamarin.ios 앱의 시작 속도를 저하 시킬 수 있습니다.The time that it takes the mono runtime to JIT compile this machine code can slow the launch of a Xamarin.Mac app by up to 20%, as it takes time for the necessary machine code to be generated.

IOS에서 Apple에 의해 적용 되는 제한 사항으로 인해 Xamarin.ios에서는 IL 코드의 JIT 컴파일을 사용할 수 없습니다.Because of limitations imposed by Apple on iOS, JIT compilation of the IL code is not available to Xamarin.iOS. 결과적으로 모든 Xamarin.ios 앱은 빌드 주기 중에 기계어 코드로 컴파일된 AOT (전체 시간 )입니다.As a result, all Xamarin.iOS app are full Ahead-Of-Time (AOT) compiled to machine code during the build cycle.

Xamarin.ios를 처음 접하는 경우 Xamarin.ios와 마찬가지로 앱 빌드 주기 중에 IL 코드를 AOT 수 있습니다.New to Xamarin.Mac is the ability to AOT the IL code during the app build cycle, just like Xamarin.iOS can. Xamarin.ios는 필요한 대부분의 기계어 코드를 컴파일하는 하이브리드 AOT 접근 방식을 사용 하지만, 런타임이 필요한 trampolines를 컴파일할 수 있도록 하 고, 현재 작업 중인 다른 사용 사례를 계속 지원 합니다. Xamarin.ios).Xamarin.Mac uses a Hybrid AOT approach that compiles a majority of the needed machine code, but allows the runtime to compile needed trampolines and the flexibility to continue to support Reflection.Emit (and other use cases that currently work on Xamarin.Mac).

AOT에서 Xamarin.ios 앱을 지원할 수 있는 두 가지 주요 영역은 다음과 같습니다.There are two major areas where AOT can help a Xamarin.Mac app:

  • "기본" 크래시 로그 개선 -xamarin.ios 응용 프로그램이 네이티브 코드에서 충돌 하는 경우 (예:를 null 수락 하지 않는 메서드로 전송 하는 등) cocoa api에 대 한 잘못 된 호출을 수행할 때 일반적으로 발생 합니다. 분석 하기 어렵습니다.Better "native" crash logs - If a Xamarin.Mac application crashes in native code, which is common occurrence when making invalid calls into Cocoa APIs (such as sending a null into a method that doesn't accept it), native crash logs with JIT frames are difficult to analyze. JIT 프레임은 디버그 정보를 포함 하지 않으므로 16 진수 오프셋을 포함 하는 여러 줄이 있고 무슨 일이 발생 했는지 알 수 없습니다.Since the JIT frames do not have debug information, there will be multiple lines with hex offsets and no clue what was going on. AOT은 "실제" 이름의 프레임을 생성 하 고 추적을 훨씬 더 쉽게 읽을 수 있습니다.AOT generates "real" named frames and the traces are much easier to read. 즉, Xamarin.ios 앱은 lldb기기와같은 네이티브 도구를 사용 하 여 더 효율적으로 상호 작용 합니다.This also means Xamarin.Mac app will interact better with native tools such as lldb and Instruments.
  • 더 나은 시작 시간 성능 -큰 xamarin.ios 응용 프로그램의 경우 두 번째 시작 시간을 사용 하면 모든 코드를 JIT 컴파일하는 데 상당한 시간이 걸릴 수 있습니다.Better launch time performance - For large Xamarin.Mac applications, with a multiple second startup time, JIT compiling all of the code can take a significant amount of time. AOT는이 작업을 앞으로 진행 합니다.AOT does this work up front.

AOT 컴파일 사용Enabling AOT compilation

AOT는 솔루션 탐색기에서 프로젝트 이름을 두 번 클릭 하 고, mac 빌드 로 이동 하 고, --aot:[options] 추가 mmp 인수: 필드 (여기서 [options] 는 하나 이상)에 추가 하 여 xamarin.ios에서 사용 하도록 설정 됩니다. AOT 유형을 제어 하는 옵션은 아래 참조).AOT is enabled in Xamarin.Mac by double-clicking the Project Name in the Solution Explorer, navigating to Mac Build and adding --aot:[options] to the Additional mmp arguments: field (where [options] is one or more options to control the AOT type, see below). 예:For example:

추가 mmp 인수에 AOT 추가Adding AOT to additional mmp arguments

중요

AOT 컴파일을 사용 하도록 설정 하면 빌드 시간이 크게 증가 하 고, 경우에 따라 최대 몇 분이 걸릴 수 있지만 응용 프로그램 시작 시간을 평균 20%까지 향상 시킬 수 있습니다.Enabling AOT compilation dramatically increases build time, sometimes up to several minutes, but it can improve app launch times by an average of 20%. 따라서 AOT 컴파일은 Xamarin.ios 앱의 릴리스 빌드에서만 사용 하도록 설정 해야 합니다.As a result, AOT compilation should only be enabled on Release builds of a Xamarin.Mac app.

Aot 컴파일 옵션Aot compilation options

Xamarin.ios 앱에서 AOT 컴파일을 사용 하도록 설정할 때 조정할 수 있는 몇 가지 옵션이 있습니다.There are several different options that can be adjusted when enabling AOT compilation on a Xamarin.Mac app:

  • none-AOT 컴파일이 없습니다.none - No AOT compilation. 이것이 기본 설정입니다.This is the default setting.
  • all-AOT는 MonoBundle의 모든 어셈블리를 컴파일합니다.all - AOT compiles every assembly in the MonoBundle.
  • core-AOT는 Xamarin.Mac, Systemmscorlib 어셈블리를 컴파일합니다.core - AOT compiles the Xamarin.Mac, System and mscorlib assemblies.
  • sdk-AOT는 및 Xamarin.Mac BCL (기본 클래스 라이브러리) 어셈블리를 컴파일합니다.sdk - AOT compiles the Xamarin.Mac and Base Class Libraries (BCL) assemblies.
  • |hybrid-위의 옵션 중 하나에이를 추가 하면 IL 제거를 허용 하지만 컴파일 시간이 길어질 수 있는 하이브리드 AOT 활성화 됩니다.|hybrid - Adding this to one of the above options enables hybrid AOT which allows for IL stripping, but will result in longer compile times.
  • +-AOT 컴파일을 위한 단일 파일을 포함 합니다.+ - Includes a single file for AOT compilation.
  • --AOT 컴파일에서 단일 파일을 제거 합니다.- - Removes a single file from AOT compilation.

예를 들어 --aot:all,-MyAssembly.dll , MyAssembly.dll MonoBundle의 모든 어셈블리에 대해 AOT 컴파일을 사용 하도록 설정 하 --aot:core|hybrid,+MyOtherAssembly.dll,-mscorlib.dll 고, 하이브리드을 mscorlib.dll사용 하도록 설정 하 MyOtherAssembly.dll 고, 코드 AOT는를 포함 하 고를 제외 합니다.For example, --aot:all,-MyAssembly.dll would enable AOT compilation on all of the assemblies in the MonoBundle except MyAssembly.dll and --aot:core|hybrid,+MyOtherAssembly.dll,-mscorlib.dll would enable hybrid, code AOT include the MyOtherAssembly.dll and excluding the mscorlib.dll.

부분 정적 등록자Partial static registrar

Xamarin.ios 앱을 개발할 때 변경 완료와 테스트 간의 시간을 최소화 하는 것이 개발 최종 기한에 중요 한 것이 될 수 있습니다.When developing a Xamarin.Mac app, minimizing the time between completing a change and testing it can become important to meeting development deadlines. 코드 베이스 및 단위 테스트의 모듈화와 같은 전략을 통해 응용 프로그램에서 비용이 많이 드는 전체 다시 빌드를 필요로 하는 횟수를 줄임으로써 컴파일 시간을 줄일 수 있습니다.Strategies such as modularization of codebases and unit tests can help to decrease compile times, as they reduce the number of times that an app will require an expensive full rebuild.

또한 xamarin.ios를 처음 접하는 경우 최초로에서 비롯 한 부분 정적 등록자디버그 구성에서 xamarin.ios 앱의 시작 시간을 크게 줄일 수 있습니다.Additionally, and new to Xamarin.Mac, Partial Static Registrar (as pioneered by Xamarin.iOS) can dramatically reduce the launch times of a Xamarin.Mac app in the Debug configuration. 부분 정적 등록자를 사용 하는 방법을 이해 하는 것은 디버그 시작 시 거의 5 배 향상 된 기능을 squeezed 수 있습니다. 즉, 등록자의 정의, 정적 및 동적 간의 차이 및이 "부분 정적" 버전에서 수행 하는 작업에 대해 약간의 배경 지식이 소요 됩니다.Understanding how using the Partial Static Registrar can squeezed out an almost a 5x improvement in debug launch will take a bit of background on what the registrar is, what the difference is between static and dynamic, and what this “partial static” version does.

등록자 정보About the registrar

Xamarin.ios 응용 프로그램은 Apple의 공동 Coa 프레임 워크 및 목표-C 런타임의 공동 coa 프레임 워크입니다.Under the hood of any Xamarin.Mac application lies the Cocoa framework from Apple and the Objective-C runtime. 이 "기본 세계"와의 C# "관리 세계" 사이에 브리지를 구축 하는 것은 xamarin.ios의 주요 책임입니다.Building a bridge between this "native world” and the "managed world” of C# is the primary responsibility of Xamarin.Mac. 이 작업의 일부는 메서드 내 NSApplication.Init () 에서 실행 되는 등록자에 의해 처리 됩니다.Part of this task is handled by the registrar, which is executed inside NSApplication.Init () method. 이는 xamarin.ios NSApplication.Init 에서 cocoa api를 먼저 호출 해야 하는 한 가지 이유입니다.This is one reason that any use of Cocoa APIs in Xamarin.Mac requires NSApplication.Init to be called first.

등록자 C# 의 작업은 NSApplicationDelegate, NSView NSWindow, 및NSObject과 같은 클래스에서 파생 되는 앱 클래스의 존재를 목표 C 런타임에 알려 주는 것입니다.The registrar’s job is to inform the Objective-C runtime of the existence of the app's C# classes that derive from classes such as NSApplicationDelegate, NSView, NSWindow, and NSObject. 이렇게 하려면 앱에서 모든 형식을 검색 하 여 등록 해야 하는 항목 및 보고할 각 형식의 요소를 확인 해야 합니다.This requires a scan of all types in the app to determine what needs registering and what elements on each type to report.

이 검색은 리플렉션을 사용 하 여 응용 프로그램을 시작할 때 동적으로 수행 하거나 빌드 시간 단계로 정적으로 수행할 수 있습니다.This scan can be done either dynamically, at startup of the application with reflection, or statically, as a build time step. 등록 유형을 선택 하는 경우 개발자는 다음 사항을 알고 있어야 합니다.When picking a registration type, the developer should be aware of the following:

  • 정적 등록은 시작 시간을 크게 줄일 수 있지만 빌드 시간을 상당히 느리게 할 수 있습니다 (일반적으로 이중 디버그 빌드 시간 이상).Static registration can drastically reduce launch times, but can slow down builds times significantly (typically more than double debug build time). 이는 릴리스 구성 빌드에 대 한 기본값입니다.This will be the default for Release configuration builds.
  • 동적 등록은 응용 프로그램이 시작 되 고 코드 생성을 건너뛸 때까지이 작업을 지연 하지만, 이러한 추가 작업은 응용 프로그램 시작 시 눈에 띄는 일시 중지 (2 초 이상)를 만들 수 있습니다.Dynamic registration delays this work until application launch and skips code generation, but this additional work can create a noticeable pause (at least two seconds) in application launch . 이는 기본적으로 동적 등록으로 설정 되 고 리플렉션의 속도가 느린 디버그 구성 빌드에서 특히 그렇습니다.This is especially noticeable in debug configuration builds, which defaults to dynamic registration and whose reflection is slower.

Xamarin.ios 8.13에 처음 도입 된 부분 정적 등록은 개발자에 게 두 옵션 중에서 가장 적합 한 기능을 제공 합니다.Partial Static Registration, first introduced in Xamarin.iOS 8.13, gives the developer the best of both options. Xamarin.Mac.dll 모든 요소에 대 한 등록 정보를 미리 계산 하 고이 정보를 정적 라이브러리의 xamarin.ios로 전달 하면 (빌드 시에만 연결 해야 함) Microsoft에서 대부분의 리플렉션 시간을 동적으로 제거 했습니다. 등록자는 빌드 시간에 영향을 주지 않습니다.By pre-computing the registration information of every element in Xamarin.Mac.dll and shipping this information with Xamarin.Mac in a static library (that only needs to be linked to at build time), Microsoft has removed most of the reflection time of the dynamic registrar while not impacting build time.

부분 정적 등록자 사용Enabling the partial static registrar

부분 정적 등록자는 솔루션 탐색기에서 프로젝트 이름을 두 번 클릭 하 고 mac 빌드 로 이동한 다음 --registrar:static 추가 mmp arguments: 필드에 추가 하 여 xamarin.ios에서 사용 하도록 설정 됩니다.The Partial Static Registrar is enabled in Xamarin.Mac by double-clicking the Project Name in the Solution Explorer, navigating to Mac Build and adding --registrar:static to the Additional mmp arguments: field. 예:For example:

추가 mmp 인수에 부분 정적 등록자 추가Adding the partial static registrar to additional mmp arguments

추가 자료Additional resources

다음은 내부적으로 작업을 수행 하는 방법에 대 한 자세한 설명입니다.Here are some more detailed explanations of how things work internally: