Objective-C che passa attorno a … liste di argomenti terminate

Avere alcuni problemi con il ... in ObjectiveC.

Fondamentalmente sto avvolgendo un metodo e voglio accettare un elenco terminato nil e passare direttamente quella stessa lista al metodo che sto tagliando.

Ecco cosa ho ma provoca un arresto EXC_BAD_ACCESS . Ispezionando i 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 a sifonare dall’argomento in arrivo all’argomento in uscita, preservando la stessa lista terminata nil ?

    Non puoi farlo, almeno non nel modo in cui vuoi farlo. Quello che si vuole fare (passare gli argomenti variabili) richiede di avere un inizializzatore su UIAlertView che accetta una va_list . Non ce n’è uno. Tuttavia, puoi 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]; } 

    Questo è, ovviamente, molto specifico del problema. La vera risposta è “non è ansible passare implicitamente una lista di argomenti variabili a un metodo / funzione che non ha un parametro va_list “. È quindi necessario trovare un modo per aggirare il problema. Nell’esempio che hai fornito, volevi creare un avviso con i titoli che hai passato. Fortunatamente per te, la class UIAlertView ha un metodo che puoi chiamare in modo iterativo per aggiungere pulsanti e ottenere così lo stesso effetto complessivo. Se non avesse questo metodo, saresti sfortunato.

    L’altra opzione davvero disordinata sarebbe quella di renderla una macro variadica. Una macro variadica si presenta così:

     #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 variadico, avresti comunque bisogno di una macro personalizzata per ogni volta che volevi farlo. Non è un’alternativa molto solida.

    Che ne dici di build un object NSInvocation ? Poiché gli argomenti devono essere passati dal puntatore, è ansible passare il puntatore all’elenco nil-terminato.

    È anche ansible eseguire iterazioni sui parametri utilizzando marg_list() e marg_list() un elenco nil-terminato autonomamente.

    Questi sono solo semplici suggerimenti; Non li ho provati.

    Questo è specifico per il caso di wrapping UIAlertView dell’OP e testato solo su iOS7: Sembra che una volta che UIAlertView è stato inizializzato con otherButtons:nil , e quindi ha il suo stile impostato su UIAlertViewStylePlainTextInput che non richiama l’ alertViewShouldEnableFirstOtherButton: del proprio delegatoViewShouldEnableFirstOtherButton alertViewShouldEnableFirstOtherButton: per convalidare ingresso. Non sono sicuro che si tratti di un bug o di un comportamento intenzionale, ma ha infranto il mio principio di minimo stupore. Questo è riproducibile con il seguente (presumo che l’ alertViewShouldEnableFirstOtherButton: del delegatoViewShouldEnableFirstOtherButton alertViewShouldEnableFirstOtherButton: sia 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, dal momento che UIAlertView accetta volentieri otherButtons:nil , è inizializzare UIAlertView con altriButtonTitles (che può essere nullo), e iterare sopra gli argomenti variadici, 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]; }