Ескертпе
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Жүйеге кіруді немесе каталогтарды өзгертуді байқап көруге болады.
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Каталогтарды өзгертуді байқап көруге болады.
Язык Objective-C основан на селекторах. Селектор — это сообщение, которое можно отправить в объект или класс. Xamarin.iOS сопоставляет селекторы экземпляров с методами экземпляра и селекторами классов со статическими методами.
В отличие от обычных функций C (и таких как функции-члены C++), вы не можете напрямую вызвать селектор с помощью P/Invoke Вместо этого, селекторы отправляются в Objective-C класс или экземпляр с помощью функции objc_msgSend Функции.
Дополнительные сведения о сообщениях Objective-Cсм. в руководстве apple по работе с объектами .
Пример
Предположим, вы хотите вызвать sizeWithFont:forWidth:lineBreakMode: селектор в NSString.
Объявление (из документации Apple) — это:
- (CGSize)sizeWithFont:(UIFont *)font forWidth:(CGFloat)width lineBreakMode:(UILineBreakMode)lineBreakMode
Этот API имеет следующие характеристики:
- Тип возвращаемого значения предназначен
CGSizeдля единого API. - Параметр
font— это UIFont (и тип (косвенно), производный от NSObject, и сопоставляется с System.IntPtr. - Параметр
width, aCGFloat, сопоставляется сnfloat. - Параметр
lineBreakMode, aUILineBreakMode, уже был привязан в Xamarin.iOS в качествеUILineBreakModeПеречисления.
Сложив все вместе, objc_msgSend объявление должно соответствовать:
CGSize objc_msgSend(
IntPtr target,
IntPtr selector,
IntPtr font,
nfloat width,
UILineBreakMode mode
);
Объявите его следующим образом:
[DllImport (Constants.ObjectiveCLibrary, EntryPoint="objc_msgSend")]
static extern CGSize cgsize_objc_msgSend_IntPtr_float_int (
IntPtr target,
IntPtr selector,
IntPtr font,
nfloat width,
UILineBreakMode mode
);
Чтобы вызвать этот метод, используйте следующий код:
NSString target = ...
Selector selector = new Selector ("sizeWithFont:forWidth:lineBreakMode:");
UIFont font = ...
nfloat width = ...
UILineBreakMode mode = ...
CGSize size = cgsize_objc_msgSend_IntPtr_float_int(
target.Handle,
selector.Handle,
font == null ? IntPtr.Zero : font.Handle,
width,
mode
);
Если возвращаемое значение было структурой, размер которой меньше 8 байт (например, более старый SizeF , используемый перед переходом на объединенные API), приведенный выше код будет выполняться на симуляторе, но произошел сбой на устройстве. Чтобы вызвать селектор, возвращающий значение меньше 8 бит в размере, объявите функцию objc_msgSend_stret :
[DllImport (MonoTouch.Constants.ObjectiveCLibrary, EntryPoint="objc_msgSend_stret")]
static extern void cgsize_objc_msgSend_stret_IntPtr_float_int (
out CGSize retval,
IntPtr target,
IntPtr selector,
IntPtr font,
nfloat width,
UILineBreakMode mode
);
Чтобы вызвать этот метод, используйте следующий код:
NSString target = ...
Selector selector = new Selector ("sizeWithFont:forWidth:lineBreakMode:");
UIFont font = ...
nfloat width = ...
UILineBreakMode mode = ...
CGSize size;
if (Runtime.Arch == Arch.SIMULATOR)
size = cgsize_objc_msgSend_IntPtr_float_int(
target.Handle,
selector.Handle,
font == null ? IntPtr.Zero : font.Handle,
width,
mode
);
else
cgsize_objc_msgSend_stret_IntPtr_float_int(
out size,
target.Handle, selector.Handle,
font == null ? IntPtr.Zero: font.Handle,
width,
mode
);
Вызов селектора
Вызов селектора состоит из трех шагов:
- Получите целевой объект селектора.
- Получите имя селектора.
- Вызов
objc_msgSendс соответствующими аргументами.
Целевые объекты селектора
Целевой объект селектора — это экземпляр объекта или Objective-C класс. Если целевой объект является экземпляром и получен из привязанного типа Xamarin.iOS, используйте ObjCRuntime.INativeObject.Handle это свойство.
Если целевой объект является классом, используйте ObjCRuntime.Class для получения ссылки на экземпляр класса, а затем используйте Class.Handle это свойство.
Имена селекторов
Имена селекторов перечислены в документации Apple. Например, NSString включает sizeWithFont: и sizeWithFont:forWidth:lineBreakMode: селекторы. Внедренные и конечные двоеточия являются частью имени селектора и не могут быть опущены.
Получив имя селектора, можно создать ObjCRuntime.Selector для него экземпляр.
Вызов objc_msgSend
objc_msgSend отправляет сообщение (селектор) в объект. Это семейство функций принимает по крайней мере два обязательных аргумента: целевой объект селектора (дескриптор экземпляра или класса), сам селектор и все аргументы, необходимые для селектора. Аргументы экземпляра и селектора должны быть System.IntPtr, и все остальные аргументы должны соответствовать типу, который ожидает селектор, например nint для intселектора или System.IntPtr для всех NSObjectпроизводных типов. Используйте NSObject.Handle свойство для получения IntPtr экземпляра Objective-C типа.
Существует несколько objc_msgSend функций:
- Используется
objc_msgSend_stretдля селекторов, возвращающих структуру. В ARM сюда входят все типы возвращаемых данных, которые не являются перечислением или любым из встроенных типов C (char, ,short,longint,float).doubleВ x86 (симуляторе) этот метод необходимо использовать для всех структур размером более 8 байт (CGSize8 байтов и не используетсяobjc_msgSend_stretв симуляторе). - Используйте
objc_msgSend_fpretдля селекторов, возвращающих значение с плавающей запятой только в x86. Эта функция не требуется использовать в ARM; вместо этого используйтеobjc_msgSend. - Основная функция objc_msgSend используется для всех остальных селекторов.
Когда вы решите, какие objc_msgSend функции необходимо вызвать (симулятор и устройство могут требовать другой метод), можно использовать обычный [DllImport] метод для объявления функции для последующего вызова.
Набор готовых objc_msgSend объявлений можно найти в ObjCRuntime.Messaging.
Различные вызовы на симуляторе и устройстве
Как описано выше, Objective-C имеет три типа objc_msgSend методов: один для регулярных вызовов, один для вызовов, возвращающих значения с плавающей запятой (только x86), и один для вызовов, возвращающих значения структуры. Последний включает суффикс _stret в ObjCRuntime.Messaging.
При вызове метода, возвращающего определенные структуры (правила, описанные ниже), необходимо вызвать метод с возвращаемым значением в качестве первого параметра в качестве out значения:
// The following returns a PointF structure:
PointF ret;
Messaging.PointF_objc_msgSend_stret_PointF_IntPtr (out ret, this.Handle, selConvertPointFromWindow.Handle, point, window.Handle);
Правило, когда использовать _stret_ метод отличается от x86 и ARM.
Если вы хотите, чтобы привязки работали как на симуляторе, так и на устройстве, добавьте код, например следующий:
if (Runtime.Arch == Arch.DEVICE)
{
PointF ret;
Messaging.PointF_objc_msgSend_stret_PointF_IntPtr (out ret, myHandle, selector.Handle);
return ret;
}
else
{
return Messaging.PointF_objc_msgSend_PointF_IntPtr (myHandle, selector.Handle);
}
Использование метода objc_msgSend_stret
При построении для ARM используйте objc_msgSend_stretдля любого типа значения, который не является перечислением или любым из базовых типов для перечисления (int, , byte, shortlong, ). floatdouble
При сборке для x86 используйте objc_msgSend_stretдля любого типа значения, который не является перечислением или любым из базовых типов для перечисления (int, , byte, shortlong, double) floatи собственный размер которого превышает 8 байт.
Создание собственных подписей
При необходимости можно использовать следующий gist для создания собственных подписей.