使用没有计数的 va_list 方法
Using a va_list method without a count
我正在 NSArray
上编写一个类别以将 JavaScript 数组方法添加到 NSArray
。在 JavaScript 中,splice()
方法都 adds/removes 项 to/from 一个数组。但是添加到数组中的对象数量可能会有所不同。所以我使用 va_list
来允许更灵活地输入对象值。
就目前而言,该方法需要一个计数输入值。没有一个我怎么能重写这个?
界面
@interface NSArray (JavaScriptArray)
- (NSArray *)splice:(NSUInteger)index remove:(NSUInteger)remove count:(NSUInteger)count arguments:(id)firstObject,...;
@end
实施
@implementation NSArray (JavaScriptArray)
- (NSArray *)splice:(NSUInteger)index remove:(NSUInteger)remove count:(NSUInteger)count arguments:(id)firstObject,...
{
NSMutableArray *mSplice = [NSMutableArray arrayWithArray:self];
if (remove != 0) {
NSUInteger removeIndex = index;
for (NSUInteger i = 0; i < remove; i++) {
[mSplice removeObjectAtIndex:removeIndex];
removeIndex = removeIndex + 1;
}
}
if (count != 0) {
NSUInteger addIndex = index;
id eachObject;
va_list argumentList;
if (firstObject) {
[mSplice insertObject:firstObject atIndex:addIndex];
addIndex = addIndex + 1;
va_start(argumentList, firstObject);
eachObject = va_arg(argumentList, id);
for (NSUInteger i = 0; i < count; i++) {
[mSplice insertObject:eachObject atIndex:addIndex];
addIndex = addIndex + 1;
}
va_end(argumentList);
}
}
return [NSArray arrayWithArray:mSplice];
}
@end
调用方法
- (void)viewDidLoad
{
[super viewDidLoad];
NSArray *fruit = @[@"Banana", @"Orange", @"Apple", @"Mango"];
NSArray *fruitSplice = [fruit splice:2 remove:0 count:4 arguments:@"Lemon", @"Kiwi", @"Kiwi", @"Kiwi"];
NSLog(@"fruitSplice %@", fruitSplice);
}
@end
调试器Window
fruitSplice (
Banana,
Orange,
Lemon,
Kiwi,
Kiwi,
Kiwi,
Kiwi,
Apple,
Mango
)
删除 count
参数没有问题,因为实际上您的 "add" 循环似乎不正确。在您使用 eachObject = va_arg(argumentList, id);
从 va_list
中获得第二个项目后,您再也不会获得另一个对象。您的示例起作用的唯一原因是所有后面的项目都相同:@"Kiwi"
。如果您的测试电话是
NSArray *fruitSplice = [fruit splice:2
remove:0
count:4
arguments:@"Lemon", @"Albatross", @"Kiwi", @"Kiwi"];
你会看到
fruitSplice (
Banana,
Orange,
Lemon,
Albatross,
Albatross,
Albatross,
Albatross,
Apple,
Mango
)
作为输出。
您需要重做 va_list
的解包,并且您可以在迭代它时保留自己的计数器,但要注意的是必须有一个 sentinel 值:一个不可能作为有效列表值出现的值,表示您已经到了最后。对于对象类型的可变参数,您通常会使用 nil
作为标记。
当您使用 va_list
时,您必须 哨兵 或 计数。您没有其他方法可以知道何时停止弹出参数。
你的签名可以变成*:
- (NSArray *)KRSpliceAt:(NSUInteger)index
removingCount:(NSUInteger)remove
addingObjects:(id)firstObject, ... NS_REQUIRES_NIL_TERMINATION;
NS_REQUIRES_NIL_TERMINATION
是严格可选的,但如果在没有标记的情况下调用该方法,编译器会通知您。
然后你的添加循环改变:
// Insertion index starts at given splice point
NSUInteger addIndex = index;
// Initialize the va_list
va_list objs;
va_start(objs, firstObj);
// Start at the beginning
id nextObj = firstObj;
// Test for sentinel nil
while( nextObj ){
[mSplice insertObject:nextObj atIndex:addIndex];
// Update insertion point
addIndex++;
// Get next argument
nextObj = va_arg(objs, id);
}
// Signal completion of list
va_end(objs);
*您添加到 类 您不拥有的方法应始终加上前缀。这有点烦人,但如果您碰巧选择了与另一个方法相同的名称,这是防止灾难性冲突的好习惯。
我正在 NSArray
上编写一个类别以将 JavaScript 数组方法添加到 NSArray
。在 JavaScript 中,splice()
方法都 adds/removes 项 to/from 一个数组。但是添加到数组中的对象数量可能会有所不同。所以我使用 va_list
来允许更灵活地输入对象值。
就目前而言,该方法需要一个计数输入值。没有一个我怎么能重写这个?
界面
@interface NSArray (JavaScriptArray)
- (NSArray *)splice:(NSUInteger)index remove:(NSUInteger)remove count:(NSUInteger)count arguments:(id)firstObject,...;
@end
实施
@implementation NSArray (JavaScriptArray)
- (NSArray *)splice:(NSUInteger)index remove:(NSUInteger)remove count:(NSUInteger)count arguments:(id)firstObject,...
{
NSMutableArray *mSplice = [NSMutableArray arrayWithArray:self];
if (remove != 0) {
NSUInteger removeIndex = index;
for (NSUInteger i = 0; i < remove; i++) {
[mSplice removeObjectAtIndex:removeIndex];
removeIndex = removeIndex + 1;
}
}
if (count != 0) {
NSUInteger addIndex = index;
id eachObject;
va_list argumentList;
if (firstObject) {
[mSplice insertObject:firstObject atIndex:addIndex];
addIndex = addIndex + 1;
va_start(argumentList, firstObject);
eachObject = va_arg(argumentList, id);
for (NSUInteger i = 0; i < count; i++) {
[mSplice insertObject:eachObject atIndex:addIndex];
addIndex = addIndex + 1;
}
va_end(argumentList);
}
}
return [NSArray arrayWithArray:mSplice];
}
@end
调用方法
- (void)viewDidLoad
{
[super viewDidLoad];
NSArray *fruit = @[@"Banana", @"Orange", @"Apple", @"Mango"];
NSArray *fruitSplice = [fruit splice:2 remove:0 count:4 arguments:@"Lemon", @"Kiwi", @"Kiwi", @"Kiwi"];
NSLog(@"fruitSplice %@", fruitSplice);
}
@end
调试器Window
fruitSplice (
Banana,
Orange,
Lemon,
Kiwi,
Kiwi,
Kiwi,
Kiwi,
Apple,
Mango
)
删除 count
参数没有问题,因为实际上您的 "add" 循环似乎不正确。在您使用 eachObject = va_arg(argumentList, id);
从 va_list
中获得第二个项目后,您再也不会获得另一个对象。您的示例起作用的唯一原因是所有后面的项目都相同:@"Kiwi"
。如果您的测试电话是
NSArray *fruitSplice = [fruit splice:2
remove:0
count:4
arguments:@"Lemon", @"Albatross", @"Kiwi", @"Kiwi"];
你会看到
fruitSplice (
Banana,
Orange,
Lemon,
Albatross,
Albatross,
Albatross,
Albatross,
Apple,
Mango
)
作为输出。
您需要重做 va_list
的解包,并且您可以在迭代它时保留自己的计数器,但要注意的是必须有一个 sentinel 值:一个不可能作为有效列表值出现的值,表示您已经到了最后。对于对象类型的可变参数,您通常会使用 nil
作为标记。
当您使用 va_list
时,您必须 哨兵 或 计数。您没有其他方法可以知道何时停止弹出参数。
你的签名可以变成*:
- (NSArray *)KRSpliceAt:(NSUInteger)index
removingCount:(NSUInteger)remove
addingObjects:(id)firstObject, ... NS_REQUIRES_NIL_TERMINATION;
NS_REQUIRES_NIL_TERMINATION
是严格可选的,但如果在没有标记的情况下调用该方法,编译器会通知您。
然后你的添加循环改变:
// Insertion index starts at given splice point
NSUInteger addIndex = index;
// Initialize the va_list
va_list objs;
va_start(objs, firstObj);
// Start at the beginning
id nextObj = firstObj;
// Test for sentinel nil
while( nextObj ){
[mSplice insertObject:nextObj atIndex:addIndex];
// Update insertion point
addIndex++;
// Get next argument
nextObj = va_arg(objs, id);
}
// Signal completion of list
va_end(objs);
*您添加到 类 您不拥有的方法应始终加上前缀。这有点烦人,但如果您碰巧选择了与另一个方法相同的名称,这是防止灾难性冲突的好习惯。