Начальное руководство по C# для разработчиков Objective-C

Xamarin.iOS позволяет использовать платформенно-независимый код, созданный на языке C#, на нескольких платформах. Однако существующие приложения iOS могут использовать Objective-C уже созданный код. Эта статья служит кратким праймером для разработчиков, Objective-C желающих перейти на Xamarin и язык C#.

Приложения для iOS и macOS, созданные на языке Objective-C, могут использовать код Xamarin и C# там, где не требуется код для конкретной платформы, за счет чего он будет также работать на устройствах не от Apple. Благодаря такому механизму можно применять на нескольких платформах разные элементы, например веб-службы, средства анализа JSON и (или) XML, любые пользовательские алгоритмы.

Чтобы использовать возможности Xamarin и по-прежнему поддерживать имеющиеся ресурсы Objective-C, код Objective-C можно сделать доступным в управляемом коде C# с помощью реализованной в Xamarin технологии привязок. Также вы всегда можете портировать код на C#, преобразовав каждую строку. Какой бы подход вы ни выбрали (привязка или портирование), необходимо иметь определенное знание языков Objective-C и C#, чтобы эффективно использовать существующий код Objective-C вместе с Xamarin.iOS.

Взаимодействие с Objective-C

В настоящее время не существует поддерживаемого механизма для создания библиотеки C#, использующей Xamarin.iOS, которую можно было бы вызывать из Objective-C. В первую очередь это связано с тем, что, помимо привязки, потребуется и среда выполнения Mono. Однако вы все равно можете создавать на Objective-C основную программную логику, включая пользовательские интерфейсы. Для этого необходимо заключить код Objective-C в библиотеку и создать к ней привязку. Xamarin.iOS потребуется только для начальной загрузки приложения (чтобы создать точку входа Main). Вся логика, выполняемая после этого, может быть написана на Objective-C и предоставлена в C# через привязку (либо с помощью P/Invoke). Такой механизм позволит вам сохранить на Objective-C всю логику работы с конкретной платформой, а на C# создавать платформенно-независимые компоненты.

В текущей статье выделены некоторые важные сходства и различия двух обсуждаемых языков. Это руководство поможет вам перейти к применению C# на платформе Xamarin.iOS любым из двух способов: создать привязку существующего кода Objective-C или портировать его на C#.

Дополнительные сведения о создании привязок см. в другой документации в разделе Привязка Objective-C.

Сравнение языков

Языки Objective-C и C# значительно отличаются друг от друга как синтаксически, так и в плане среды выполнения. Objective-C является динамическим языком со схемой передачи сообщений, а C# использует статическую типизацию. По синтаксису Objective-C очень похож на Smalltalk, тогда как C# унаследовал почти весь базовый синтаксис от Java, хотя за последние годы в нем появилось множество дополнительных возможностей и отличий.

Тем не менее, в Objective-C и C# есть несколько почти аналогичных языковых функций. Понимание различий полезно при создании привязки C# к коду Objective-C или при портировании Objective-C на C#.

Протоколы и интерфейсы

В языках Objective-C и C# используется одиночное наследование. Однако оба этих языка позволяют реализовать в одном классе сразу несколько интерфейсов. В Objective-C эти логические объекты называются протоколами,а в C# — интерфейсами. Реализация интерфейсов в C# отличается от протоколов Objective-C в первую очередь тем, что протокол может иметь необязательные методы. Дополнительные сведения см в статье о событиях, делегатах и протоколах.

Категории и методы расширения

Objective-C позволяет добавлять в класс методы, для которых нет кода реализации, используя категории. В C# похожая концепция применяется через методы расширения.

Методы расширения позволяют добавлять в класс статические методы, а статические методы в C# аналогичны методам класса в Objective-C. Например, следующий код добавляет метод с именем ScrollToBottomUITextView класса, который, в свою очередь, является управляемым классом, привязанным к классу Objective-CUITextView из UIKit:

public static class UITextViewExtensions
{
    public static void ScrollToBottom (this UITextView textView)
    {
        // code to scroll textView
    }
}

Теперь, когда в коде создан экземпляр UITextView, этот метод будет доступен в списке автозаполнения, как показано ниже:

The method available in the autocomplete

При вызове метода расширения экземпляр передается в качестве аргумента, как, например, textView в этом примере.

Платформы и сборки

В Objective-C связанные классы объединяются в специальные каталоги, называемые "платформами". В C# и .NET вместо них используются сборки, которые позволяют многократно использовать заранее скомпилированный код. В других средах (не iOS) сборки содержат код на промежуточном языке (IL). Этот код компилируется по требованию (JIT) во время выполнения программы. Однако Apple не поддерживает выполнение кода с JIT-компиляцией в приложениях iOS, выпущенных в App Store. Поэтому код C#, создаваемый в Xamarin для iOS, заранее компилируется в один исполняемый файл Unix вместе с файлами метаданных, включенными в пакет приложения.

Селекторы и именованные параметры

Методы Objective-C обязательно включают в селекторы имена параметров. Это обусловлено принципом их работы. Например, селектор AddCrayon:WithColor: четко указывает назначение каждого параметра при использовании в коде. C# также предлагает дополнительную поддержку именованных аргументов.

Например, представленный выше код можно реализовать в C# с помощью именованных аргументов следующим образом:

AddCrayon (crayon: myCrayon, color: UIColor.Blue);

В C# версии 4.0 реализована поддержка этой возможности, но на практике она применяется довольно редко. Тем не менее при необходимости вы всегда можете ею воспользоваться.

Заголовки и пространства имен

Objective-C является надстройкой над языком C и для объявления публичных элементов использует файлы заголовков, отдельные от файла реализации. В C# не используются файлы заголовков. В отличие от Objective-C, код C# содержится в пространствах имен. Чтобы включить код, существующий в определенном пространстве имен, вы можете добавить в начало файла реализации директиву using или указать использовать полное имя типа вместе с пространством имен.

Например, следующий код включает пространство имен UIKit, то есть делает все классы этого пространства имен доступными в текущей реализации:

using UIKit;
namespace MyAppNamespace
{
    // implementation of classes
}

Кроме того, ключевое слово namespace в приведенном выше коде задает пространство имен, используемое для самого файла реализации. Если несколько файлов реализации используют одно пространство имен, то это пространство имен не обязательно включать в директиву using, так как такое включение подразумевается по умолчанию.

Свойства

Как в Objective-C, так и в C# используется понятие свойств, которые представляют собой высокоуровневую абстракцию для методов доступа. В Objective-C методы доступа фактически создаются с помощью директивы компилятора @property. А в C# свойства поддерживаются в самом языке. В C# свойство можно реализовать двумя способами: длинный синтаксис для обращения к резервному полю или более короткий синтаксис автоматического свойства. Эти способы представлены в следующих примерах:

// automatic property syntax
public string Name { get; set; }

// property implemented with a backing field
string address;
public string Address {
    get {
        // could add additional code here
        return address;
    }
    set {
        address = value;
    }
}

Ключевое слово static

Ключевое слово static в Objective-C и C# имеет кардинально разные значения. В Objective-C статические функции позволяют ограничить область действия функции текущим файлом. А в C# области поддерживается через ключевые слова public, private и internal.

Переменная в Objective-C, к которой применено ключевое слово static, сохраняет свое значение при разных вызовах функций.

В C# также используется ключевое слово static. Если оно применяется к методу, оно по сути делает то же, что модификатор + в Objective-C. Проще говоря, это ключевое слово используется, чтобы создать метод класса. Его можно применить и к другим конструкциям, например к полям, свойствам и событиям. В таком случае они становятся частью самого типа, в котором объявлены, а не частью экземпляра этого типа. Вы можете даже создать статический класс, в котором все определенные методы также должны быть статическими.

NSArray и инициализация списка

Теперь Objective-C позволяет использовать для NSArray литеральный синтаксис, что упрощает инициализацию. Но в C# есть тип List с еще более богатыми возможностями — универсальный тип списка. Это означает, что тип его элементов задается в коде, предназначенном для создания списка (аналогично шаблонам в C++). Кроме того, списки поддерживают синтаксис автоматической инициализации, как показано ниже:

MyClass object1 = new MyClass ();
MyClass object2 = new MyClass ();
List<MyClass> myList = new List<MyClass>{ object1, object2 };

Блоки и лямбда-выражения

Objective-C использует блоки для создания замыканий. Это позволяет встроенной (inline) функции использовать состояние замыкающей ее области. В C# схожая концепция реализована при помощи лямбда-выражений. Лямбда-выражения в C# создаются с использованием оператора =>, как показано ниже:

(args) => {
    //  implementation code
};

Дополнительные сведения о лямбда-выражениях см. в руководстве по программированию на C#, предоставленном корпорацией Майкрософт.

Итоги

В этой статье мы сравнили широкий спектр возможностей языков Objective-C и C#. Некоторые из этих возможностей в обоих языках практически идентичны, например блоки и лямбда-выражения или категории и методы расширения. Но есть несколько аспектов, по которым языки заметно различаются, например концепция пространства имен в C# и значение ключевого слова static.