Как работает Xamarin.Mac
Большую часть времени разработчику никогда не придется беспокоиться о внутренней "магии" Xamarin.Mac, однако, имея грубое понимание того, как вещи работают под капотом, поможет как интерпретировать существующую документацию с объективом C# и отладкой проблем, когда они возникают.
В Xamarin.Mac приложение мостит два мира: существует Objective-C среда выполнения на основе, содержащая экземпляры собственных классов (NSString
, NSApplication
и т. д.), а среда выполнения C# содержит экземпляры управляемых классов (System.String
и HttpClient
т. д.). Между этими двумя мирами Xamarin.Mac создает двусторонний мост, чтобы приложение может вызывать методы (селекторы) в Objective-C (например NSApplication.Init
) и Objective-C вызывать методы C# приложения (например, методы делегата приложения). Как правило, вызовы Objective-C обрабатываются прозрачно через P/Invokes и некоторые код среды выполнения Xamarin предоставляет.
Предоставление классам И методам C# доступ к Objective-C
Тем не менее, чтобы Objective-C вернуться в объекты C# приложения, их необходимо предоставить таким образом, чтобы Objective-C понять. Это делается с помощью Register
атрибутов и Export
атрибутов. Возьмем следующий пример:
[Register ("MyClass")]
public class MyClass : NSObject
{
[Export ("init")]
public MyClass ()
{
}
[Export ("run")]
public void Run ()
{
}
}
В этом примере Objective-C среда выполнения теперь будет знать о классе, вызываемом MyClass
init
селекторами и run
.
В большинстве случаев это сведения о реализации, которые разработчик может игнорировать, так как большинство обратных вызовов, получаемых приложением, будет либо через переопределенные методы классов base
(напримерAppDelegate
, , Delegates
), DataSources
либо действия, передаваемые в API. Во всех этих случаях Export
атрибуты не нужны в коде C#.
Выполнение конструктора
Во многих случаях разработчику потребуется предоставить API создания классов C# приложения для Objective-C среды выполнения, чтобы его можно было создать из таких мест, как при вызове в раскадровки или XIB-файлах. Ниже приведены пять наиболее распространенных конструкторов, используемых в приложениях Xamarin.Mac:
// 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
NSCoder
созданные конструкторы при создании некоторых типов, таких как пользовательские NSViews
. Если Xamarin.Mac необходимо вызвать один из этих конструкторов в ответ на Objective-C запрос среды выполнения и вы удалили его, приложение завершится сбоем в машинном коде и может быть трудно определить именно эту проблему.
Управление памятью и циклы
Управление памятью в Xamarin.Mac очень похоже на Xamarin.iOS. Это также сложный раздел, который выходит за рамки этого документа. Ознакомьтесь с рекомендациями по работе с памятью и производительностью.
Перед компиляцией времени
Как правило, приложения .NET не компилируются до машинного кода при их построении, вместо этого они компилируются в промежуточный уровень, называемый кодом IL, который получает JIT-код , скомпилированный в машинный код при запуске приложения.
Время, затраченное на JIT-компиляцию этого машинного кода, может замедлить запуск приложения Xamarin.Mac до 20 %, так как требуется время для создания необходимого кода компьютера.
Из-за ограничений, введенных Apple в iOS, JIT-компиляция кода IL недоступна для Xamarin.iOS. В результате все приложения Xamarin.iOS полны заранее (AOT), скомпилированные в машинный код во время цикла сборки.
Новые возможности Xamarin.Mac — это возможность AOT код IL во время цикла сборки приложения, как и Xamarin.iOS. Xamarin.Mac использует гибридный подход AOT, который компилирует большинство необходимых машинного кода, но позволяет среде выполнения компилировать необходимые батуты и гибкость для поддержки Отражения.Эмит (и других вариантов использования, которые в настоящее время работают на Xamarin.Mac).
Существует две основные области, в которых AOT может помочь приложению Xamarin.Mac:
- Лучше "собственные" журналы сбоев . Если приложение Xamarin.Mac завершает работу в машинном коде, что часто возникает при выполнении недопустимых вызовов в API Cocoa (например, отправка
null
в метод, который не принимает его), собственные журналы сбоев с кадрами JIT трудно проанализировать. Так как кадры JIT не имеют сведений об отладке, будет несколько строк со смещениями шестнадцатеричных смещений и нет подсказки о том, что происходит. AOT создает "реальные" именованные кадры и трассировки гораздо проще читать. Это также означает, что приложение Xamarin.Mac лучше взаимодействует с собственными инструментами, такими как lldb и Tools. - Улучшенная производительность времени запуска. Для больших приложений Xamarin.Mac с несколькими секундами запуска JIT,компилируя весь код, может занять значительное время. AOT выполняет эту работу заранее.
Включение компиляции AOT
AOT включен в Xamarin.Mac, дважды щелкнув имя проекта в Обозреватель решений, перейдя к Сборке Mac и добавив --aot:[options]
к дополнительным аргументам mmp: поле (где [options]
один или несколько вариантов управления типом AOT см. ниже). Например:
Внимание
Включение компиляции AOT значительно увеличивает время сборки, иногда до нескольких минут, но это может улучшить время запуска приложения в среднем на 20%. В результате компиляция AOT должна быть включена только в сборках выпуска приложения Xamarin.Mac.
Параметры компиляции Aot
Существует несколько различных вариантов, которые можно настроить при включении компиляции AOT в приложении Xamarin.Mac:
none
— Нет компиляции AOT. Этот параметр принимается по умолчанию.all
— AOT компилирует каждую сборку в MonoBundle.core
— AOT компилируетXamarin.Mac
System
сборки иmscorlib
сборки.sdk
— AOT компилируетXamarin.Mac
сборки и базовые библиотеки классов (BCL).|hybrid
— Добавление этого параметра в один из указанных выше вариантов позволяет гибридному AOT, который позволяет удалять IL, но приведет к более длительной компиляции.+
— включает один файл для компиляции AOT.-
— удаляет один файл из компиляции AOT.
Например, включите компиляцию AOT для всех сборок в MonoBundle, --aot:all,-MyAssembly.dll
за исключением --aot:core|hybrid,+MyOtherAssembly.dll,-mscorlib.dll
MyAssembly.dll
гибридных, код AOT включает MyOtherAssembly.dll
и исключает.mscorlib.dll
Частичный статический registrar
При разработке приложения Xamarin.Mac минимизация времени между завершением изменения и тестированием может стать важной для достижения крайних сроков разработки. Стратегии, такие как модульизация баз кода и модульных тестов, могут помочь уменьшить время компиляции, так как они сокращают количество раз, когда приложению потребуется дорогостоящее полное перестроение.
Кроме того, и новые для Xamarin.Mac частичные статические Registrar (впервые созданные Xamarin.iOS) могут значительно сократить время запуска приложения Xamarin.Mac в конфигурации отладки . Понимание того, как использование частичной статической Registrar функции может выжать почти 5x улучшений при запуске отладки, займет немного фона по тому, что registrar такое, что разница между статическим и динамическим, и что делает эта "частичная статическая" версия.
Сведения о registrar
Под капотом любого приложения Xamarin.Mac лежит платформа Cocoa от Apple и Objective-C среды выполнения. Создание моста между этим "собственным миром" и "управляемым миром" C# является основной ответственностью Xamarin.Mac. Часть этой задачи обрабатывается методом registrar, который выполняется внутри NSApplication.Init ()
метода. Это одна из причин того, что любое использование API Cocoa в Xamarin.Mac требуется NSApplication.Init
сначала вызвать.
Задание registrarсостоит в том, чтобы сообщить Objective-C среде выполнения существования классов C# приложения, производных от таких классов, как NSApplicationDelegate
, NSView
NSWindow
и NSObject
. Для этого требуется проверка всех типов в приложении для определения потребностей регистрации и элементов каждого типа для отчета.
Эта проверка может выполняться динамически, при запуске приложения с отражением или статическим образом в качестве шага времени сборки. При выборе типа регистрации разработчик должен учитывать следующее:
- Статическое регистрация может значительно сократить время запуска, но может значительно замедлить сборку (как правило, более двух отладочного времени сборки). Это будет по умолчанию для сборок конфигурации выпуска .
- Динамическая регистрация задерживает эту работу до запуска приложения и пропускает создание кода, но эта дополнительная работа может создать заметную паузу (по крайней мере две секунды) в запуске приложения. Это особенно заметно в сборках конфигурации отладки, которая по умолчанию использует динамическую регистрацию и отражение которых медленнее.
Частичное статическое регистрация, впервые представленная в Xamarin.iOS 8.13, дает разработчику лучший из обоих вариантов. Предварительно вычисляя сведения о регистрации каждого элемента Xamarin.Mac.dll
и отправляя эти сведения с помощью Xamarin.Mac в статической библиотеке (которая должна быть связана только во время сборки), корпорация Майкрософт удалила большую часть времени отражения динамического registrar , не влияя на время сборки.
Включение частичной статической registrar
Частичный статический Registrar компонент включен в Xamarin.Mac, дважды щелкнув имя проекта в Обозреватель решений, перейдя к сборке Mac и добавив --registrar:static
в поля дополнительные аргументы mmp: поле. Например:
Дополнительные ресурсы
Ниже приведены более подробные объяснения того, как работают вещи внутри: