selectoare Objective-C în Xamarin.iOS

  • 07/12/2017
  • 4 minute de citit
    • d
    • d
    • c
    • a

limbajul Objective-C se bazează pe selectori. Un selector este amesaj care poate fi trimis unui obiect sau unei clase. Xamarin.iOS maps instanță selectorsto metode de instanță, și selectoare de clasă la metode statice.

spre deosebire de funcțiile normale C (și cum ar fi funcțiile membre C++), nu puteți invoca direct un selector folosind p/invoca în schimb,selectorii sunt trimiși la o clasă sau instanță Objective-C folosind funcțiaobjc_msgSend.

pentru mai multe informații despre mesajele din Objective-C, aruncați o privire la Apple ‘ sworking with Objectsguide.

exemplu

să presupunem că doriți să invocați selectorulsizeWithFont:forWidth:lineBreakMode:pe NSString.Declarația (din documentația Apple) este:

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

acest API are următoarele caracteristici:

  • tipul de retur este CGSize pentru API-ul unificat.
  • parametrul font este un UIFont (și un tip (indirect) derivat din NSObject, și este mapat la sistem.IntPtr.
  • parametrul width, a CGFloat, este mapat la nfloat.
  • parametrul lineBreakMode, a UILineBreakMode,a fost deja legat în Xamarin.iOS ca enumerareaUILineBreakMode.

punând totul împreună, declarația objc_msgSend ar trebui să se potrivească:

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

declarați-o după cum urmează:

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

pentru a apela această metodă, utilizați cod, cum ar fi următoarele:

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

dacă valoarea returnată ar fi fost o structură cu o dimensiune mai mică de 8 octeți (la fel ca cea mai veche SizeF utilizată înainte de a trece la API-urile unificate), codul de mai sus ar fi rulat pe simulator, dar s-ar fi prăbușit pe dispozitiv. Pentru a apela un selector care returnează o valoare mai mică de 8 biți, declarați funcția 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);

pentru a apela această metodă, utilizați cod, cum ar fi următoarele:

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

invocarea unui selector

invocarea unui selector are trei pași:

  1. ia ținta selector.
  2. obțineți numele selectorului.
  3. apel objc_msgSend cu argumentele corespunzătoare.

obiective Selector

o țintă selector este fie o instanță obiect sau o clasă Objective-C. Dacă ținta este o instanță și a venit de la un Xamarin legat.tip iOS, utilizați ObjCRuntime.INativeObject.Handle proprietate.

dacă ținta este o clasă, utilizați ObjCRuntime.Class pentru a obține o referință la classinstance, apoi utilizați proprietatea Class.Handle.

numele selectorului

numele selectorului sunt listate în documentația Apple. De exemplu, NSString include selectorii sizeWithFont: și sizeWithFont:forWidth:lineBreakMode:. Coloanele încorporate și cele finale fac parte din numele selectorului și nu pot fi omise.

odată ce aveți un nume selector, puteți crea o instanță ObjCRuntime.Selector pentru acesta.

apelarea objc_msgSend

objc_msgSend trimite un mesaj (selector) unui obiect. Această familie de funcții are cel puțin două argumente necesare: ținta selectorului (mâner aninstance sau class), selectorul în sine și orice argumente necesare pentru selector. Argumentele instanță și selector trebuie să fieSystem.IntPtr și toate argumentele rămase trebuie să corespundă tipului pe care theselector îl așteaptă, de exemplu un nint pentru un int sau unSystem.IntPtrpentru toate tipurile derivate NSObject. Utilizați proprietateaNSObject.Handlepentru a obține un IntPtr pentru o instanță de tip Objective-C.

există mai multe funcții objc_msgSend :

  • utilizați objc_msgSend_stretpentru selectori care returnează o struct. Pe ARM, aceasta include toate returntypes care nu sunt o enumerare sau oricare dintre C built-in tipuri (char,short, int, long, float, double). Pe x86 (simulatorul), această metodă trebuie utilizată pentru toate structurile cu dimensiuni mai mari de 8 octeți (CGSize este de 8 octeți și nu utilizează objc_msgSend_stret în simulator).
  • utilizați objc_msgSend_fpretpentru selectorii care returnează o valoare în virgulă mobilă numai pe x86. Thisfunction nu trebuie să fie utilizat pe ARM; în schimb, utilizați objc_msgSend.
  • funcția mainobjc_msgsend este utilizată pentru toți ceilalți selectori.

după ce v-ați decis care objc_msgSendfuncția(E) trebuie să apelați(simulator și dispozitiv poate necesita fiecare o metodă diferită), puteți usea normală metoda de a declara funcția pentru invocarea ulterioară.

un set de declarații prefabricate objc_msgSend poate fi găsit înObjCRuntime.Messaging.

diferite invocări pe simulator și dispozitiv

așa cum este descris mai sus, Objective-C are trei tipuri de objc_msgSendmetode: una pentru invocări regulate, una pentru invocări care returnează valorile punctelor plutitoare (numai x86) și una pentru invocări care returnează valorile Struct. Acesta din urmă include sufixul _stret înObjCRuntime.Messaging.

dacă invocați o metodă care va returna anumite structuri (reguli descrise mai jos), trebuie să invocați metoda cu valoarea returnată ca primparametru ca valoare 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);

regula pentru când se utilizează metoda _stret_ diferă pe x86 și ARM.Dacă doriți ca legăturile dvs. să funcționeze atât pe simulator, cât și pe dispozitiv, adăugați cod, cum ar fi următoarele:

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

folosind metoda objc_msgSend_stret

când construiți pentru ARM, utilizațiobjc_msgSend_stretpentru orice tip de valoare care nu este o enumerare sau oricare dintre tipurile de bază pentru o enumerare (int, byte, short, long, double, float).

când construiți pentru x86, utilizați objc_msgSend_stret pentru orice tip de valoare care nu este o enumerare sau oricare dintre tipurile de bază pentru o enumerare (int, byte, short, long, double, float)și a cărui dimensiune nativă este mai mare de 8 octeți.

crearea propriilor semnături

următorul rezumat poate fi utilizat pentru a crea propriile semnături, dacă este necesar.

Lasă un răspuns

Adresa ta de email nu va fi publicată.