about

The app which I am currently doing has social functions, so I did some features for searching friends on our server and , of course, managing those connections. It is easy to use a UIActionSheet to show user different managing choices such as unfollow, block, connect and disconnect. But it is easy for user to forget which friend is chosen. Of course, you can set some information to UIActionSheet’s title and description, but how about making things much nicer. So what I did is to create a custom action sheet which can show friend’s image and other information directly in the description area.

The images below are showing you the difference between custom action sheet and UIActionSheet. I try my best to make the custom one look like what apple did.

Difference between custom and originalDifference between custom and original

The init function in .h file looks like this:

1
2
3
4
5
- (id)initWithImage:(UIImage *)titleImage 
title:(NSString *)title
delegate:(id)delegate
cancelButtonTitle:(NSString *)cancelButtonTitle
otherButtonTitles:(NSString *)otherButtonTitles, ...NS_REQUIRES_NIL_TERMINATION;

Notice there is a NS_REQUIRES_NIL_TERMINATION at the end of the init code. The NS_REQUIRES_NIL_TERMINATION part is a macro that tells the compiler that invocations of this method must include a nil-terminated list of arguments. With NS_REQUIRES_NIL_TERMINATION, when you init a custom action sheet, Xcode will automatically add nil at the end of the code. It looks like this:

Well, Xcode is smart. But if you forget to put the nil at the end of otherButtonTitles, the compiler won’t know where to stop. The app will crash. There is one piece of code in init function:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
va_list args;
va_start(args, otherButtonTitles);
if (otherButtonTitles) {
[_buttonTitleArray addObject:otherButtonTitles];
while (1) {
NSString *otherButtonTitle = va_arg(args, NSString *);
if (otherButtonTitle == nil) {
break;
} else {
[_buttonTitleArray addObject:otherButtonTitle];
}
}
}
va_end(args);

va_arg(args, NSString *) will not stop get next NSString object if there is no nil in the init code.

The rest of things are implementing interface, creating show and hide animation and making pressed delegate. For delegate, there is a NSMutableArray which contains all the buttons the code creates. When one button is pressed, you find the index of the button and send it back to the viewController. Make sure the delegate and the delegate function are not nil.

1
2
3
4
5
6
7
8
9
10
11
- (void)buttonPressed:(UIButton *)button {
if (self.delegate && [self.delegate respondsToSelector:@selector(actionSheet:clickedButtonIndex:)]) {
for (int i = 0; i < _buttonArray.count; i++) {
if (button == _buttonArray[i]) {
[_delegate actionSheet:self clickedButtonIndex:i];
break;
}
}
}
[self hide];
}