Objective-C, проходящий вокруг... nil завершенных списков аргументов
Имея некоторые проблемы с ...
в ObjectiveC.
Я в основном обертываю метод и хочу принять завершенный список nil
и напрямую передать тот же список методу, который я обертываю.
Вот что я имею, но это вызывает сбой EXC_BAD_ACCESS
. Проверяя локальные вары, он появляется, когда otherButtonTitles
является просто a NSString
, когда он передается с помощью 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];
}
Как просто переходить от аргумента, входящего в аргумент исходящий, сохраняя тот же самый nil
завершенный список?
Ответы
Ответ 1
Вы не можете этого сделать, по крайней мере, не так, как вы этого хотите. То, что вы хотите сделать (передать переменные аргументы), требует наличия инициализатора на UIAlertView
, который принимает va_list
. Нет. Однако вы можете использовать метод 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];
}
Это, конечно, очень проблемно. Реальный ответ: "вы не можете неявно передавать список переменных аргументов методу/функции, который не имеет параметра va_list
". Поэтому вы должны найти способ решения проблемы. В примере, который вы указали, вы хотели создать alertView с заголовками, которые вы передали. К счастью для вас, класс UIAlertView
имеет метод, который вы можете итеративно вызвать, чтобы добавить кнопки, и тем самым добиться того же общего эффекта. Если у него не было этого метода, вам не повезло.
Другим действительно грязным вариантом было бы сделать его переменным макросом. Макроэкономический макрос выглядит следующим образом:
#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]; \
}
Однако даже при использовании многопараметрического макроса вам все равно понадобится настраиваемый макрос для каждого раза, когда вы захотите это сделать. Это не очень надежная альтернатива.
Ответ 2
Как построить объект NSInvocation
? Поскольку аргументы должны быть переданы указателем, вы можете передать указатель на список, завершенный нулем.
Вы также можете выполнять итерацию по параметрам с помощью marg_list()
и самостоятельно создавать список с нулевым завершением.
Это просто предложения; Я не пробовал их.
Ответ 3
Это относится к случаю OP UIAlertView
-wrapping и проверяется только на iOS7: Кажется, что после того, как a UIAlertView
был инициализирован с помощью otherButtons:nil
, а затем имеет свой стиль в UIAlertViewStylePlainTextInput
, он не делает 't вызвать своего делегата alertViewShouldEnableFirstOtherButton:
для подтверждения ввода. Я не уверен, что это ошибка или намеренное поведение, но это сломало мой принцип наименьшего удивления. Это можно воспроизвести с помощью следующего (предположим, делегат alertViewShouldEnableFirstOtherButton:
реализован):
UIAlertView *av = [[UIAlertView alloc] initWithTitle:@"Title"
message:@"message"
delegate:self
cancelButtonTitle:@"Cancel"
otherButtonTitles:nil];
[av setAlertViewStyle:UIAlertViewStylePlainTextInput];
[av addButtonWithTitle:@"OK"];
[av show];
Решение, так как UIAlertView с радостью принимает otherButtons:nil
, является инициализацией UIAlertView
с другими элементами ButtonTitles (которые могут быть 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];
// 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];
}