- 07/12/2017
- 4 perc olvasni
-
-
d
-
d
-
c
-
a
-
az Objective-C nyelv a szelektorokon alapul. A választó amessage, amelyet el lehet küldeni egy objektumnak vagy egy osztálynak. Xamarin.az iOS leképezi a példányválasztókat a példánymódszerekre, az osztályválasztókat pedig a statikus módszerekre.
a normál C függvényektől eltérően (és a C++ tagfüggvényekhez hasonlóan) nem lehet közvetlenül meghívni egy választótp/meghívás ehelyett a választókat egy Objective-C osztályba vagy példányba küldi aobjc_msgSend
függvény használatával.
az Objective-C üzenetekkel kapcsolatos további információkért tekintse meg az Apple objectsguide-ot.
példa
tegyük fel, hogy meg akarja hívni asizeWithFont:forWidth:lineBreakMode:
választót NSString
.A nyilatkozat (Az Apple dokumentációjából):
- (CGSize)sizeWithFont:(UIFont *)font forWidth:(CGFloat)width lineBreakMode:(UILineBreakMode)lineBreakMode
ez az API a következő jellemzőkkel rendelkezik:
- a visszatérési típus
CGSize
az egységes API esetében. - a
font
paraméter egy Uifont (és egy Típus (közvetetten) az NSObject-ből származik, és a rendszerhez van hozzárendelve.IntPtr. - a
width
paraméter, aCGFloat
,nfloat
– re van leképezve. - a
lineBreakMode
paraméter, aUILineBreakMode
, már kötött a Xamarin.iOS, mint aUILineBreakMode
felsorolás.
mindent összevetve, a objc_msgSend
nyilatkozatnak meg kell egyeznie:
CGSize objc_msgSend( IntPtr target, IntPtr selector, IntPtr font, nfloat width, UILineBreakMode mode);
állapítsa meg a következőképpen:
static extern CGSize cgsize_objc_msgSend_IntPtr_float_int ( IntPtr target, IntPtr selector, IntPtr font, nfloat width, UILineBreakMode mode);
a módszer meghívásához használja a következő kódot:
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);
ha a visszaadott érték 8 bájtnál kisebb méretű struktúra lett volna (mint a régebbi SizeF
, amelyet az egységes API-kra való váltás előtt használtak), a fenti kód a szimulátoron futott volna, de összeomlott az eszközön. Ha olyan választót szeretne meghívni, amely 8 bitnél kisebb értéket ad vissza, deklarálja a objc_msgSend_stret
függvényt:
static extern void cgsize_objc_msgSend_stret_IntPtr_float_int ( out CGSize retval, IntPtr target, IntPtr selector, IntPtr font, nfloat width, UILineBreakMode mode);
a módszer meghívásához használja a következő kódot:
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 );
a választó meghívása
a választó meghívása három lépésből áll:
- Szerezd meg a választó célt.
- Szerezd meg a választó nevét.
- hívja a
objc_msgSend
– et a megfelelő argumentumokkal.
választó célok
a választó cél vagy objektumpéldány, vagy Objective-C osztály. Ha a cél egy példány, és egy kötött Xamarinból származik.iOS Típus, használja a ObjCRuntime.INativeObject.Handle
tulajdonságot.
ha a cél egy osztály, használja a ObjCRuntime.Class
hivatkozást a classinstance-re, majd használja a Class.Handle
tulajdonságot.
Választónevek
a Választóneveket az Apple dokumentációja tartalmazza. Például a NSString
magában foglalja a sizeWithFont:
és a sizeWithFont:forWidth:lineBreakMode:
választókat. A beágyazott és záró kettőspontok a választó nevének részét képezik, és nem hagyhatók el.
ha megvan a választó neve, létrehozhat egy ObjCRuntime.Selector
példányt.
Objc_msgsend hívása
objc_msgSend
üzenetet (választót) küld egy objektumnak. Ez a család offfunkciók vesz legalább két szükséges érvek: a választó cél (aninstance vagy osztály fogantyú), a választó maga, és minden argumentsrequired a választó. A példány és a választó argumentumainakSystem.IntPtr
– nek kell lenniük, és az összes fennmaradó argumentumnak meg kell egyeznie a theselector által elvárt típussal, például egy nint
egy int
-ra, vagy egySystem.IntPtr
az összes NSObject
– ből származó típusra. A NSObject.Handle
tulajdonsággal IntPtr
értéket kaphat egy Objective-C típusú példányhoz.
egynél több objc_msgSend
funkció van:
- használja a
objc_msgSend_stret
– et olyan szelektorokhoz, amelyek visszaadják a struct-ot. Az ARM, ez magában foglalja az összes returntypes, amelyek nem egy felsorolás vagy a C beépített típusok (char
,short
,int
,long
,float
,double
). Az x86-on (a szimulátoron) ezt a módszert kell használni minden 8 bájtnál nagyobb méretű struktúrához (aCGSize
8 bájt, és nem használja aobjc_msgSend_stret
– et a szimulátorban). - használja a
objc_msgSend_fpret
értéket olyan választókhoz, amelyek lebegőpontos értéket adnak vissza csak x86-on. Ezt a funkciót nem kell használni az ARM-en; ehelyett használjaobjc_msgSend
. - a mainobjc_msgSendfunction minden más választóhoz használható.
miután eldöntötte, hogy melyik objc_msgSend
függvényt(függvényeket) kell hívnia(a szimulátorhoz és az eszközhöz eltérő módszerre lehet szükség), használhatja a normál módszert a függvény későbbi meghíváshoz történő deklarálásához.
az előre elkészített objc_msgSend
deklarációk halmaza megtalálható aObjCRuntime.Messaging
-ben.
különböző invokációk a szimulátoron és az eszközön
a fent leírtak szerint az Objective-C háromféle objc_msgSend
módszert tartalmaz: az egyik a rendszeres invokációkhoz, az egyik a visszatérő pontértékekhez (csak x86), a másik pedig a returnstruct értékekhez. Ez utóbbi tartalmazza a _stret
utótagotObjCRuntime.Messaging
– ben.
ha olyan metódust hív meg, amely bizonyos struktúrákat (az alábbiakban ismertetett szabályokat) ad vissza, akkor a metódust kell meghívnia, amelynek visszatérési értéke az elsőparaméter out
értékként:
// The following returns a PointF structure:PointF ret;Messaging.PointF_objc_msgSend_stret_PointF_IntPtr (out ret, this.Handle, selConvertPointFromWindow.Handle, point, window.Handle);
a _stret_
módszer használatának szabálya eltér az x86 és az ARM esetében.Ha azt szeretné, hogy a kötések mind a szimulátoron,mind az eszközön működjenek, adjon hozzá az alábbi kódot:
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);}
az objc_msgSend_stret metódus használata
amikor arm-re épít, használja aobjc_msgSend_stret
értéket minden olyan értéktípushoz, amely nem felsorolás, vagy a felsorolás egyik alaptípusa(int
, byte
, short
, long
, double
, float
).
ha x86-ra épít, használja aobjc_msgSend_stret
értéket minden olyan értéktípushoz, amely nem felsorolás, vagy a felsorolás bármely alaptípusa(int
, byte
, short
, long
, double
, float
)és amelynek natív mérete nagyobb, mint 8 bájt.
saját aláírások létrehozása
szükség esetén a következő lényeg használható saját aláírások létrehozására.