Справочник по типам привязки
В этом документе описывается список атрибутов, которые можно использовать для аннотации файлов контракта API для управления привязкой и созданным кодом.
Контракты API Xamarin.iOS и Xamarin.Mac записываются в C# главным образом в виде определений интерфейсов, определяющих способ Objective-C поверхности кода на C#. Процесс включает в себя сочетание объявлений интерфейса, а также некоторые основные определения типов, которым может потребоваться контракт API. Общие сведения о типах привязок см. в наших вспомогательных библиотеках привязкиObjective-C.
Определения типов
Синтаксис
[BaseType (typeof (BTYPE))
interface MyType : [Protocol1, Protocol2] {
IntPtr Constructor (string foo);
}
Каждый интерфейс в определении контракта, имеющий [BaseType]
атрибут, объявляет базовый тип для созданного объекта. В приведенном выше объявлении MyType
будет создан тип C# класса, который привязывается к типу Objective-C , который называется MyType
.
Если указать какие-либо типы после имени типа (в примере выше Protocol1
иProtocol2
) с помощью синтаксиса наследования интерфейса содержимое этих интерфейсов будет вложено так, как если бы они были частью контракта.MyType
Способ применения протокола Xamarin.iOS заключается в том, что тип принимает протокол путем встраивание всех методов и свойств, объявленных в протоколе в сам тип.
Ниже показано, как Objective-C объявление для UITextField
этого будет определено в контракте Xamarin.iOS:
@interface UITextField : UIControl <UITextInput> {
}
Будет написан так же, как контракт API C#:
[BaseType (typeof (UIControl))]
interface UITextField : UITextInput {
}
Вы можете управлять многими другими аспектами создания кода, применяя другие атрибуты к интерфейсу, а также настраивая [BaseType]
атрибут.
Создание событий
Одна из функций проектирования API Xamarin.iOS и Xamarin.Mac заключается в том, что мы сопоставляем Objective-C классы делегатов как события C# и обратные вызовы. Пользователи могут выбирать на основе каждого экземпляра, следует ли использовать Objective-C шаблон программирования, назначая свойствам, например Delegate
экземпляру класса, реализующего различные методы, вызываемые Objective-C средой выполнения, или выбрав события и свойства в стиле C#.
Давайте рассмотрим один пример использования Objective-C модели:
bool MakeDecision ()
{
return true;
}
void Setup ()
{
var scrollView = new UIScrollView (myRect);
scrollView.Delegate = new MyScrollViewDelegate ();
...
}
class MyScrollViewDelegate : UIScrollViewDelegate {
public override void Scrolled (UIScrollView scrollView)
{
Console.WriteLine ("Scrolled");
}
public override bool ShouldScrollToTop (UIScrollView scrollView)
{
return MakeDecision ();
}
}
В приведенном выше примере видно, что мы решили перезаписать два метода, одно уведомление о том, что произошло событие прокрутки, а второе — обратный вызов, который должен возвращать логическое значение, указывающее scrollView
, следует ли прокручивать его в верхнюю или нет.
Модель C# позволяет пользователю библиотеки прослушивать уведомления с помощью синтаксиса событий C# или синтаксиса свойства для подключения обратных вызовов, которые, как ожидается, будут возвращать значения.
Вот как код C# для той же функции выглядит так, как с помощью лямбда-кодов:
void Setup ()
{
var scrollview = new UIScrollView (myRect);
// Event connection, use += and multiple events can be connected
scrollView.Scrolled += (sender, eventArgs) { Console.WriteLine ("Scrolled"); }
// Property connection, use = only a single callback can be used
scrollView.ShouldScrollToTop = (sv) => MakeDecision ();
}
Так как события не возвращают значения (они имеют тип возвращаемого значения void), можно подключить несколько копий. Это ShouldScrollToTop
не событие, а свойство с типом UIScrollViewCondition
, который имеет эту подпись:
public delegate bool UIScrollViewCondition (UIScrollView scrollView);
Он возвращает bool
значение, в этом случае лямбда-синтаксис позволяет нам просто возвращать значение из MakeDecision
функции.
Генератор привязок поддерживает создание событий и свойств, которые связывают класс, как UIScrollView
с его UIScrollViewDelegate
(хорошо называются классом Model), это делается путем аннотирования [BaseType]
определения с Events
помощью и Delegates
параметров (описанных ниже).
Помимо аннотирования [BaseType]
этих параметров, необходимо сообщить генератору о нескольких дополнительных компонентах.
Для событий, которые принимают несколько параметров (в Objective-C соглашении является то, что первый параметр в классе делегата является экземпляром объекта отправителя), необходимо указать имя, которое вы хотите, чтобы созданный EventArgs
класс был. Это делается с атрибутом в объявлении [EventArgs]
метода в классе Model. Например:
[BaseType (typeof (UINavigationControllerDelegate))]
[Model][Protocol]
public interface UIImagePickerControllerDelegate {
[Export ("imagePickerController:didFinishPickingImage:editingInfo:"), EventArgs ("UIImagePickerImagePicked")]
void FinishedPickingImage (UIImagePickerController picker, UIImage image, NSDictionary editingInfo);
}
В приведенном выше объявлении будет создан класс, производный UIImagePickerImagePickedEventArgs
от EventArgs
параметров и пакетов, UIImage
и NSDictionary
класс. Генератор создает следующее:
public partial class UIImagePickerImagePickedEventArgs : EventArgs {
public UIImagePickerImagePickedEventArgs (UIImage image, NSDictionary editingInfo);
public UIImage Image { get; set; }
public NSDictionary EditingInfo { get; set; }
}
Затем он предоставляет следующие сведения в UIImagePickerController
классе:
public event EventHandler<UIImagePickerImagePickedEventArgs> FinishedPickingImage { add; remove; }
Методы модели, возвращающие значение, привязаны по-разному. Для них требуется как имя созданного делегата C# (сигнатура для метода), так и значение по умолчанию для возврата в случае, если пользователь не предоставляет реализацию.
Например, ShouldScrollToTop
это определение:
[BaseType (typeof (NSObject))]
[Model][Protocol]
public interface UIScrollViewDelegate {
[Export ("scrollViewShouldScrollToTop:"), DelegateName ("UIScrollViewCondition"), DefaultValue ("true")]
bool ShouldScrollToTop (UIScrollView scrollView);
}
Приведенный UIScrollViewCondition
выше делегат создаст делегат с подписью, показанной выше, и если пользователь не предоставляет реализацию, возвращаемое значение будет true.
[DefaultValue]
Помимо атрибута, можно также использовать [DefaultValueFromArgument]
атрибут, который направляет генератор для возврата значения указанного параметра в вызове или [NoDefaultValue]
параметре, который указывает генератору, что значение по умолчанию отсутствует.
BaseTypeAttribute
Синтаксис
public class BaseTypeAttribute : Attribute {
public BaseTypeAttribute (Type t);
// Properties
public Type BaseType { get; set; }
public string Name { get; set; }
public Type [] Events { get; set; }
public string [] Delegates { get; set; }
public string KeepRefUntil { get; set; }
}
BaseType.Name
Свойство используется Name
для управления именем, к которому этот тип привязывается в Objective-C мире. Обычно это имя используется для указания типа C#, соответствующего рекомендациям по проектированию платформа .NET Framework, но которое сопоставляется с именем, Objective-C которое не соответствует этому соглашению.
Например, в следующем случае мы сопоставляем тип с NSUrlConnection
типомObjective-CNSURLConnection
, так как рекомендации по проектированию платформа .NET Framework используют "URL-адрес" вместо URL-адреса:
[BaseType (typeof (NSObject), Name="NSURLConnection")]
interface NSUrlConnection {
}
Указанное имя используется в качестве значения для созданного [Register]
атрибута в привязке. Если Name
не указано, короткое имя типа используется в качестве значения атрибута [Register]
в созданных выходных данных.
BaseType.Events и BaseType.Delegates
Эти свойства используются для создания событий в стиле C#в созданных классах. Они используются для связывания заданного класса с его Objective-C классом делегата. Во многих случаях класс использует класс делегата для отправки уведомлений и событий. Например, BarcodeScanner
класс-компаньон BardodeScannerDelegate
. Класс BarcodeScanner
обычно имеет Delegate
свойство, для которого вы назначите экземпляр BarcodeScannerDelegate
, в то время как это работает, вам может потребоваться предоставить пользователям интерфейс событий стиля C#, а в тех случаях вы будете использовать Events
и Delegates
свойства атрибута [BaseType]
.
Эти свойства всегда задаются вместе и должны иметь одинаковое количество элементов и храниться в синхронизации. Массив Delegates
содержит одну строку для каждого слабо типизированного делегата, который требуется упаковать, и Events
массив содержит один тип для каждого типа, с которым требуется связать его.
[BaseType (typeof (NSObject),
Delegates=new string [] { "WeakDelegate" },
Events=new Type [] {typeof(UIAccelerometerDelegate)})]
public interface UIAccelerometer {
}
[BaseType (typeof (NSObject))]
[Model][Protocol]
public interface UIAccelerometerDelegate {
}
BaseType.KeepRefUntil
Если этот атрибут применяется при создании новых экземпляров этого класса, экземпляр этого объекта будет храниться вокруг, пока не будет вызван метод, KeepRefUntil
на который ссылается ссылка. Это полезно для улучшения удобства использования API, если вы не хотите, чтобы пользователь держал ссылку на объект вокруг использования кода. Значение этого свойства — это имя метода в Delegate
классе, поэтому его необходимо использовать в сочетании с Events
свойствами и Delegates
свойствами.
В следующем примере показано, как это используется UIActionSheet
в Xamarin.iOS:
[BaseType (typeof (NSObject), KeepRefUntil="Dismissed")]
[BaseType (typeof (UIView),
KeepRefUntil="Dismissed",
Delegates=new string [] { "WeakDelegate" },
Events=new Type [] {typeof(UIActionSheetDelegate)})]
public interface UIActionSheet {
}
[BaseType (typeof (NSObject))]
[Model][Protocol]
public interface UIActionSheetDelegate {
[Export ("actionSheet:didDismissWithButtonIndex:"), EventArgs ("UIButton")]
void Dismissed (UIActionSheet actionSheet, nint buttonIndex);
}
НазначеноDefaultCtorAttribute
Если этот атрибут применяется к определению интерфейса, он создаст [DesignatedInitializer]
атрибут по умолчанию (созданного) конструктора, который сопоставляется с селектором init
.
DisableDefaultCtorAttribute
Если этот атрибут применяется к определению интерфейса, он не позволит генератору создавать конструктор по умолчанию.
Используйте этот атрибут, если требуется инициализировать объект с помощью одного из других конструкторов класса.
PrivateDefaultCtorAttribute
Если этот атрибут применяется к определению интерфейса, он помечает конструктор по умолчанию как закрытый. Это означает, что вы по-прежнему можете создать экземпляр объекта этого класса внутри файла расширения, но он просто не будет доступен пользователям вашего класса.
CategoryAttribute
Используйте этот атрибут для определения типа, чтобы привязать Objective-C категории и предоставить их как методы расширения C# для зеркального отображения Objective-C возможностей.
Категории — это механизм, используемый Objective-C для расширения набора методов и свойств, доступных в классе. На практике они используются для расширения функциональных возможностей базового класса (например NSObject
, при связывании определенной платформы), что делает свои методы доступными, но только если новая платформа связана UIKit
. В некоторых других случаях они используются для упорядочивания функций в классе по функциям. Они похожи на методы расширения C#.
Это то, что категория будет выглядеть следующим образом:Objective-C
@interface UIView (MyUIViewExtension)
-(void) makeBackgroundRed;
@end
Приведенный выше пример найден в библиотеке, которая расширит экземпляры UIView
с помощью метода makeBackgroundRed
.
Для привязки [Category]
этих атрибутов можно использовать в определении интерфейса. При использовании [Category]
атрибута значение атрибута [BaseType]
изменяется от использования, чтобы указать базовый класс для расширения, чтобы быть типом для расширения.
Ниже показано, как UIView
расширения привязаны и преобразуются в методы расширения C#:
[BaseType (typeof (UIView))]
[Category]
interface MyUIViewExtension {
[Export ("makeBackgroundRed")]
void MakeBackgroundRed ();
}
В приведенном выше примере будет создан MyUIViewExtension
класс, содержащий MakeBackgroundRed
метод расширения. Это означает, что теперь вы можете вызывать MakeBackgroundRed
любой UIView
подкласс, предоставляя вам те же функции, что и вы.Objective-C
В некоторых случаях статические элементы находятся внутри категорий, как показано в следующем примере:
@interface FooObject (MyFooObjectExtension)
+ (BOOL)boolMethod:(NSRange *)range;
@end
Это приведет к неправильному определению интерфейса C# категории:
[Category]
[BaseType (typeof (FooObject))]
interface FooObject_Extensions {
// Incorrect Interface definition
[Static]
[Export ("boolMethod:")]
bool BoolMethod (NSRange range);
}
Это неправильно, так как для использования BoolMethod
расширения требуется экземплярFooObject
, но вы привязывают статическое расширение ObjC, это побочный эффект из-за того, как реализуются методы расширения C#.
Единственным способом использования указанных выше определений является следующий уродливый код:
(null as FooObject).BoolMethod (range);
Рекомендация, чтобы избежать этого, заключается в том, чтобы встраивать BoolMethod
определение внутри FooObject
самого определения интерфейса, это позволит вызывать это расширение, как это предназначено FooObject.BoolMethod (range)
.
[BaseType (typeof (NSObject))]
interface FooObject {
[Static]
[Export ("boolMethod:")]
bool BoolMethod (NSRange range);
}
Мы будем выдавать предупреждение (BI1117) всякий раз, когда мы найдем [Static]
член внутри [Category]
определения. Если вы действительно хотите иметь [Static]
элементы внутри [Category]
определений, вы можете замолчать предупреждение с помощью [Category (allowStaticMembers: true)]
или декорирования элемента или [Category]
определения интерфейса.[Internal]
StaticAttribute
Если этот атрибут применяется к классу, он просто создаст статический класс, который не является производным от NSObject
, поэтому [BaseType]
атрибут игнорируется. Статические классы используются для размещения общедоступных переменных C, которые необходимо предоставить.
Например:
[Static]
interface CBAdvertisement {
[Field ("CBAdvertisementDataServiceUUIDsKey")]
NSString DataServiceUUIDsKey { get; }
Будет создавать класс C# со следующим API:
public partial class CBAdvertisement {
public static NSString DataServiceUUIDsKey { get; }
}
Определения протокола и модели
Модели обычно используются реализацией протокола. Они отличаются тем, что среда выполнения будет регистрироваться только с Objective-C помощью методов, которые фактически были перезаписаны. В противном случае метод не будет зарегистрирован.
Это означает, что при подклассе класса, помеченного флагом с помощью ModelAttribute
базового метода, не следует вызывать базовый метод. Вызов этого метода вызовет следующее исключение: Foundation.You_Should_Not_Call_base_In_This_Method. Вы должны реализовать все поведение в подклассе для любых методов, которые вы переопределяете.
AbstractAttribute
По умолчанию члены, которые являются частью протокола, не являются обязательными. Это позволяет пользователям создавать подкласс Model
объекта, просто производный от класса в C# и переопределяя только те методы, которые они заботят. Objective-C Иногда контракт требует, чтобы пользователь предоставлял реализацию для этого метода (они помечены @required
директивой в Objective-C). В этих случаях следует пометить эти методы атрибутом [Abstract]
.
Атрибут [Abstract]
может применяться к методам или свойствам и приводит к тому, что генератор помечает созданный элемент как абстрактный и класс будет абстрактным классом.
Ниже приведено следующее из Xamarin.iOS:
[BaseType (typeof (NSObject))]
[Model][Protocol]
public interface UITableViewDataSource {
[Export ("tableView:numberOfRowsInSection:")]
[Abstract]
nint RowsInSection (UITableView tableView, nint section);
}
DefaultValueAttribute
Указывает значение по умолчанию, возвращаемое методом модели, если пользователь не предоставляет метод для этого конкретного метода в объекте Model.
Синтаксис
public class DefaultValueAttribute : Attribute {
public DefaultValueAttribute (object o);
public object Default { get; set; }
}
Например, в следующем мнимом классе делегата Camera
для класса мы предоставляем объект ShouldUploadToServer
, который будет предоставляться в качестве свойства класса Camera
. Если пользователь Camera
класса явно не задает значение лямбда-выражения, которое может отвечать true или false, значение по умолчанию, возвращаемое в данном случае, будет false, значение, указанное в атрибуте DefaultValue
:
[BaseType (typeof (NSObject))]
[Model][Protocol]
interface CameraDelegate {
[Export ("camera:shouldPromptForAction:"), DefaultValue (false)]
bool ShouldUploadToServer (Camera camera, CameraAction action);
}
Если пользователь задает обработчик в мнимом классе, это значение будет игнорироваться:
var camera = new Camera ();
camera.ShouldUploadToServer = (camera, action) => return SomeDecision ();
См. также: [NoDefaultValue]
, [DefaultValueFromArgument]
.
DefaultValueFromArgumentAttribute
Синтаксис
public class DefaultValueFromArgumentAttribute : Attribute {
public DefaultValueFromArgumentAttribute (string argument);
public string Argument { get; }
}
Этот атрибут при указании метода, возвращающего значение в классе модели, будет указывать генератору возвращать значение указанного параметра, если пользователь не предоставил собственный метод или лямбда-код.
Пример:
[BaseType (typeof (NSObject))]
[Model][Protocol]
public interface NSAnimationDelegate {
[Export ("animation:valueForProgress:"), DelegateName ("NSAnimationProgress"), DefaultValueFromArgumentAttribute ("progress")]
float ComputeAnimationCurve (NSAnimation animation, nfloat progress);
}
В приведенном выше случае, если пользователь NSAnimation
класса решил использовать любое из событий или свойств C# и не задал NSAnimation.ComputeAnimationCurve
лямбда-метод, возвращаемое значение будет значением, переданным в параметре хода выполнения.
См. также: [NoDefaultValue]
[DefaultValue]
ИгнорируетсяInDelegateAttribute
Иногда не следует предоставлять свойство события или делегата из класса Model в класс узла, поэтому добавление этого атрибута позволит генератору избежать создания любого метода, украшенного им.
[BaseType (typeof (UINavigationControllerDelegate))]
[Model][Protocol]
public interface UIImagePickerControllerDelegate {
[Export ("imagePickerController:didFinishPickingImage:editingInfo:"), EventArgs ("UIImagePickerImagePicked")]
void FinishedPickingImage (UIImagePickerController picker, UIImage image, NSDictionary editingInfo);
[Export ("imagePickerController:didFinishPickingImage:"), IgnoredInDelegate)] // No event generated for this method
void FinishedPickingImage (UIImagePickerController picker, UIImage image);
}
ДелегатNameAttribute
Этот атрибут используется в методах модели, возвращающих значения, чтобы задать имя используемой подписи делегата.
Пример:
[BaseType (typeof (NSObject))]
[Model][Protocol]
public interface NSAnimationDelegate {
[Export ("animation:valueForProgress:"), DelegateName ("NSAnimationProgress"), DefaultValueFromArgumentAttribute ("progress")]
float ComputeAnimationCurve (NSAnimation animation, float progress);
}
При приведенном выше определении генератор создаст следующее общедоступное объявление:
public delegate float NSAnimationProgress (MonoMac.AppKit.NSAnimation animation, float progress);
ДелегатApiNameAttribute
Этот атрибут используется для изменения имени свойства, созданного в классе узла. Иногда это полезно, если имя метода класса FooDelegate имеет смысл для класса Делегата, но будет выглядеть странно в классе узла как свойство.
Кроме того, это действительно полезно (и необходимо), если у вас есть два или более методов перегрузки, которые имеют смысл сохранить их как в классе FooDelegate, но вы хотите предоставить их в классе узла с лучшим именем.
Пример:
[BaseType (typeof (NSObject))]
[Model][Protocol]
public interface NSAnimationDelegate {
[Export ("animation:valueForProgress:"), DelegateApiName ("ComputeAnimationCurve"), DelegateName ("Func<NSAnimation, float, float>"), DefaultValueFromArgument ("progress")]
float GetValueForProgress (NSAnimation animation, float progress);
}
При приведенном выше определении генератор создаст следующее общедоступное объявление в классе узла:
public Func<NSAnimation, float, float> ComputeAnimationCurve { get; set; }
EventArgsAttribute
Для событий, которые принимают несколько параметров (в Objective-C соглашении является то, что первый параметр в классе делегата является экземпляром объекта отправителя), необходимо указать имя, которое необходимо указать для созданного класса EventArgs. Это делается с атрибутом [EventArgs]
в объявлении метода в Model
классе.
Например:
[BaseType (typeof (UINavigationControllerDelegate))]
[Model][Protocol]
public interface UIImagePickerControllerDelegate {
[Export ("imagePickerController:didFinishPickingImage:editingInfo:"), EventArgs ("UIImagePickerImagePicked")]
void FinishedPickingImage (UIImagePickerController picker, UIImage image, NSDictionary editingInfo);
}
Приведенное выше объявление создаст класс, производный UIImagePickerImagePickedEventArgs
от EventArgs и упаковывает оба параметра, UIImage
а также класс NSDictionary
. Генератор создает следующее:
public partial class UIImagePickerImagePickedEventArgs : EventArgs {
public UIImagePickerImagePickedEventArgs (UIImage image, NSDictionary editingInfo);
public UIImage Image { get; set; }
public NSDictionary EditingInfo { get; set; }
}
Затем он предоставляет следующие сведения в UIImagePickerController
классе:
public event EventHandler<UIImagePickerImagePickedEventArgs> FinishedPickingImage { add; remove; }
EventNameAttribute
Этот атрибут используется для изменения имени события или свойства, созданного в классе генератором. Иногда полезно, если имя метода класса Model имеет смысл для класса модели, но будет выглядеть странно в исходном классе как событие или свойство.
Например, использует UIWebView
следующий бит из UIWebViewDelegate
:
[Export ("webViewDidFinishLoad:"), EventArgs ("UIWebView"), EventName ("LoadFinished")]
void LoadingFinished (UIWebView webView);
Приведенный выше метод предоставляется LoadingFinished
в качестве метода, UIWebViewDelegate
но LoadFinished
как событие для подключения к UIWebView
:
var webView = new UIWebView (...);
webView.LoadFinished += delegate { Console.WriteLine ("done!"); }
ModelAttribute
При применении атрибута [Model]
к определению типа в API контракта среда выполнения создаст специальный код, который будет вызывать методы только в классе, если пользователь перезаписывает метод в классе. Этот атрибут обычно применяется ко всем API, которые упаковывают класс делегата Objective-C .
Среда выполнения также создаст Objective-C класс, соответствующий имени соответствующего протокола.
Можно настроить имя Objective-C класса двумя способами:
Параметр:
AutoGeneratedName = true
[Model (AutoGeneratedName = true)]
Это приведет к созданию уникального Objective-C имени среды выполнения для типа. Имя в настоящее время основано на имени сборки и полном имени типа модели (это может измениться в будущем).
Явно указывая имя:
[Model (Name = "CustomName")]
Рекомендуется использовать AutoGeneratedName = true
. В .NET имя всегда создается (если он явно не указан как в 2. выше), а AutoGeneratedName
свойство больше не существует.
NoDefaultValueAttribute
Указывает, что метод в модели не предоставляет возвращаемое значение по умолчанию.
Это работает с Objective-C средой выполнения, отвечая на Objective-C false
запрос среды выполнения, чтобы определить, реализован ли указанный селектор в этом классе.
[BaseType (typeof (NSObject))]
[Model][Protocol]
interface CameraDelegate {
[Export ("shouldDisplayPopup"), NoDefaultValue]
bool ShouldUploadToServer ();
}
См. также: [DefaultValue]
[DefaultValueFromArgument]
Протоколы
Концепция Objective-C протокола на самом деле не существует в C#. Протоколы похожи на интерфейсы C#, но они отличаются тем, что не все методы и свойства, объявленные в протоколе, должны быть реализованы классом, который его принимает. Вместо этого некоторые методы и свойства являются необязательными.
Некоторые протоколы обычно используются в качестве классов модели, они должны быть привязаны с помощью атрибута [Model]
.
[BaseType (typeof (NSObject))]
[Model, Protocol]
interface MyProtocol {
// Use [Abstract] when the method is defined in the @required section
// of the protocol definition in Objective-C
[Abstract]
[Export ("say:")]
void Say (string msg);
[Export ("listen")]
void Listen ();
}
Начиная с Xamarin.iOS 7.0 была включена новая и улучшенная функция привязки протокола. Любое определение, содержащее [Protocol]
атрибут, фактически создает три вспомогательных класса, которые значительно улучшают способ использования протоколов:
// Full method implementation, contains all methods
class MyProtocol : IMyProtocol {
public void Say (string msg);
public void Listen (string msg);
}
// Interface that contains only the required methods
interface IMyProtocol: INativeObject, IDisposable {
[Export ("say:")]
void Say (string msg);
}
// Extension methods
static class IMyProtocol_Extensions {
public static void Optional (this IMyProtocol this, string msg);
}
}
Реализация класса предоставляет полный абстрактный класс, который можно переопределить отдельные методы и получить полную безопасность типов. Но из-за того, что C# не поддерживает несколько наследования, существуют сценарии, в которых может потребоваться другой базовый класс, но по-прежнему требуется реализовать интерфейс.
Это место, в котором происходит созданное определение интерфейса. Это интерфейс, имеющий все необходимые методы из протокола. Это позволяет разработчикам, которые хотят реализовать протокол только для реализации интерфейса. Среда выполнения автоматически регистрирует тип в качестве принятия протокола.
Обратите внимание, что интерфейс перечисляет только необходимые методы и предоставляет необязательные методы. Это означает, что классы, которые принимают протокол, получат полную проверку типов для необходимых методов, но придется прибегнуть к слабому вводу (вручную с помощью атрибутов экспорта и сопоставления подписи) для необязательных методов протокола.
Чтобы упростить использование API, использующего протоколы, средство привязки также создаст класс методов расширений, который предоставляет все необязательные методы. Это означает, что до тех пор, пока вы используете API, вы сможете обрабатывать протоколы как все методы.
Если вы хотите использовать определения протокола в API, необходимо написать скелет пустых интерфейсов в определении API. Если вы хотите использовать MyProtocol в API, вам потребуется сделать следующее:
[BaseType (typeof (NSObject))]
[Model, Protocol]
interface MyProtocol {
// Use [Abstract] when the method is defined in the @required section
// of the protocol definition in Objective-C
[Abstract]
[Export ("say:")]
void Say (string msg);
[Export ("listen")]
void Listen ();
}
interface IMyProtocol {}
[BaseType (typeof(NSObject))]
interface MyTool {
[Export ("getProtocol")]
IMyProtocol GetProtocol ();
}
Это необходимо, так как во время IMyProtocol
привязки не будет существовать, поэтому необходимо предоставить пустой интерфейс.
Внедрение интерфейсов, созданных протоколом
При реализации одного из интерфейсов, созданных для протоколов, как показано ниже.
class MyDelegate : NSObject, IUITableViewDelegate {
nint IUITableViewDelegate.GetRowHeight (nint row) {
return 1;
}
}
Реализация необходимых методов интерфейса экспортируется с соответствующим именем, поэтому это эквивалентно следующему:
class MyDelegate : NSObject, IUITableViewDelegate {
[Export ("getRowHeight:")]
nint IUITableViewDelegate.GetRowHeight (nint row) {
return 1;
}
}
Это будет работать для всех обязательных элементов протокола, но существует особый случай с необязательными селекторами, которые следует учитывать.
Необязательные члены протокола обрабатываются одинаково при использовании базового класса:
public class UrlSessionDelegate : NSUrlSessionDownloadDelegate {
public override void DidWriteData (NSUrlSession session, NSUrlSessionDownloadTask downloadTask, long bytesWritten, long totalBytesWritten, long totalBytesExpectedToWrite)
но при использовании интерфейса протокола необходимо добавить [экспорт]. Интегрированная среда разработки добавит ее через автозавершение при добавлении, начиная с переопределения.
public class UrlSessionDelegate : NSObject, INSUrlSessionDownloadDelegate {
[Export ("URLSession:downloadTask:didWriteData:totalBytesWritten:totalBytesExpectedToWrite:")]
public void DidWriteData (NSUrlSession session, NSUrlSessionDownloadTask downloadTask, long bytesWritten, long totalBytesWritten, long totalBytesExpectedToWrite)
Существует небольшое различие в поведении между двумя в среде выполнения:
- Пользователи базового класса (NSUrlSessionDownloadDelegate) предоставляют все обязательные и необязательные селекторы, возвращая разумные значения по умолчанию.
- Пользователи интерфейса (НАПРИМЕР, INSUrlSessionDownloadDelegate) отвечают только на указанные селекторы.
Некоторые редкие классы могут вести себя по-разному здесь. В почти всех случаях, однако, это безопасно использовать либо.
Встраивание протокола
Хотя вы привязываете существующие Objective-C типы, объявленные как принятие протокола, необходимо напрямую встраивать протокол. Для этого просто объявите протокол как интерфейс без атрибута [BaseType]
и перечислите протокол в списке базовых интерфейсов для вашего интерфейса.
Пример:
interface SpeakProtocol {
[Export ("say:")]
void Say (string msg);
}
[BaseType (typeof (NSObject))]
interface Robot : SpeakProtocol {
[Export ("awake")]
bool Awake { get; set; }
}
Определения элементов
Атрибуты в этом разделе применяются к отдельным элементам типа: свойствам и объявлениям методов.
AlignAttribute
Используется для указания значения выравнивания для типов возвращаемых свойств. Некоторые свойства принимают указатели на адреса, которые должны быть выровнены по определенным границам (в Xamarin.iOS это происходит, например с некоторыми GLKBaseEffect
свойствами, которые должны быть выровнены по 16 байтам). Это свойство можно использовать для декорирования метода получения и использования значения выравнивания. Обычно это используется с типами и OpenTK.Matrix4
типами при интеграции с OpenTK.Vector4
Objective-C API.
Пример:
public interface GLKBaseEffect {
[Export ("constantColor")]
Vector4 ConstantColor { [Align (16)] get; set; }
}
Внешний видAttribute
Атрибут [Appearance]
ограничен iOS 5, где был представлен диспетчер внешнего вида.
Атрибут [Appearance]
может применяться к любому методу или свойству, участвующим UIAppearance
в платформе. Если этот атрибут применяется к методу или свойству класса, он будет направлять генератор привязки для создания строго типизированного класса внешнего вида, который используется для стиля всех экземпляров этого класса или экземпляров, соответствующих определенным критериям.
Пример:
public interface UIToolbar {
[Export ("setBackgroundImage:forToolbarPosition:barMetrics:")]
[Appearance]
void SetBackgroundImage (UIImage backgroundImage, UIToolbarPosition position, UIBarMetrics barMetrics);
[Export ("backgroundImageForToolbarPosition:barMetrics:")]
[Appearance]
UIImage GetBackgroundImage (UIToolbarPosition position, UIBarMetrics barMetrics);
}
Приведенный выше код создаст следующий код в uiToolbar:
public partial class UIToolbar {
public partial class UIToolbarAppearance : UIView.UIViewAppearance {
public virtual void SetBackgroundImage (UIImage backgroundImage, UIToolbarPosition position, UIBarMetrics barMetrics);
public virtual UIImage GetBackgroundImage (UIToolbarPosition position, UIBarMetrics barMetrics)
}
public static new UIToolbarAppearance Appearance { get; }
public static new UIToolbarAppearance AppearanceWhenContainedIn (params Type [] containers);
}
AutoReleaseAttribute (Xamarin.iOS 5.4)
[AutoReleaseAttribute]
Используйте методы и свойства для оболочки вызова метода к методу в объектеNSAutoReleasePool
.
В Objective-C некоторых методах, возвращающих значения, добавленные в значение по умолчанию NSAutoReleasePool
. По умолчанию они будут переходить к потоку NSAutoReleasePool
, но так как Xamarin.iOS также сохраняет ссылку на объекты до тех пор, пока управляемый объект живет, вам может не потребоваться сохранить дополнительную ссылку на NSAutoReleasePool
нее, которая будет использоваться только до тех пор, пока поток не вернется к следующему потоку, или вернуться к основному циклу.
Этот атрибут применяется например к тяжелым свойствам (например UIImage.FromFile
), возвращающим объекты, добавленные в значение по умолчанию NSAutoReleasePool
. Без этого атрибута изображения будут храниться до тех пор, пока поток не вернул элемент управления в основной цикл. Uf ваш поток был каким-то фоновым загрузчиком, который всегда жив и ждет работы, изображения никогда не будут выпущены.
ForcedTypeAttribute
Используется [ForcedTypeAttribute]
для принудительного создания управляемого типа, даже если возвращаемый неуправляемый объект не соответствует типу, описанному в определении привязки.
Это полезно, если тип, описанный в заголовке, не соответствует возвращаемого типа собственного метода, например, принимает следующее Objective-C определение из NSURLSession
:
- (NSURLSessionDownloadTask *)downloadTaskWithRequest:(NSURLRequest *)request
Очевидно, что он вернет NSURLSessionDownloadTask
экземпляр, но все же возвращает NSURLSessionTask
объект , который является суперклассом и таким образом не преобразуется в NSURLSessionDownloadTask
. Так как мы в типобезопасном контексте InvalidCastException
произойдет.
Чтобы соответствовать описанию заголовка и избежать InvalidCastException
использования, [ForcedTypeAttribute]
используется.
[BaseType (typeof (NSObject), Name="NSURLSession")]
interface NSUrlSession {
[Export ("downloadTaskWithRequest:")]
[return: ForcedType]
NSUrlSessionDownloadTask CreateDownloadTask (NSUrlRequest request);
}
Также [ForcedTypeAttribute]
принимает логическое значение с именем Owns
, которое по false
умолчанию [ForcedType (owns: true)]
. Параметр owns используется для выполнения политики владения для объектов Core Foundation.
Допустимо [ForcedTypeAttribute]
только для параметров, свойств и возвращаемого значения.
BindAsAttribute
Разрешает [BindAsAttribute]
привязку NSNumber
NSValue
и NSString
(перечисления) в более точные типы C#. Атрибут можно использовать для создания более точного, более точного API .NET через собственный API.
Методы можно декорировать (при возвращаемом значении), параметрами и свойствами BindAs
. Единственное ограничение заключается в том, что член не должен находиться внутри или [Model]
в интерфейсе[Protocol]
.
Например:
[return: BindAs (typeof (bool?))]
[Export ("shouldDrawAt:")]
NSNumber ShouldDraw ([BindAs (typeof (CGRect))] NSValue rect);
Выходные данные:
[Export ("shouldDrawAt:")]
bool? ShouldDraw (CGRect rect) { ... }
Внутренне мы будем делать bool?
преобразования ->NSNumber
и CGRect
<->NSValue
преобразования.<
Текущие поддерживаемые типы инкапсуляции:
NSValue
NSNumber
NSString
NSValue
Следующие типы данных C# поддерживаются для инкапсулированного из/в NSValue
:
- CGAffineTransform
- NSRange
- CGVector
- SCNMatrix4
- CLLocationCoordinate2D
- SCNVector3
- SCNVector4
- CGPoint / PointF
- CGRect / RectangleF
- CGSize / SizeF
- UIEdgeInsets
- UIOffset
- MKCoordinateSpan
- CMTimeRange
- CMTime
- CMTimeMapping
- CATransform3D
NSNumber
Следующие типы данных C# поддерживаются для инкапсулированного из/в NSNumber
:
- bool
- byte
- двойной точности
- с плавающей запятой
- short
- INT
- длинный
- sbyte
- ushort
- uint
- ulong
- nfloat
- nint
- nuint
- Перечисления
NSString
[BindAs]
работает в константе NSString с перечислением, чтобы можно было создать лучший API .NET, например:
[BindAs (typeof (CAScroll))]
[Export ("supportedScrollMode")]
NSString SupportedScrollMode { get; set; }
Выходные данные:
[Export ("supportedScrollMode")]
CAScroll SupportedScrollMode { get; set; }
Мы будем обрабатывать enum
<>NSString
преобразование только в том случае, если предоставленный тип [BindAs]
перечисления поддерживается константой NSString.
Массивы
[BindAs]
также поддерживает массивы любого из поддерживаемых типов, можно использовать следующее определение API в качестве примера:
[return: BindAs (typeof (CAScroll []))]
[Export ("getScrollModesAt:")]
NSString [] GetScrollModes ([BindAs (typeof (CGRect []))] NSValue [] rects);
Выходные данные:
[Export ("getScrollModesAt:")]
CAScroll? [] GetScrollModes (CGRect [] rects) { ... }
Параметр rects
будет инкапсулирован в объект NSArray
, содержащий NSValue
для каждого CGRect
из них, и в возврате вы получите массив CAScroll?
, созданный с помощью значений возвращаемого NSArray
содержащего NSStrings
.
BindAttribute
Атрибут [Bind]
имеет два использования, когда применяется к объявлению метода или свойства, а другой при применении к отдельному методу получения или задания в свойстве.
Если используется для метода или свойства, [Bind]
эффект атрибута заключается в создании метода, вызывающего указанный селектор. Но полученный созданный метод не украшен [Export]
атрибутом, что означает, что он не может участвовать в переопределении метода. Обычно это используется в сочетании с атрибутом [Target]
для реализации Objective-C методов расширения.
Например:
public interface UIView {
[Bind ("drawAtPoint:withFont:")]
SizeF DrawString ([Target] string str, CGPoint point, UIFont font);
}
При использовании в методе получения или задания [Bind]
атрибут используется для изменения значений по умолчанию, выводимых генератором кода при создании имен селектора получения и задания Objective-C для свойства. По умолчанию при флаге свойства с именем fooBar
генератор создаст fooBar
экспорт для метода получения и setFooBar:
задания. В некоторых случаях Objective-C не следует этому соглашению, обычно они изменяют имя isFooBar
метода получения.
Этот атрибут будет использоваться для информирования генератора об этом.
Например:
// Default behavior
[Export ("active")]
bool Active { get; set; }
// Custom naming with the Bind attribute
[Export ("visible")]
bool Visible { [Bind ("isVisible")] get; set; }
AsyncAttribute
Доступно только в версии Xamarin.iOS 6.3 и более поздней версии.
Этот атрибут можно применить к методам, которые принимают обработчик завершения в качестве последнего аргумента.
Атрибут можно использовать [Async]
для методов, последний аргумент которого является обратным вызовом. При применении этого метода генератор привязки создаст версию этого метода с суффиксом Async
. Если обратный вызов не принимает параметров, возвращаемое значение будет Task
иметь значение, если обратный вызов принимает параметр, результат будет результатом Task<T>
.
[Export ("upload:complete:")]
[Async]
void LoadFile (string file, NSAction complete)
Ниже будет создан этот асинхронный метод:
Task LoadFileAsync (string file);
Если обратный вызов принимает несколько параметров, необходимо задать ResultType
или ResultTypeName
указать требуемое имя созданного типа, которое будет содержать все свойства.
delegate void OnComplete (string [] files, nint byteCount);
[Export ("upload:complete:")]
[Async (ResultTypeName="FileLoading")]
void LoadFiles (string file, OnComplete complete)
Ниже будет создан этот асинхронный метод, где FileLoading
содержатся свойства для доступа к обоим files
и byteCount
:
Task<FileLoading> LoadFile (string file);
Если последним параметром обратного вызова является NSError
, созданный Async
метод проверяет, не имеет ли значение NULL, а если это так, созданный асинхронный метод установит исключение задачи.
[Export ("upload:onComplete:")]
[Async]
void Upload (string file, Action<string,NSError> onComplete);
Приведенный выше метод создает следующий асинхронный метод:
Task<string> UploadAsync (string file);
При возникновении ошибки результирующая задача будет иметь исключение, заданное в качестве NSErrorException
оболочки результирующего NSError
объекта.
AsyncAttribute.ResultType
Используйте это свойство, чтобы указать значение возвращаемого Task
объекта. Этот параметр принимает существующий тип, поэтому его необходимо определить в одном из определений основных api.
AsyncAttribute.ResultTypeName
Используйте это свойство, чтобы указать значение возвращаемого Task
объекта. Этот параметр принимает имя требуемого имени типа, генератор создает ряд свойств, по одному для каждого параметра, который принимает обратный вызов.
AsyncAttribute.MethodName
Используйте это свойство для настройки имени созданных асинхронных методов. По умолчанию используется имя метода и добавляется текст Async, который можно использовать для изменения этого по умолчанию.
DesignatedInitializerAttribute
Когда этот атрибут применяется к конструктору, он создаст то же самое [DesignatedInitializer]
в конечной сборке платформы. Это поможет интегрированной среде разработки указать, какой конструктор должен использоваться в подклассах.
Это должно сопоставляться с Objective-Cиспользованием /clang.__attribute__((objc_designated_initializer))
DisableZeroCopyAttribute
Этот атрибут применяется к строковым параметрам или строковым свойствам и указывает генератору кода не использовать маршалинг строк нулевого копирования для этого параметра, а вместо этого создать новый экземпляр NSString из строки C#.
Этот атрибут требуется только в строках, если вы указываете генератору использовать маршалинг строк нулевого копирования с помощью --zero-copy
параметра командной строки или настройки атрибута ZeroCopyStringsAttribute
уровня сборки.
Это необходимо в случаях, когда свойство объявляется retain
как Objective-C свойство или assign
свойство вместо copy
свойства. Обычно они происходят в сторонних библиотеках, которые были неправильно оптимизированы разработчиками. Как правило, или assign
NSString
свойства неверны, retain
так как NSMutableString
или производные от пользователя классы NSString
могут изменять содержимое строк без знания кода библиотеки, не нарушая приложение. Обычно это происходит из-за преждевременной оптимизации.
Ниже показаны два таких свойства:Objective-C
@property(nonatomic,retain) NSString *name;
@property(nonatomic,assign) NSString *name2;
DisposeAttribute
При применении [DisposeAttribute]
к классу необходимо указать фрагмент кода, который будет добавлен в Dispose()
реализацию метода класса.
Dispose
Так как метод автоматически создается bgen
средством, необходимо использовать [Dispose]
атрибут для внедрения кода в реализацию созданного Dispose
метода.
Например:
[BaseType (typeof (NSObject))]
[Dispose ("if (OpenConnections > 0) CloseAllConnections ();")]
interface DatabaseConnection {
}
ExportAttribute
Атрибут [Export]
используется для флага метода или свойства, предоставляемых Objective-C среде выполнения. Этот атрибут используется между средством привязки и фактическими средами выполнения Xamarin.iOS и Xamarin.Mac. Для методов параметр передается подробно в созданный код для свойств, создается метод получения и задания экспорта на основе базового объявления (см. раздел о [BindAttribute]
том, как изменить поведение средства привязки).
Синтаксис
public enum ArgumentSemantic {
None, Assign, Copy, Retain.
}
[AttributeUsage (AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Property)]
public class ExportAttribute : Attribute {
public ExportAttribute();
public ExportAttribute (string selector);
public ExportAttribute (string selector, ArgumentSemantic semantic);
public string Selector { get; set; }
public ArgumentSemantic ArgumentSemantic { get; set; }
}
Селектор представляет имя базового Objective-C метода или свойства, привязанного.
ExportAttribute.ArgumentSemantic
FieldAttribute
Этот атрибут используется для предоставления глобальной переменной C в виде поля, загруженного по запросу и доступного для кода C#. Обычно это необходимо для получения значений констант, определенных в C или Objective-C которые могут быть либо маркерами, используемыми в некоторых API, либо значения которых непрозрачны и должны использоваться как есть в пользовательском коде.
Синтаксис
public class FieldAttribute : Attribute {
public FieldAttribute (string symbolName);
public FieldAttribute (string symbolName, string libraryName);
public string SymbolName { get; set; }
public string LibraryName { get; set; }
}
Символ symbolName
C, с которым можно связаться. По умолчанию это будет загружено из библиотеки, имя которой выводится из пространства имен, в котором определен тип. Если это не библиотека, в которой отображается символ, необходимо передать libraryName
параметр. Если вы связываете статическую библиотеку, используйте __Internal
ее в качестве libraryName
параметра.
Созданные свойства всегда статически.
Свойства, помеченные атрибутом Field, могут иметь следующие типы:
NSString
NSArray
nint
/int
/long
nuint
/uint
/ulong
nfloat
/float
double
CGSize
System.IntPtr
- Перечисления
Методы установки не поддерживаются для перечислений, поддерживаемых константами NSString, но при необходимости их можно вручную привязать.
Пример:
[Static]
interface CameraEffects {
[Field ("kCameraEffectsZoomFactorKey", "CameraLibrary")]
NSString ZoomFactorKey { get; }
}
InternalAttribute
Атрибут [Internal]
может применяться к методам или свойствам, и он влияет на перетаскивание созданного кода с internal
помощью ключевого слова C#, что делает код доступным только для кода в созданной сборке. Это обычно используется для скрытия API, которые слишком низкоуровневы или предоставляют неоптимальный общедоступный API, который требуется улучшить или для API, которые не поддерживаются генератором и требуют написания кода вручную.
При разработке привязки обычно вы будете скрывать метод или свойство с помощью этого атрибута и указать другое имя метода или свойства, а затем в файле дополнительной поддержки C# вы добавите строго типизированный оболочку, которая предоставляет базовые функциональные возможности.
Например:
[Internal]
[Export ("setValue:forKey:")]
void _SetValueForKey (NSObject value, NSObject key);
[Internal]
[Export ("getValueForKey:")]
NSObject _GetValueForKey (NSObject key);
Затем в поддерживаемом файле можно получить следующий код:
public NSObject this [NSObject idx] {
get {
return _GetValueForKey (idx);
}
set {
_SetValueForKey (value, idx);
}
}
IsThreadStaticAttribute
Этот атрибут помечает поле резервного копирования для свойства, которое будет аннотировано атрибутом .NET [ThreadStatic]
. Это полезно, если поле является статической переменной потока.
МаршалNativeExceptions (Xamarin.iOS 6.0.6)
Этот атрибут создаст исключения, поддерживая собственные (Objective-C) методы.
Вместо прямого вызова objc_msgSend
вызов вызов будет проходить через пользовательскую батутную линию, которая перехватывает исключения ObjectiveC и маршалирует их в управляемые исключения.
В настоящее время поддерживаются только несколько objc_msgSend
подписей (вы узнаете, не поддерживается ли подпись при собственном связывании приложения, использующего привязку, завершается сбоем с отсутствующим символом xamarin__objc_msgSend ), но при запросе можно добавить дополнительные сведения.
NewAttribute
Этот атрибут применяется к методам и свойствам, чтобы генератор создавал new
ключевое слово перед объявлением.
Он используется для предотвращения предупреждений компилятора при появлении того же имени метода или свойства в подклассе, который уже существовал в базовом классе.
NotificationAttribute
Этот атрибут можно применить к полям, чтобы генератор создает строго типизированный вспомогательный класс Notifications.
Этот атрибут можно использовать без аргументов для уведомлений, не имеющих полезных данных, или можно указать System.Type
, что ссылается на другой интерфейс в определении API, как правило, с именем, заканчивающимся "EventArgs". Генератор преобразует интерфейс в класс, который подклассы EventArgs
и будет включать все свойства, перечисленные там. Атрибут [Export]
должен использоваться в EventArgs
классе для перечисления имени ключа, используемого для поиска Objective-C словаря, чтобы получить значение.
Например:
interface MyClass {
[Notification]
[Field ("MyClassDidStartNotification")]
NSString DidStartNotification { get; }
}
Приведенный выше код создаст вложенный класс MyClass.Notifications
со следующими методами:
public class MyClass {
[..]
public Notifications {
public static NSObject ObserveDidStart (EventHandler<NSNotificationEventArgs> handler)
public static NSObject ObserveDidStart (NSObject objectToObserve, EventHandler<NSNotificationEventArgs> handler)
}
}
Пользователи кода могут легко подписаться на уведомления, опубликованные в NSDefaultCenter , используя следующий код:
var token = MyClass.Notifications.ObserverDidStart ((notification) => {
Console.WriteLine ("Observed the 'DidStart' event!");
});
Или задать определенный объект для наблюдения. Если передать null
этот objectToObserve
метод, он будет вести себя так же, как и другой одноранговый узел.
var token = MyClass.Notifications.ObserverDidStart (objectToObserve, (notification) => {
Console.WriteLine ("Observed the 'DidStart' event on objectToObserve!");
});
Возвращаемое значение ObserveDidStart
можно использовать для простого прекращения получения уведомлений, как показано ниже.
token.Dispose ();
Или можно вызвать NSNotification.DefaultCenter.RemoveObserver и передать маркер. Если уведомление содержит параметры, необходимо указать вспомогательный EventArgs
интерфейс, как показано ниже.
interface MyClass {
[Notification (typeof (MyScreenChangedEventArgs)]
[Field ("MyClassScreenChangedNotification")]
NSString ScreenChangedNotification { get; }
}
// The helper EventArgs declaration
interface MyScreenChangedEventArgs {
[Export ("ScreenXKey")]
nint ScreenX { get; set; }
[Export ("ScreenYKey")]
nint ScreenY { get; set; }
[Export ("DidGoOffKey")]
[ProbePresence]
bool DidGoOff { get; }
}
Приведенный выше класс создает MyScreenChangedEventArgs
класс со ScreenX
свойствами, ScreenY
которые будут получать данные из словаря NSNotification.UserInfo , используя ключи ScreenXKey
, и ScreenYKey
соответственно применить соответствующие преобразования. Атрибут [ProbePresence]
используется для проверки генератора, если ключ задан в объекте UserInfo
, а не пытается извлечь значение. Это используется для случаев, когда наличие ключа является значением (обычно для логических значений).
Это позволяет писать код следующим образом:
var token = MyClass.NotificationsObserveScreenChanged ((notification) => {
Console.WriteLine ("The new screen dimensions are {0},{1}", notification.ScreenX, notification.ScreenY);
});
В некоторых случаях константы не связаны со значением, переданным в словаре. Apple иногда использует константы открытых символов и иногда использует строковые константы. По умолчанию [Export]
атрибут в предоставленном EventArgs
классе будет использовать указанное имя в качестве открытого символа для просмотра во время выполнения. Если это не так, а вместо этого предполагается, что он должен выглядеть как строковая константа, а затем передать ArgumentSemantic.Assign
значение атрибуту Export.
Новые возможности Xamarin.iOS 8.4
Иногда уведомления начинают жизнь без каких-либо аргументов, поэтому использование [Notification]
без аргументов приемлемо. Но иногда будут представлены параметры уведомления. Для поддержки этого сценария атрибут может применяться несколько раз.
Если вы разрабатываете привязку и хотите избежать нарушения существующего пользовательского кода, вы вернете существующее уведомление из:
interface MyClass {
[Notification]
[Field ("MyClassScreenChangedNotification")]
NSString ScreenChangedNotification { get; }
}
В версию, которая выводит атрибут уведомления дважды, как показано ниже:
interface MyClass {
[Notification]
[Notification (typeof (MyScreenChangedEventArgs)]
[Field ("MyClassScreenChangedNotification")]
NSString ScreenChangedNotification { get; }
}
NullAllowedAttribute
Если это применяется к свойству, оно помечает свойство как разрешение на назначение значения null
. Это допустимо только для ссылочных типов.
Если этот параметр применяется к параметру в сигнатуре метода, он указывает, что указанный параметр может иметь значение NULL и что проверка не должна выполняться для передачи null
значений.
Если у ссылочного типа нет этого атрибута, средство привязки создаст проверку на присвоенное значение перед передачей и Objective-C создаст проверку, которая вызовет исключение ArgumentNullException
, если присвоено null
значение.
Например:
// In properties
[NullAllowed]
UIImage IconFile { get; set; }
// In methods
void SetImage ([NullAllowed] UIImage image, State forState);
OverrideAttribute
Используйте этот атрибут, чтобы указать генератору привязки, что привязка для этого конкретного метода должна быть помечена ключевым словом override
.
PreSnippetAttribute
Этот атрибут можно использовать для вставки кода после проверки входных параметров, но до вызова Objective-Cкода.
Пример:
[Export ("demo")]
[PreSnippet ("var old = ViewController;")]
void Demo ();
PrologueSnippetAttribute
Этот атрибут можно использовать для вставки кода перед проверкой любого из параметров в созданном методе.
Пример:
[Export ("demo")]
[Prologue ("Trace.Entry ();")]
void Demo ();
PostGetAttribute
Указывает генератору привязки вызвать указанное свойство из этого класса, чтобы получить из него значение.
Обычно это свойство используется для обновления кэша, указывающего на ссылки на объекты, на которые ссылается граф объектов. Обычно он отображается в коде с операциями, такими как Add/Remove. Этот метод используется так, чтобы после добавления или удаления элементов внутренний кэш был обновлен, чтобы обеспечить сохранение управляемых ссылок на объекты, которые фактически используются. Это возможно, так как средство привязки создает резервное поле для всех ссылочных объектов в данной привязке.
Пример:
[BaseType (typeof (NSObject))]
public interface NSOperation {
[Export ("addDependency:")][PostGet ("Dependencies")]
void AddDependency (NSOperation op);
[Export ("removeDependency:")][PostGet ("Dependencies")]
void RemoveDependency (NSOperation op);
[Export ("dependencies")]
NSOperation [] Dependencies { get; }
}
В этом случае Dependencies
свойство будет вызываться после добавления или удаления зависимостей из NSOperation
объекта, обеспечивая наличие графа, представляющего фактически загруженные объекты, предотвращая утечку памяти, а также повреждение памяти.
PostSnippetAttribute
Этот атрибут можно использовать для вставки исходного кода C# после вызова базового Objective-C метода кода.
Пример:
[Export ("demo")]
[PostSnippet ("if (old != null) old.DemoComplete ();")]
void Demo ();
ProxyAttribute
Этот атрибут применяется к возвращаемым значениям, чтобы пометить их как прокси-объекты. Некоторые Objective-C API возвращают прокси-объекты, которые не могут отличаться от пользовательских привязок. Эффект этого атрибута заключается в том, чтобы пометить объект как DirectBinding
объект. Для сценария в Xamarin.Mac можно просмотреть обсуждение этой ошибки.
ReleaseAttribute (Xamarin.iOS 6.0)
Это можно применить к возвращаемым типам, чтобы указать, что генератор должен вызывать Release
объект перед возвратом. Это необходимо только в том случае, если метод предоставляет сохраненный объект (в отличие от автоматического запуска объекта, который является наиболее распространенным сценарием).
Пример:
[Export ("getAndRetainObject")]
[return: Release ()]
NSObject GetAndRetainObject ();
Кроме того, этот атрибут распространяется на созданный код, чтобы среда выполнения Xamarin.iOS знала, что он должен хранить объект после возвращения Objective-C из такой функции.
SealedAttribute
Указывает генератору пометить созданный метод как запечатанный. Если этот атрибут не указан, по умолчанию создается виртуальный метод (либо виртуальный метод, абстрактный метод, либо переопределение в зависимости от того, как используются другие атрибуты).
StaticAttribute
[Static]
При применении атрибута к методу или свойству создается статический метод или свойство. Если этот атрибут не указан, генератор создает метод экземпляра или свойство.
TransientAttribute
Используйте этот атрибут для флага свойств, значения которых являются временными, то есть объекты, которые временно создаются iOS, но не являются длительными. Если этот атрибут применяется к свойству, генератор не создает резервное поле для этого свойства, что означает, что управляемый класс не сохраняет ссылку на объект.
WrapAttribute
В конструкторе привязок [Wrap]
Xamarin.iOS/Xamarin.Mac атрибут используется для упаковки слабо типизированного объекта с строго типизированным объектом. Это происходит в основном с Objective-C объектами делегатов, которые обычно объявляются как тип id
или NSObject
. Соглашение, используемое Xamarin.iOS и Xamarin.Mac, заключается в том, чтобы предоставлять эти делегаты или источники данных как тип NSObject
и называться с помощью соглашения "Слабый" + имя, которое предоставляется. Свойство id delegate
из Objective-C этого объекта будет предоставляться в виде NSObject WeakDelegate { get; set; }
свойства в файле контракта API.
Но, как правило, значение, назначенное этому делегату, имеет сильный тип, поэтому мы применяем сильный тип и применяем [Wrap]
атрибут, это означает, что пользователи могут использовать слабые типы, если им нужен тонкий контроль или если им нужно прибегнуть к низкоуровневым трюкам, или они могут использовать строго типизированное свойство для большей части своей работы.
Пример:
[BaseType (typeof (NSObject))]
interface Demo {
[Export ("delegate"), NullAllowed]
NSObject WeakDelegate { get; set; }
[Wrap ("WeakDelegate")]
DemoDelegate Delegate { get; set; }
}
[BaseType (typeof (NSObject))]
[Model][Protocol]
interface DemoDelegate {
[Export ("doDemo")]
void DoDemo ();
}
Вот как пользователь будет использовать слабо типизированные версии делегата:
// The weak case, user has to roll his own
class SomeObject : NSObject {
[Export ("doDemo")]
void CallbackForDoDemo () {}
}
var demo = new Demo ();
demo.WeakDelegate = new SomeObject ();
И вот как пользователь будет использовать строго типизированную версию, обратите внимание, что пользователь использует систему типов C#и использует ключевое слово переопределения для объявления намерения и не требуется вручную декорировать метод, [Export]
так как мы работали в привязке для пользователя:
// This is the strong case,
class MyDelegate : DemoDelegate {
override void Demo DoDemo () {}
}
var strongDemo = new Demo ();
demo.Delegate = new MyDelegate ();
Другим способом использования атрибута [Wrap]
является поддержка строго типизированной версии методов. Например:
[BaseType (typeof (NSObject))]
interface XyzPanel {
[Export ("playback:withOptions:")]
void Playback (string fileName, [NullAllowed] NSDictionary options);
[Wrap ("Playback (fileName, options?.Dictionary")]
void Playback (string fileName, XyzOptions options);
}
[Wrap]
Если атрибут применяется к методу внутри типа, украшенного [Category]
атрибутом, необходимо включить This
в качестве первого аргумента, так как создается метод расширения. Например:
[Wrap ("Write (This, image, options?.Dictionary, out error)")]
bool Write (CIImage image, CIImageRepresentationOptions options, out NSError error);
Элементы, созданные [Wrap]
не virtual
по умолчанию, если вам нужен virtual
элемент, можно задать необязательный isVirtual
true
параметр.
[BaseType (typeof (NSObject))]
interface FooExplorer {
[Export ("fooWithContentsOfURL:")]
void FromUrl (NSUrl url);
[Wrap ("FromUrl (NSUrl.FromString (url))", isVirtual: true)]
void FromUrl (string url);
}
[Wrap]
также можно использовать непосредственно в методах получения свойств и методах задания.
Это позволяет иметь полный контроль над ними и настраивать код по мере необходимости.
Например, рассмотрим следующее определение API, использующее интеллектуальные перечисления:
// Smart enum.
enum PersonRelationship {
[Field (null)]
None,
[Field ("FMFather", "__Internal")]
Father,
[Field ("FMMother", "__Internal")]
Mother
}
Определение интерфейса:
// Property definition.
[Export ("presenceType")]
NSString _PresenceType { get; set; }
PersonRelationship PresenceType {
[Wrap ("PersonRelationshipExtensions.GetValue (_PresenceType)")]
get;
[Wrap ("_PresenceType = value.GetConstant ()")]
set;
}
Атрибуты параметра
В этом разделе описываются атрибуты, которые можно применять к параметрам в определении метода, а также [NullAttribute]
к свойству в целом.
BlockCallback
Этот атрибут применяется к типам параметров в объявлениях делегатов C#, чтобы уведомить привязщика о том, что параметр в вопросе соответствует Objective-C соглашению о вызове блоков и должен маршалировать его таким образом.
Обычно это используется для обратных вызовов, определенных следующим образом:Objective-C
typedef returnType (^SomeTypeDefinition) (int parameter1, NSString *parameter2);
См. также: CCallback.
CCallback
Этот атрибут применяется к типам параметров в объявлениях делегатов C#, чтобы уведомить привязщика о том, что параметр в вопросе соответствует соглашению о вызове функции C ABI и должен маршалировать его таким образом.
Обычно это используется для обратных вызовов, определенных следующим образом:Objective-C
typedef returnType (*SomeTypeDefinition) (int parameter1, NSString *parameter2);
См. также: BlockCallback.
Параметры
Атрибут можно использовать [Params]
в последнем параметре массива определения метода, чтобы генератор ввел в определение "params". Это позволяет привязке легко разрешать необязательные параметры.
Например, следующее определение:
[Export ("loadFiles:")]
void LoadFiles ([Params]NSUrl [] files);
Позволяет записывать следующий код:
foo.LoadFiles (new NSUrl (url));
foo.LoadFiles (new NSUrl (url1), new NSUrl (url2), new NSUrl (url3));
Это имеет дополнительное преимущество, которое не требует, чтобы пользователи создавали массив исключительно для передачи элементов.
PlainString
Атрибут можно использовать [PlainString]
перед строковыми параметрами, чтобы указать генератору привязки передать строку в виде строки C, а не передавать его в качестве параметра NSString
.
Большинство Objective-C API используют NSString
параметры, но несколько API предоставляют char *
API для передачи строк вместо NSString
варианта.
Используйте [PlainString]
в этих случаях.
Например, следующие Objective-C объявления:
- (void) setText: (NSString *) theText;
- (void) logMessage: (char *) message;
Должен быть привязан следующим образом:
[Export ("setText:")]
void SetText (string theText);
[Export ("logMessage:")]
void LogMessage ([PlainString] string theText);
СохранитьAttribute
Указывает генератору сохранить ссылку на указанный параметр. Генератор предоставит резервное хранилище для этого поля или укажите имя (the WrapName
) для хранения значения. Это полезно для хранения ссылки на управляемый объект, передаваемый в качестве параметра Objective-C , и когда вы знаете, что Objective-C будет хранить только эту копию объекта. Например, API, например SetDisplay (SomeObject)
, будет использовать этот атрибут, так как, скорее всего, SetDisplay может отображать только один объект за раз. Если необходимо отслеживать несколько объектов (например, для API stack-like), вы будете использовать [RetainList]
атрибут.
Синтаксис
public class RetainAttribute {
public RetainAttribute ();
public RetainAttribute (string wrapName);
public string WrapName { get; }
}
TransientAttribute
Этот атрибут применяется к параметрам и используется только при переходе с Objective-C C#. Во время этих переходов различные Objective-CNSObject
параметры упаковываются в управляемое представление объекта.
Среда выполнения будет принимать ссылку на собственный объект и сохранять ссылку до тех пор, пока не будет удалена последняя управляемая ссылка на объект, и GC имеет возможность запуститься.
В некоторых случаях важно, чтобы среда выполнения C# не сохраняла ссылку на собственный объект. Иногда это происходит, когда базовый машинный код привязывает специальное поведение к жизненному циклу параметра. Например, деструктор для параметра выполнит некоторые действия очистки или удаляет драгоценный ресурс.
Этот атрибут сообщает среде выполнения, что требуется, чтобы объект был удален, если это возможно, при возврате обратно Objective-C из метода перезаписи.
Правило простое: если среде выполнения пришлось создать новое управляемое представление из собственного объекта, то в конце функции будет удалено количество хранения для собственного объекта, а свойство Handle управляемого объекта будет удалено. Это означает, что если вы сохранили ссылку на управляемый объект, эта ссылка станет бесполезной (вызов методов в ней вызовет исключение).
Если переданный объект не был создан, или если уже было выдающееся управляемое представление объекта, принудительное удаление не происходит.
Атрибуты свойства
NotImplementedAttribute
Этот атрибут используется для поддержки Objective-C идиома, в котором свойство с методом getter представлено в базовом классе, а подкласс мутируемый вводит метод задания.
Так как C# не поддерживает эту модель, базовый класс должен иметь как метод задания, так и метод получения, а подкласс может использовать OverrideAttribute.
Этот атрибут используется только в наборах свойств и используется для поддержки мутируемой идиомы.Objective-C
Пример:
[BaseType (typeof (NSObject))]
interface MyString {
[Export ("initWithValue:")]
IntPtr Constructor (string value);
[Export ("value")]
string Value {
get;
[NotImplemented ("Not available on MyString, use MyMutableString to set")]
set;
}
}
[BaseType (typeof (MyString))]
interface MyMutableString {
[Export ("value")]
[Override]
string Value { get; set; }
}
Атрибуты перечисления
Сопоставление NSString
констант с значениями перечисления — это простой способ создания лучшего API .NET. Оно делает следующее.
- позволяет использовать завершение кода, показывая только правильные значения для API;
- добавляет безопасность типов, нельзя использовать другую
NSString
константу в неправильном контексте; и - позволяет скрыть некоторые константы, что делает завершение кода более коротким списком API без потери функциональности.
Пример:
enum NSRunLoopMode {
[DefaultEnumValue]
[Field ("NSDefaultRunLoopMode")]
Default,
[Field ("NSRunLoopCommonModes")]
Common,
[Field (null)]
Other = 1000
}
В приведенном выше определении привязки генератор создаст enum
сам себя, а также создаст статический *Extensions
тип, включающий методы преобразования двух способов между значениями перечисления и NSString
константами. Это означает, что константы остаются доступными разработчикам, даже если они не являются частью API.
Примеры:
// using the NSString constant in a different API / framework / 3rd party code
CallApiRequiringAnNSString (NSRunLoopMode.Default.GetConstant ());
// converting the constants from a different API / framework / 3rd party code
var constant = CallApiReturningAnNSString ();
// back into an enum value
CallApiWithEnum (NSRunLoopModeExtensions.GetValue (constant));
DefaultEnumValueAttribute
Вы можете украсить одно значение перечисления с помощью этого атрибута. Это станет константой, возвращаемой, если значение перечисления не известно.
В приведенном выше примере:
var x = (NSRunLoopMode) 99;
Call (x.GetConstant ()); // NSDefaultRunLoopMode will be used
Если значение перечисления не украшено, NotSupportedException
создается исключение.
ErrorDomainAttribute
Коды ошибок привязаны как значения перечисления. Обычно для них существует домен ошибок, и это не всегда легко найти, какой из них применяется (или если он даже существует).
Этот атрибут можно использовать для связывания домена ошибки с самой перечислением.
Пример:
[Native]
[ErrorDomain ("AVKitErrorDomain")]
public enum AVKitError : nint {
None = 0,
Unknown = -1000,
PictureInPictureStartFailed = -1001
}
Затем можно вызвать метод GetDomain
расширения, чтобы получить константу домена любой ошибки.
FieldAttribute
Это тот же [Field]
атрибут, используемый для констант внутри типа. Его также можно использовать внутри перечисления для сопоставления значения с определенной константой.
null
Значение можно использовать для указания значения перечисления, которое должно быть возвращено, если задана null
NSString
константа.
В приведенном выше примере:
var constant = NSRunLoopMode.NewInWatchOS3; // will be null in watchOS 2.x
Call (NSRunLoopModeExtensions.GetValue (constant)); // will return 1000
Если значение отсутствует null
, ArgumentNullException
создается исключение.
Глобальные атрибуты
Глобальные атрибуты применяются с помощью [assembly:]
модификатора атрибутов, например [LinkWithAttribute]
атрибутов, например атрибутов доступности.
LinkWithAttribute
Это атрибут уровня сборки, позволяющий разработчикам указывать флаги связывания, необходимые для повторного использования привязанной библиотеки, не заставляя потребителя библиотеки вручную настраивать gcc_flags и дополнительные аргументы mtouch, передаваемые библиотеке.
Синтаксис
// In properties
[Flags]
public enum LinkTarget {
Simulator = 1,
ArmV6 = 2,
ArmV7 = 4,
Thumb = 8,
}
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple=true)]
public class LinkWithAttribute : Attribute {
public LinkWithAttribute ();
public LinkWithAttribute (string libraryName);
public LinkWithAttribute (string libraryName, LinkTarget target);
public LinkWithAttribute (string libraryName, LinkTarget target, string linkerFlags);
public bool ForceLoad { get; set; }
public string Frameworks { get; set; }
public bool IsCxx { get; set; }
public string LibraryName { get; }
public string LinkerFlags { get; set; }
public LinkTarget LinkTarget { get; set; }
public bool NeedsGccExceptionHandling { get; set; }
public bool SmartLink { get; set; }
public string WeakFrameworks { get; set; }
}
Этот атрибут применяется на уровне сборки, например, это то, что используют привязки CorePlot:
[assembly: LinkWith ("libCorePlot-CocoaTouch.a", LinkTarget.ArmV7 | LinkTarget.ArmV7s | LinkTarget.Simulator, Frameworks = "CoreGraphics QuartzCore", ForceLoad = true)]
При использовании [LinkWith]
атрибута указанный объект libraryName
внедряется в результирующую сборку, позволяя пользователям отправлять одну библиотеку DLL, содержащую неуправляемые зависимости, а также флаги командной строки, необходимые для правильного использования библиотеки из Xamarin.iOS.
libraryName
В этом случае LinkWith
атрибут можно использовать только для указания дополнительных флагов компоновщика:
[assembly: LinkWith (LinkerFlags = "-lsqlite3")]
Конструкторы LinkWithAttribute
Эти конструкторы позволяют указать библиотеку для связывания с результирующей сборкой и внедрения в нее поддерживаемых целевых объектов, поддерживаемых библиотекой и любых необязательных флагов библиотеки, необходимых для связывания с библиотекой.
Обратите внимание, что LinkTarget
аргумент выводится Xamarin.iOS и не требуется задавать.
Примеры:
// Specify additional linker:
[assembly: LinkWith (LinkerFlags = "-sqlite3")]
// Specify library name for the constructor:
[assembly: LinkWith ("libDemo.a");
// Specify library name, and link target for the constructor:
[assembly: LinkWith ("libDemo.a", LinkTarget.Thumb | LinkTarget.Simulator);
// Specify only the library name, link target and linker flags for the constructor:
[assembly: LinkWith ("libDemo.a", LinkTarget.Thumb | LinkTarget.Simulator, SmartLink = true, ForceLoad = true, IsCxx = true);
LinkWithAttribute.ForceLoad
Свойство ForceLoad
используется для определения того, используется ли -force_load
флаг ссылки для связывания собственной библиотеки. На данный момент это всегда должно быть верно.
LinkWithAttribute.Frameworks
Если привязанная библиотека имеет жесткое требование для любой платформы (кроме Foundation
и UIKit
), необходимо задать Frameworks
для свойства строку, содержащую список необходимых платформ с разделителями пространства. Например, если вы привязывают библиотеку, которая требуется CoreGraphics
, и CoreText
присвойте свойству Frameworks
значение "CoreGraphics CoreText"
.
LinkWithAttribute.IsCxx
Задайте для этого свойства значение true, если результирующий исполняемый файл необходимо скомпилировать с помощью компилятора C++, а не по умолчанию, который является компилятором C. Используйте это, если библиотека, которую вы являетесь привязкой, была написана на языке C++.
LinkWithAttribute.LibraryName
Имя неуправляемой библиотеки для пакета. Это файл с расширением .a" и может содержать код объекта для нескольких платформ (например, ARM и x86 для симулятора).
Более ранние версии Xamarin.iOS проверили LinkTarget
свойство, чтобы определить поддерживаемую платформу, но теперь она обнаружена автоматически, и LinkTarget
свойство игнорируется.
LinkWithAttribute.LinkerFlags
Строка LinkerFlags
позволяет авторам привязки указывать все дополнительные флаги компоновщика, необходимые при связывании собственной библиотеки с приложением.
Например, если для собственной библиотеки требуется libxml2 и zlib, необходимо задать LinkerFlags
для "-lxml2 -lz"
строки значение .
LinkWithAttribute.LinkTarget
Более ранние версии Xamarin.iOS проверили LinkTarget
свойство, чтобы определить поддерживаемую платформу, но теперь она обнаружена автоматически, и LinkTarget
свойство игнорируется.
LinkWithAttribute.NeedsGccExceptionHandling
Задайте для этого свойства значение true, если для связывания библиотеки требуется библиотека обработки исключений GCC (gcc_eh)
LinkWithAttribute.SmartLink
Свойство SmartLink
должно иметь значение true, чтобы разрешить Xamarin.iOS определить, является ли ForceLoad
это обязательным или нет.
LinkWithAttribute.WeakFrameworks
Свойство WeakFrameworks
работает так же, как Frameworks
свойство, за исключением того, -weak_framework
что в режиме связи описатель передается в gcc для каждой из перечисленных платформ.
WeakFrameworks
позволяет библиотекам и приложениям слабо связываться с платформами, чтобы они могли при необходимости использовать их, если они доступны, но не принимают жесткой зависимости от них, что полезно, если библиотека предназначена для добавления дополнительных функций в более новых версиях iOS. Дополнительные сведения о слабом связывании см. в документации Apple по слабым связываниям.
Хорошие кандидаты для слабой компоновки будут Frameworks
такими как Accounts, CoreBluetooth
, CoreImage
, GLKit
NewsstandKit
и Twitter
так как они доступны только в iOS 5.
СоветAttribute
Используйте этот атрибут, чтобы дать разработчикам указание о других API, которые могут быть удобнее для них использовать. Например, если вы предоставляете строго типизированную версию API, этот атрибут можно использовать для слабо типизированного атрибута, чтобы направить разработчика к лучшему API.
Сведения из этого атрибута отображаются в документации и средствах для предоставления пользовательских предложений по улучшению
ТребуетСяSuperAttribute
Это специализированный подкласс атрибута[Advice]
, который можно использовать для указания разработчику, что переопределение метода требует вызова базового (переопределенного) метода.
Это соответствует clang
__attribute__((objc_requires_super))
ZeroCopyStringsAttribute
Доступна только в Xamarin.iOS 5.4 и более поздней версии.
Этот атрибут указывает генератору, что привязка для данной конкретной библиотеки (при применении к [assembly:]
) или типу должна использовать быстрый маршалинг строк нулевого копирования. Этот атрибут эквивалентен передаче параметра --zero-copy
командной строки генератору.
При использовании нулевого копирования для строк генератор фактически использует ту же строку C#, что и строка Objective-C , которая используется без создания нового NSString
объекта и избегая копирования данных из строк C# в Objective-C строку. Единственным недостатком использования строк нулевого копирования является то, что необходимо убедиться, что любое строковое свойство, которое выполняется в оболочке, которое будет помечено как retain
или copy
имеет [DisableZeroCopy]
набор атрибутов. Это требуется, так как дескриптор для строк нулевого копирования выделяется в стеке и является недопустимым при возврате функции.
Пример:
[ZeroCopyStrings]
[BaseType (typeof (NSObject))]
interface MyBinding {
[Export ("name")]
string Name { get; set; }
[Export ("domain"), NullAllowed]
string Domain { get; set; }
[DisablZeroCopy]
[Export ("someRetainedNSString")]
string RetainedProperty { get; set; }
}
Вы также можете применить атрибут на уровне сборки, и он будет применяться ко всем типам сборки:
[assembly:ZeroCopyStrings]
Строго типизированные словари
С помощью Xamarin.iOS 8.0 мы ввели поддержку легкого создания строго типизированных классов, которые обтекают NSDictionaries
.
Хотя всегда можно было использовать тип данных DictionaryContainer вместе с ручным API, это гораздо проще сделать. Дополнительные сведения см. в разделе "Строгое отображение типов".
StrongDictionary
При применении этого атрибута к интерфейсу генератор создает класс с тем же именем, что и интерфейс, производный от DictionaryContainer , и преобразует каждое свойство, определенное в интерфейсе, в строго типизированный метод получения и задание словаря.
Это автоматически создает класс, который можно создать из существующего NSDictionary
или созданного.
Этот атрибут принимает один параметр, имя класса, содержащего ключи, используемые для доступа к элементам словаря. По умолчанию каждое свойство в интерфейсе с атрибутом будет искать член в указанном типе для имени с суффиксом "Ключ".
Например:
[StrongDictionary ("MyOptionKeys")]
interface MyOption {
string Name { get; set; }
nint Age { get; set; }
}
[Static]
interface MyOptionKeys {
// In Objective-C this is "NSString *MYOptionNameKey;"
[Field ("MYOptionNameKey")]
NSString NameKey { get; }
// In Objective-C this is "NSString *MYOptionAgeKey;"
[Field ("MYOptionAgeKey")]
NSString AgeKey { get; }
}
В приведенном выше случае MyOption
класс создаст строковое свойство, для Name
которого будет использоваться MyOptionKeys.NameKey
ключ в словаре для получения строки. И будет использовать MyOptionKeys.AgeKey
в качестве ключа в словаре, чтобы получить объект NSNumber
, содержащий int.
Если вы хотите использовать другой ключ, можно использовать атрибут экспорта для свойства, например:
[StrongDictionary ("MyColoringKeys")]
interface MyColoringOptions {
[Export ("TheName")] // Override the default which would be NameKey
string Name { get; set; }
[Export ("TheAge")] // Override the default which would be AgeKey
nint Age { get; set; }
}
[Static]
interface MyColoringKeys {
// In Objective-C this is "NSString *MYColoringNameKey"
[Field ("MYColoringNameKey")]
NSString TheName { get; }
// In Objective-C this is "NSString *MYColoringAgeKey"
[Field ("MYColoringAgeKey")]
NSString TheAge { get; }
}
Типы надежных словарей
В определении StrongDictionary
поддерживаются следующие типы данных:
Тип интерфейса C# | NSDictionary Тип хранилища |
---|---|
bool |
Boolean хранящийся в объекте NSNumber |
Значения перечисления | целое число, хранящееся в NSNumber |
int |
32-разрядное целое число, хранящееся в NSNumber |
uint |
32-разрядное целое число без знака, хранящееся в NSNumber |
nint |
NSInteger хранящийся в объекте NSNumber |
nuint |
NSUInteger хранящийся в объекте NSNumber |
long |
64-разрядное целое число, хранящееся в NSNumber |
float |
32-разрядное целое число, хранящееся в качестве целого числа NSNumber |
double |
64-разрядное целое число, хранящееся в качестве целого числа NSNumber |
NSObject и подклассы |
NSObject |
NSDictionary |
NSDictionary |
string |
NSString |
NSString |
NSString |
C# Array NSObject |
NSArray |
C# Array перечислений |
NSArray NSNumber содержащие значения |