Objective-C selectors in Xamarin.iOS

  • 07/12/2017
  • 4 minuten om te lezen
    • d
    • d
    • c
    • a

de Objective-C taal is gebaseerd op selectors. Een selector is een bericht dat kan worden verzonden naar een object of een klasse. Xamarin.iOS wijst instance selectors toe aan instance methods, en class selectors aan statische methoden.

in tegenstelling tot normale C-functies (en zoals C++ – member-functies), kunt u niet rechtstreeks een selector aanroepen met behulp van P/inroepen.in plaats daarvan worden selectors naar een Objective-C-klasse of instantie gestuurd met behulp van deobjc_msgSend – functie.

voor meer informatie over berichten in Objective-C, Zie Apple ‘ sworking with objects Guide.

voorbeeld

stel dat u desizeWithFont:forWidth:lineBreakMode:selector op NSStringwilt aanroepen.De verklaring (uit de documentatie van Apple) is:

- (CGSize)sizeWithFont:(UIFont *)font forWidth:(CGFloat)width lineBreakMode:(UILineBreakMode)lineBreakMode

deze API heeft de volgende kenmerken:

  • het return type is CGSize voor de Unified API.
  • de font parameter is een UIFont (en een type (indirect) afgeleid van NSObject, en wordt toegewezen aan het systeem.IntPtr.
  • de parameter width, a CGFloat, wordt toegewezen aan nfloat.
  • de parameter lineBreakMode, a UILineBreakMode, is al gebonden in Xamarin.iOS als de UILineBreakModeopsomming.

bij elkaar opgeteld moet de objc_msgSend – declaratie overeenkomen met:

CGSize objc_msgSend( IntPtr target, IntPtr selector, IntPtr font, nfloat width, UILineBreakMode mode);

verklaart het als volgt::

static extern CGSize cgsize_objc_msgSend_IntPtr_float_int ( IntPtr target, IntPtr selector, IntPtr font, nfloat width, UILineBreakMode mode);

om deze methode aan te roepen, gebruik code zoals de volgende:

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);

als de geretourneerde waarde een structuur was die minder dan 8 bytes groot was (zoals de oudere SizeF die werd gebruikt voor het overschakelen naar de Unified API ‘ s), zou de bovenstaande code op de simulator zijn uitgevoerd, maar op het apparaat zijn gecrasht. Als u een selector wilt aanroepen die een waarde van minder dan 8 bits retourneert, declareert u de functie 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);

om deze methode aan te roepen, gebruik code zoals de volgende:

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 );

een selector aanroepen

een selector aanroepen heeft drie stappen:

  1. haal het selectordoel.
  2. krijg de naam van de selector.
  3. Call objc_msgSend met de juiste argumenten.

selectordoelen

een selectordoel is een object-instantie of een object – C-klasse. Als het doel een instantie is en afkomstig is van een gebonden Xamarin.iOS-type, gebruik de eigenschap ObjCRuntime.INativeObject.Handle.

als het doel een klasse is, gebruik dan ObjCRuntime.Class om een verwijzing naar de classinstance te krijgen, gebruik dan de eigenschap Class.Handle.

Selectornamen

Selectornamen worden vermeld in de documentatie van Apple. NSString omvat bijvoorbeeld sizeWithFont: en sizeWithFont:forWidth:lineBreakMode: selectors. De ingebedde en achterliggende punten maken deel uit van de selectornaam en kunnen niet worden weggelaten.

Als u een selectornaam hebt, kunt u er een instance ObjCRuntime.Selector voor maken.

het aanroepen van objc_msgSend

objc_msgSend stuurt een bericht (selector) naar een object. Deze familie offunctions heeft ten minste twee vereiste argumenten: het selector doel (aninstance of class handle), de selector zelf, en alle argumenten vereist voor de selector. De instantie-en selectorargumenten moetenSystem.IntPtr zijn, en alle overige argumenten moeten overeenkomen met het type dat de selector verwacht, bijvoorbeeld een nint voor een int, of eenSystem.IntPtr voor alle NSObject-afgeleide types. Gebruik de eigenschapNSObject.Handleom een IntPtr te verkrijgen voor een Objective-C type instantie.

er is meer dan één objc_msgSend functie:

  • gebruik objc_msgSend_stretvoor selectors die een struct retourneren. Op ARM, dit omvat alle returntypes die geen opsomming of een van de C ingebouwde types zijn(char,short, int, long, float, double). Op x86 (de simulator) moet deze methode gebruikt worden voor alle structuren groter dan 8 bytes (CGSize is 8 bytes en gebruikt objc_msgSend_stret niet in de simulator).
  • gebruik objc_msgSend_fpretvoor selectors die alleen op x86 een drijvende-kommawaarde retourneren. Deze functie hoeft niet op ARM te worden gebruikt; gebruik in plaats daarvan objc_msgSend.
  • de functie mainobjc_msgsend wordt gebruikt voor alle andere selectors.

zodra u hebt besloten welke objc_msgSend functie(s) u moet aanroepen (simulator en apparaat kunnen elk een andere methode vereisen), kunt u een normale methode gebruiken om de functie te declareren voor latere aanroep.

een reeks vooraf gemaakte objc_msgSend verklaringen is te vinden inObjCRuntime.Messaging.

verschillende aanroepingen op simulator en apparaat

zoals hierboven beschreven, heeft Objective-C drie soorten objc_msgSend methoden: één voor regelmatige aanroepingen, één voor aanroepingen die zwevende puntwaarden retourneren (alleen x86), en één voor aanroepingen die waarden retourneren. Deze laatste bevat het achtervoegsel _stret inObjCRuntime.Messaging.

als u een methode aanroept die bepaalde struct ‘ s retourneert (regels hieronder beschreven), moet u de methode aanroepen met de retourwaarde als de firstparameter als een out waarde:

// The following returns a PointF structure:PointF ret;Messaging.PointF_objc_msgSend_stret_PointF_IntPtr (out ret, this.Handle, selConvertPointFromWindow.Handle, point, window.Handle);

de regel voor het gebruik van de _stret_ methode verschilt op x86 en ARM.Als u wilt dat uw bindingen werken op zowel de simulator en het apparaat,voeg code zoals de volgende:

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);}

gebruik de objc_msgSend_stret-methode

gebruik bij het bouwen voor ARMobjc_msgSend_stretvoor elk waardetype dat geen Enumeratie is of een van de basistypen voor een enumeratie (int, byte, short, long, double, float).

gebruik bij het bouwen voor x86objc_msgSend_stretvoor elk waardetype dat geen Enumeratie is of een van de basistypen voor een enumeratie (int, byte, short, long, double, float)en waarvan de oorspronkelijke grootte groter is dan 8 bytes.

uw eigen handtekeningen aanmaken

de volgende kern kan worden gebruikt om uw eigen handtekeningen te maken, indien nodig.

Geef een antwoord

Het e-mailadres wordt niet gepubliceerd.