Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
La Objective-C lingua si basa sui selettori. Un selettore è un messaggio che può essere inviato a un oggetto o a una classe. Xamarin.iOS esegue il mapping dei selettori di istanza ai metodi di istanza e ai selettori di classe ai metodi statici.
A differenza delle normali funzioni C (e come le funzioni membro C++), non è possibile richiamare direttamente un selettore usando P/Invoke , i selettori vengono inviati a una classe o a un'istanza Objective-C usando objc_msgSend Funzione.
Per altre informazioni sui messaggi in Objective-C, vedere la guida Sull'uso degli oggetti di Apple.
Esempio
Si supponga di voler richiamare il sizeWithFont:forWidth:lineBreakMode: selettore in NSString.
La dichiarazione (dalla documentazione di Apple) è:
- (CGSize)sizeWithFont:(UIFont *)font forWidth:(CGFloat)width lineBreakMode:(UILineBreakMode)lineBreakMode
Questa API presenta le caratteristiche seguenti:
- Il tipo restituito è
CGSizeper l'API unificata. - Il
fontparametro è un oggetto UIFont (e un tipo (indirettamente) derivato da NSObject ed è mappato a System.IntPtr. - Il
widthparametro , unCGFloatoggetto , viene mappato anfloat. - Il
lineBreakModeparametro , unUILineBreakMode, è già stato associato in Xamarin.iOS comeUILineBreakModeEnumerazione.
Mettendo tutto insieme, la objc_msgSend dichiarazione deve corrispondere:
CGSize objc_msgSend(
IntPtr target,
IntPtr selector,
IntPtr font,
nfloat width,
UILineBreakMode mode
);
Dichiararlo come segue:
[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
);
Per chiamare questo metodo, usare codice come il seguente:
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
);
Se il valore restituito fosse una struttura di dimensioni inferiori a 8 byte (come quella precedente SizeF usata prima di passare alle API unificate), il codice precedente sarebbe stato eseguito nel simulatore, ma si è verificato un arresto anomalo del dispositivo. Per chiamare un selettore che restituisce un valore inferiore a 8 bit di dimensioni, dichiarare la objc_msgSend_stret funzione:
[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
);
Per chiamare questo metodo, usare codice come il seguente:
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
);
Chiamata di un selettore
La chiamata di un selettore prevede tre passaggi:
- Ottenere la destinazione del selettore.
- Ottenere il nome del selettore.
- Chiamare
objc_msgSendcon gli argomenti appropriati.
Destinazioni del selettore
Una destinazione del selettore è un'istanza dell'oggetto o una Objective-C classe. Se la destinazione è un'istanza e proviene da un tipo Xamarin.iOS associato, usare la ObjCRuntime.INativeObject.Handle proprietà .
Se la destinazione è una classe, usare ObjCRuntime.Class per ottenere un riferimento all'istanza della classe , quindi usare la Class.Handle proprietà .
Nomi del selettore
I nomi dei selettori sono elencati nella documentazione di Apple. Ad esempio, NSString include sizeWithFont: e sizeWithFont:forWidth:lineBreakMode: selettori. I due punti incorporati e finali fanno parte del nome del selettore e non possono essere omessi.
Dopo aver ottenuto un nome del selettore, è possibile crearne un'istanza ObjCRuntime.Selector .
Chiamata di objc_msgSend
objc_msgSend invia un messaggio (selettore) a un oggetto . Questa famiglia di funzioni accetta almeno due argomenti obbligatori: la destinazione del selettore (un'istanza o un handle di classe), il selettore stesso e tutti gli argomenti necessari per il selettore. Gli argomenti dell'istanza e del selettore devono essere System.IntPtre tutti gli argomenti rimanenti devono corrispondere al tipo previsto dal selettore, ad esempio per nint un intoggetto o per System.IntPtr tutti i NSObjecttipi derivati da . Usare il NSObject.Handle per ottenere un oggetto per un'istanza IntPtrObjective-C del tipo.
È presente più di una objc_msgSend funzione:
- Usare
objc_msgSend_stretper i selettori che restituiscono uno struct. In ARM sono inclusi tutti i tipi restituiti che non sono un'enumerazione o uno qualsiasi dei tipi predefiniti C (char,short,longint,float, , ).doubleIn x86 (simulatore), questo metodo deve essere usato per tutte le strutture di dimensioni superiori a 8 byte (CGSizeè di 8 byte e non viene usatoobjc_msgSend_stretnel simulatore). - Usare
objc_msgSend_fpretper i selettori che restituiscono un valore a virgola mobile solo su x86. Questa funzione non deve essere usata in ARM; Usare inveceobjc_msgSend. - La funzione objc_msgSend principale viene usata per tutti gli altri selettori.
Dopo aver deciso quali objc_msgSend funzioni è necessario chiamare (simulatore e dispositivo possono richiedere un metodo diverso), è possibile usare un metodo normale [DllImport] per dichiarare la funzione per una chiamata successiva.
Un set di dichiarazioni predefinite objc_msgSend è disponibile in ObjCRuntime.Messaging.
Chiamate diverse nel simulatore e nel dispositivo
Come descritto in precedenza, Objective-C include tre tipi di objc_msgSend metodi: uno per le chiamate regolari, uno per le chiamate che restituiscono valori a virgola mobile (solo x86) e uno per le chiamate che restituiscono valori di struct. Quest'ultimo include il suffisso _stret in ObjCRuntime.Messaging.
Se si richiama un metodo che restituisce determinati struct (regole descritte di seguito), è necessario richiamare il metodo con il valore restituito come primo parametro come out valore:
// The following returns a PointF structure:
PointF ret;
Messaging.PointF_objc_msgSend_stret_PointF_IntPtr (out ret, this.Handle, selConvertPointFromWindow.Handle, point, window.Handle);
La regola per quando usare il _stret_ metodo è diversa da x86 e ARM.
Se si desidera che le associazioni funzionino sia sul simulatore che sul dispositivo, aggiungere codice come il seguente:
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);
}
Utilizzo del metodo objc_msgSend_stret
Durante la compilazione per ARM, usare objc_msgSend_stretper qualsiasi tipo di valore che non è un'enumerazione o uno qualsiasi dei tipi di base per un'enumerazione (int, byte, shortlong, double). float
Quando si compila per x86, usare objc_msgSend_stretper qualsiasi tipo valore che non è un'enumerazione o uno dei tipi di base per un'enumerazione (int, byte, shortlong, doublefloat) e la cui dimensione nativa è maggiore di 8 byte.
Creazione di firme personalizzate
Il gist seguente può essere usato per creare firme personalizzate, se necessario.