问题
Am attempting to subclass UIAlertView to better handle error states in my app. The trouble am having is with the otherButtonTitles nil terminated parameter, when I create my subclass it is only picking up the first string in the list rather than all the strings
+ (ErrorAlertView *)displayErrorAlertViewWithTitle:(NSString *)title
message:(NSString *)message
delegate:(id<UIAlertViewDelegate>)delegate
errorDelegate:(id<ErrorAlertViewDelegate>)errorDelegate
cancelButtonTitle:(NSString *)cancelButtonTitle
displayNow:(BOOL)displayNow
tag:(NSUInteger)tag
otherButtonTitles:(NSString *)otherButtonTitles, ...;
{
ErrorAlertView *errorAlertView = [[ErrorAlertView alloc] initWithTitle:title
message:message
delegate:delegate
cancelButtonTitle:cancelButtonTitle
otherButtonTitles:otherButtonTitles, nil];
errorAlertView.errorDelegate = errorDelegate;
errorAlertView.tag = tag;
if (displayNow) {
[errorAlertView show];
}
return [errorAlertView autorelease];
}
If I make the following call the above method:
[ErrorAlertView displayErrorAlertViewWithTitle:[self noInternetConnectionAlertViewTitle]
message:[self noInternetConnectionAlertViewMessage]
delegate:self
errorDelegate:errorDelegate
cancelButtonTitle:@"OK"
displayNow:YES
tag:ErrorAlertTagInternetConnectionError
@"Try again",@"Setting", nil];
The UIAlertView is being shown with only the @"Try again" button being shown.
回答1:
You can't send a variable set of parameters like that.
When I subclassed UIAlertView I did this:
va_list args;
va_start(args, otherButtonTitles);
for (NSString *anOtherButtonTitle = otherButtonTitles; anOtherButtonTitle != nil; anOtherButtonTitle = va_arg(args, NSString*)) {
[self addButtonWithTitle:anOtherButtonTitle];
}
Alternatively, you could create a variant of your function that accepts a va_list as a (single) parameter, and then runs the above code.
Generally, when writing a variadic function, you should include an alternative for handling this eventuality. Apple supply the addButtonWithTitle: method in this case.
回答2:
From the UIAlertView Class Reference
Subclassing Notes
The UIAlertView class is intended to be used as-is and does not support subclassing. The view hierarchy for this class is private and must not be modified.
There are, however, many other alert view implementations that you may find useful, posted here on CocoaControls.
回答3:
Instead of subclassing UIAlertView, I prefer to create simple classes that typically just have a show method that takes a delegate parameter. The delegate protocol then has expressive methods that correspond to the available options.
While this approach results in more delegate functions than the typical alert view delegate approach, I think it makes the code a lot more readable.
The code typically looks like this (Swift):
@objc protocol DeleteUniverseAlertViewDelegate {
func deleteUniverseAlertViewDidConfirmDelete(view: DeleteUniverseAlertView)
}
class DeleteUniverseAlertView : NSObject, UIAlertViewDelegate {
private weak var delegate: DeleteUniverseAlertViewDelegate? = nil
class func showWithDelegate(delegate: DeleteUniverseAlertViewDelegate) -> DeleteUniverseAlertView {
let view = DeleteUniverseAlertView()
view.delegate = delegate
UIAlertView(title: "Delete universe?", message: "Are you really, really sure about this?", delegate: view, cancelButtonTitle: "Cancel", otherButtonTitles: "Yes, delete!").show()
return view
}
func alertView(alertView: UIAlertView, clickedButtonAtIndex buttonIndex: Int) {
if (buttonIndex > 0) {
delegate?.deleteUniverseAlertViewDidConfirmDelete(self)
}
}
}
When you then need to show this alert, just implement the protocol and show the custom alert like this (remember to keep a strong reference to the alert view):
deleteAlert = DeletePlaceAlertView.showWithDelegate(self)
来源:https://stackoverflow.com/questions/8309869/subclassing-uialertview