Бөлісу құралы:


Как работает 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 в дополнительные аргументы mmp

Внимание

Включение компиляции AOT значительно увеличивает время сборки, иногда до нескольких минут, но это может улучшить время запуска приложения в среднем на 20%. В результате компиляция AOT должна быть включена только в сборках выпуска приложения Xamarin.Mac.

Параметры компиляции Aot

Существует несколько различных вариантов, которые можно настроить при включении компиляции AOT в приложении Xamarin.Mac:

  • none — Нет компиляции AOT. Этот параметр принимается по умолчанию.
  • all — AOT компилирует каждую сборку в MonoBundle.
  • core— AOT компилирует Xamarin.MacSystem сборки и 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, NSViewNSWindowи NSObject. Для этого требуется проверка всех типов в приложении для определения потребностей регистрации и элементов каждого типа для отчета.

Эта проверка может выполняться динамически, при запуске приложения с отражением или статическим образом в качестве шага времени сборки. При выборе типа регистрации разработчик должен учитывать следующее:

  • Статическое регистрация может значительно сократить время запуска, но может значительно замедлить сборку (как правило, более двух отладочного времени сборки). Это будет по умолчанию для сборок конфигурации выпуска .
  • Динамическая регистрация задерживает эту работу до запуска приложения и пропускает создание кода, но эта дополнительная работа может создать заметную паузу (по крайней мере две секунды) в запуске приложения. Это особенно заметно в сборках конфигурации отладки, которая по умолчанию использует динамическую регистрацию и отражение которых медленнее.

Частичное статическое регистрация, впервые представленная в Xamarin.iOS 8.13, дает разработчику лучший из обоих вариантов. Предварительно вычисляя сведения о регистрации каждого элемента Xamarin.Mac.dll и отправляя эти сведения с помощью Xamarin.Mac в статической библиотеке (которая должна быть связана только во время сборки), корпорация Майкрософт удалила большую часть времени отражения динамического registrar , не влияя на время сборки.

Включение частичной статической registrar

Частичный статический Registrar компонент включен в Xamarin.Mac, дважды щелкнув имя проекта в Обозреватель решений, перейдя к сборке Mac и добавив --registrar:static в поля дополнительные аргументы mmp: поле. Например:

Добавление частичного статического registrar в дополнительные аргументы mmp

Дополнительные ресурсы

Ниже приведены более подробные объяснения того, как работают вещи внутри: