- 07/12/2017
- 4 minutter at læse
-
-
d
-
d
-
c
-
a
-
Objective-C-sproget er baseret på vælgere. En vælger er en besked, der kan sendes til et objekt eller en klasse. – Amarin.iOS kortlægger instansvalgtil instansmetoder og klassevælgere til statiske metoder.
i modsætning til normale C-funktioner (og lignende C++ – medlemsfunktioner) kan du ikke direkte påberåbe dig en vælger ved hjælp AFP/Invoke i stedet sendes vælgere til en Objective-C-klasse eller instans ved hjælp af funktionenobjc_msgSend
.
for mere information om meddelelser i Objective-C, se på Apples arbejde med Objectsguide.
eksempel
Antag at du vil påberåbesizeWithFont:forWidth:lineBreakMode:
vælgeren på NSString
.Erklæringen (fra Apples dokumentation) er:
- (CGSize)sizeWithFont:(UIFont *)font forWidth:(CGFloat)width lineBreakMode:(UILineBreakMode)lineBreakMode
denne API har følgende egenskaber:
- returtypen er
CGSize
for Unified API. - parameteren
font
er en UIFont (og en type (indirekte) afledt af NSObject og er kortlagt til System.IntPtr. - parameteren
width
, aCGFloat
, er kortlagt tilnfloat
. - parameteren
lineBreakMode
, aUILineBreakMode
, er allerede bundet i Ksamarin.iOS som optællingenUILineBreakMode
.
at sætte det hele sammen, objc_msgSend
erklæringen skal matche:
CGSize objc_msgSend( IntPtr target, IntPtr selector, IntPtr font, nfloat width, UILineBreakMode mode);
erklære det som følger:
static extern CGSize cgsize_objc_msgSend_IntPtr_float_int ( IntPtr target, IntPtr selector, IntPtr font, nfloat width, UILineBreakMode mode);
for at kalde denne metode skal du bruge kode som følgende:
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);
havde den returnerede værdi været en struktur, der var mindre end 8 bytes i størrelse (som den ældre SizeF
, der blev brugt, før du skiftede til Unified API ‘ er), ville ovenstående kode have kørt på simulatoren, men styrtede ned på enheden. Hvis du vil kalde en vælger, der returnerer en værdi, der er mindre end 8 bit i størrelse, skal du erklære funktionen 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);
for at kalde denne metode skal du bruge kode som følgende:
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 );
påkaldelse af en vælger
påkaldelse af en vælger har tre trin:
- få vælgeren mål.
- få vælgerens navn.
- Ring
objc_msgSend
med de relevante argumenter.
Vælgermål
et vælgermål er enten en objektinstans eller en Objective-C-klasse. Hvis målet er et eksempel og kom fra en bundet Ksamarin.iOS type, Brug egenskaben ObjCRuntime.INativeObject.Handle
.
hvis målet er en klasse, skal du bruge ObjCRuntime.Class
for at få en reference til klasseninstance og derefter bruge egenskaben Class.Handle
.
Vælgernavne er angivet i Apples dokumentation. For eksempel inkluderer NSString
sizeWithFont:
og sizeWithFont:forWidth:lineBreakMode:
vælgere. De indlejrede og efterfølgende kolonner er en del af vælgernavnet og kan ikke udelades.
når du har et vælgernavn, kan du oprette en ObjCRuntime.Selector
instans til det.
opkald objc_msgSend
objc_msgSend
sender en besked (vælger) til et objekt. Denne familie af funktioner tager mindst to krævede argumenter: vælgermålet (aninstance eller klassehåndtag), selve vælgeren og eventuelle argumenterkræves for vælgeren. Eksempel-og vælgerargumenterne skal væreSystem.IntPtr
, og alle resterende argumenter skal svare til typen theselector forventer, for eksempel en nint
for en int
eller enSystem.IntPtr
for alle NSObject
-afledte typer. Brug egenskabenNSObject.Handle
til at få en IntPtr
til en forekomst af Objective-C-typen.
der er mere end en objc_msgSend
funktion:
- brug
objc_msgSend_stret
til vælgere, der returnerer en struktur. På ARM, dette inkluderer alle returtyper, der ikke er en optælling eller nogen af de C-indbyggede typer (char
,short
,int
,long
,float
,double
). På 86 (simulatoren) skal denne metode bruges til alle strukturer større end 8 byte i størrelse(CGSize
er 8 byte og bruger ikkeobjc_msgSend_stret
isimulator). - brug
objc_msgSend_fpret
til vælgere, der kun returnerer en floating point-værdi på 86. Denne funktion behøver ikke bruges på ARM; brug i stedetobjc_msgSend
. - hovedobjc_msgsendfunktionen bruges til alle andre vælgere.
når du har besluttet, hvilken objc_msgSend
funktion(er) du skal ringe til(simulator og enhed kan hver især kræve en anden metode), kan du brugeen normal metode til at erklære funktionen til senere påkaldelse.
et sæt af pre-made objc_msgSend
erklæringer kan findes iObjCRuntime.Messaging
.
forskellige påkaldelser på simulator og enhed
som beskrevet ovenfor har Objective-C tre slags objc_msgSend
metoder: en til regelmæssige påkaldelser, en til påkaldelser, der returnerer flydende punktværdier (kun 86) og en til påkaldelser, der returnerer værdier. Sidstnævnte omfatter suffikset _stret
iObjCRuntime.Messaging
.
hvis du påkalder en metode, der returnerer visse strukturer (regler beskrevet nedenfor), skal du påkalde metoden med returværdien som den førsteparameter som en out
værdi:
// The following returns a PointF structure:PointF ret;Messaging.PointF_objc_msgSend_stret_PointF_IntPtr (out ret, this.Handle, selConvertPointFromWindow.Handle, point, window.Handle);
reglen for hvornår man skal bruge _stret_
– metoden er forskellig på H86 og ARM.Hvis du vil have dine bindinger til at fungere på både simulatoren og enheden,skal du tilføje kode som følgende:
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);}
brug af objc_msgSend_stret-metoden
når du bygger til ARM, skal du brugeobjc_msgSend_stret
til enhver værditype, der ikke er en optælling eller nogen af basetyperne til en optælling (int
, byte
, short
, long
, double
, float
).
når du bygger til 86, skal du brugeobjc_msgSend_stret
for enhver værditype, der ikke er en optælling eller nogen af basistyperne til en optælling (int
, byte
, short
, long
, double
, float
)og hvis oprindelige størrelse er større end 8 bytes.
oprettelse af dine egne signaturer
følgende kerne kan bruges til at oprette dine egne signaturer, hvis det kræves.