定义一个参数个数可变的方法

有时候,我们想定义一个参数个数可变的方法。例如我们想用系统的alertView去实现一些功能,但是系统的提供的不能完全的满足我们的需求,当然我们可以通过category来实现,给UIAlertView扩展一些方法但是,但是如果要添加某些属性,通过category实现起来就会麻烦点了(runtime 可以实现)。

看了下系统的alert View 的init方法中使用了一个 NS_REQUIRES_NIL_TERMINATION 的宏

- (instancetype)initWithTitle:(nullable NSString )title message:(nullable NSString *)message delegate:(nullable id /<UIAlertViewDelegate>*/)delegate cancelButtonTitle:(nullable NSString *)cancelButtonTitle otherButtonTitles:(nullable NSString *)otherButtonTitles, ... NS_REQUIRES_NIL_TERMINATION NS_EXTENSION_UNAVAILABLE_IOS("Use UIAlertController instead.");
    if !defined(NS_REQUIRES_NIL_TERMINATION)
    #if TARGET_OS_WIN32
        #define NS_REQUIRES_NIL_TERMINATION
    #else
        #if defined(__APPLE_CC__) && (__APPLE_CC__ >= 5549)
            #define NS_REQUIRES_NIL_TERMINATION __attribute__((sentinel(0,1)))
        #else
            #define NS_REQUIRES_NIL_TERMINATION __attribute__((sentinel))
        #endif
    #endif
    endif

attribute((sentinel)) 告知编译器 需要一个结尾的参数,告知编译器参数的列表已经到最后一个不要再继续执行下去了

按照alert的init放,写了个事例demo

typedef void(^KSEditAlertBlock)(NSInteger buttonIndex, id returnObj);

@interface KSAlertView : NSObject

- (instancetype)initAlertTitle:(NSString *)title message:(NSString *)alertMessage cancelButtonTitle:(NSString *)cancleButtonTitle otherButtonTitles:(NSString *)otherButtonTitles, ... NS_REQUIRES_NIL_TERMINATION;
- (void)setButtonPressBlock:(KSEditAlertBlock)block;

这样,我们在传参数的时候,就可以将多个(不定)参数传递到方法里面

参数传进去了,并不是意味着我们可以直接使用了,需要使用参数,我们还需要做其他的事情

    NSMutableArray *listArray = [NSMutableArray array];
    va_list argList;
    if (otherButtonTitles) {
      // va_start(ap, param) __builtin_va_start(ap, param)
              // va_start宏,获取可变参数列表的第一个参数的地址,在这里是获取otherButtonTitles的内存地址,这时argList的指针 指向otherButtonTitles
        va_start(argList, otherButtonTitles);
        
        id temp; // 临时指针变量
      // va_arg(ap, type)    __builtin_va_arg(ap, type)  
            // var_arg 宏 返回当前指定类型的值,并且把 argList 的位置指向变参表的下一个变量位置
        while ((temp = va_arg(argList, id))) {
            [listArray addObject:temp];
        }
      va_end(argList); // 关闭 argList指针
    }
    self.alert = [[UIAlertView alloc] initWithTitle:title message:alertMessage delegate:self cancelButtonTitle:cancleButtonTitle otherButtonTitles:otherButtonTitles, nil];
    for (NSString *buttonName in listArray) {
        [self.alert addButtonWithTitle:buttonName];
    }
    self.alert.alertViewStyle = UIAlertViewStylePlainTextInput;
    _textField = [self.alert textFieldAtIndex:0];
    _textField.placeholder = @"请输入";
    _textField.keyboardType = UIKeyboardTypeNumberPad;
    [self.alert show];

这时候我们就可以将传到方法内的可变参数表中的参数正确的使用了 当然在调用的时候一定要记住,在可变参数的结尾,要加上nil 这个哨兵参数,这样取参循环才会结束,否则temp = va_arg(argList, id)这个就会一直取值,当取到未分配的内存地址,listArray赋值的时候就会造成crash。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值