Objective-C passando intorno ... nil terminato liste di argomenti
-
23-09-2019 - |
Domanda
avendo alcuni problemi con la ...
in ObjectiveC.
Sono fondamentalmente avvolgendo un metodo e vogliono accettare un nil
lista terminata e direttamente passare lo stesso elenco per il metodo che sto avvolgendo.
Ecco quello che ho, ma provoca un incidente EXC_BAD_ACCESS
. Ispezione delle vars locali, appare quando otherButtonTitles
è semplicemente un NSString
quando viene passato con otherButtonTitles:@"Foo", nil]
+ (void)showWithTitle:(NSString *)title
message:(NSString *)message
delegate:(id)delegate
cancelButtonTitle:(NSString *)cancelButtonTitle
otherButtonTitles:(NSString *)otherButtonTitles, ...
{
UIAlertView *alert = [[[UIAlertView alloc] initWithTitle:title
message:message
delegate:delegate
cancelButtonTitle:cancelButtonTitle
otherButtonTitles:otherButtonTitles] autorelease];
[alert show];
}
Come faccio semplicemente sifone dalla discussione in arrivo per l'argomento in uscita, mantenendo la stessa identica nil
lista terminato?
Soluzione
Non si può fare questo, almeno non nel modo in cui hai intenzione di farlo. Che cosa si vuole fare (passare sugli argomenti variabili) richiede avere un inizializzatore su UIAlertView
che accetta un va_list
. Non c'è una sola. Tuttavia, è possibile utilizzare il metodo addButtonWithTitle:
:
+ (void)showWithTitle:(NSString *)title
message:(NSString *)message
delegate:(id)delegate
cancelButtonTitle:(NSString *)cancelButtonTitle
otherButtonTitles:(NSString *)otherButtonTitles, ...
{
UIAlertView *alert = [[[UIAlertView alloc] initWithTitle:title
message:message
delegate:delegate
cancelButtonTitle:cancelButtonTitle
otherButtonTitles:nil] autorelease];
if (otherButtonTitles != nil) {
[alert addButtonWithTitle:otherButtonTitles];
va_list args;
va_start(args, otherButtonTitles);
NSString * title = nil;
while(title = va_arg(args,NSString*)) {
[alert addButtonWithTitle:title];
}
va_end(args);
}
[alert show];
}
Questa è, ovviamente, molto problema specifico. La vera risposta è "non è possibile passare in modo implicito in un elenco di argomenti variabili a un metodo / funzione che non dispongono di un parametro va_list
". È quindi necessario trovare un modo per aggirare il problema. Nell'esempio hai dato, si voleva fare un alertView con i titoli avete passato. Fortunatamente per voi, la classe UIAlertView
ha un metodo che è possibile chiamare per iterativamente aggiungere pulsanti, e quindi ottenere lo stesso effetto complessivo. Se non avesse questo metodo, devi essere fuori di fortuna.
L'altra opzione davvero disordinato potrebbe essere quella di rendere una macro variadic. Una macro variadic assomiglia a questo:
#define SHOW_ALERT(title,msg,del,cancel,other,...) { \
UIAlertView *_alert = [[[UIAlertView alloc] initWithTitle:title message:msg delegate:del cancelButtonTitle:cancel otherButtonTitles:other, ##__VA_ARGS__] autorelease]; \
[_alert show]; \
}
Tuttavia, anche con l'approccio macro variadic, saresti ancora bisogno di una macro personalizzata per ogni volta che si voleva fare questo. Non è una solida alternativa.
Altri suggerimenti
Che ne dite di costruire un oggetto NSInvocation
? Dal momento che gli argomenti devono essere passati per puntatore, si potrebbe passare il puntatore alla lista terminata da zero.
Si potrebbe anche scorrere i parametri utilizzando marg_list()
e costruire un elenco terminata da zero da soli.
Questi sono solo semplici suggerimenti; Non li ho provato.
Questo è specifico per caso UIAlertView
-wrapping del PO, e testato solo su iOS7: Sembra che una volta UIAlertView
è stato inizializzato con otherButtons:nil
, e poi ha messo il suo stile di UIAlertViewStylePlainTextInput
esso non chiama alertViewShouldEnableFirstOtherButton:
dei suoi delegati per la convalida ingresso. Non sono sicuro se questo è un bug o un comportamento previsto ma è rotto il principio del minimo stupore. Questo è riproducibile con la seguente (io presumo alertViewShouldEnableFirstOtherButton:
del delegato è implementato):
UIAlertView *av = [[UIAlertView alloc] initWithTitle:@"Title"
message:@"message"
delegate:self
cancelButtonTitle:@"Cancel"
otherButtonTitles:nil];
[av setAlertViewStyle:UIAlertViewStylePlainTextInput];
[av addButtonWithTitle:@"OK"];
[av show];
La soluzione, poiché UIAlertView accetta tranquillamente otherButtons:nil
, è di inizializzare UIAlertView
con otherButtonTitles (che può essere zero), e iterare gli argomenti variadic, come sopra:
+ (void)showWithTitle:(NSString *)title
message:(NSString *)message
delegate:(id)delegate
cancelButtonTitle:(NSString *)cancelButtonTitle
otherButtonTitles:(NSString *)otherButtonTitles, ...
{
UIAlertView *alert = [[[UIAlertView alloc] initWithTitle:title
message:message
delegate:delegate
cancelButtonTitle:cancelButtonTitle
otherButtonTitles:otherButtonTitles] autorelease];
// add your [alert setAlertViewStyle:UIAlertViewStylePlainTextInput] etc. as required here
if (otherButtonTitles != nil) {
va_list args;
va_start(args, otherButtonTitles);
NSString * title = nil;
while(title = va_arg(args,NSString*)) {
[alert addButtonWithTitle:title];
}
va_end(args);
}
[alert show];
}