在ARC中伪造va_list
我需要在iOS应用程序中创build一个虚拟的va_list
传递给一个NSString的initWithFormat:arguments:
function,这是我的代码:
NSArray *fixedArguments = [[NSArray alloc] initWithArray:arguments]; NSRange range = NSMakeRange(0, [fixedArguments count]); va_list fakeArgList = (va_list)malloc(sizeof(NSString *) * [fixedArguments count]); __unsafe_unretained id *ptr = (__unsafe_unretained id *)fakeArgList; [fixedArguments getObjects:ptr range:range]; content = [[NSString alloc] initWithFormat:outputFormat arguments:(va_list)fakeArgList]; free(fakeArgList);
编译器会在cast行上抱怨这条消息:
error: cast of a non-Objective-C pointer type 'va_list' (aka 'char *') to '__unsafe_unretained id *' is disallowed with ARC
getObjects:range:
函数的定义如下:
- (void)getObjects:(id __unsafe_unretained [])objects range:(NSRange)range;
我已经尝试了一切,但仍然无法摆脱这个错误…
是否有一个解决scheme,创build一个虚拟的va_list
启用ARC? 我究竟做错了什么?
编辑:这不再工作。 正如在最初的答案中所预见的那样,ABI似乎已经从这个答案中改变了出来
玩了一下,并得到它的工作 – 双检查泄漏或遗弃的记忆,没有看到任何。
NSArray *fixedArguments = [[NSArray alloc] initWithObjects: @"foo", @"bar", @"baz", nil]; NSRange range = NSMakeRange(0, [fixedArguments count]); NSMutableData* data = [NSMutableData dataWithLength: sizeof(id) * [fixedArguments count]]; [fixedArguments getObjects: (__unsafe_unretained id *)data.mutableBytes range:range]; NSString* content = [[NSString alloc] initWithFormat: @"1: %@ 2: %@ 3: %@" arguments: data.mutableBytes]; NSLog(@"%@", content);
我喜欢(AB)像这样使用NSMutableData来获得保留/释放语义在任意一块内存上 – 这不一定与手头上的问题有关,但它是一个巧妙的小技巧。
作为未来读者的一个注意事项:像这样伪装va_list恰好适用于MacOS和iOS的当前ABI,但总的来说它不是可移植的,并不是一个好的方法。
如果你愿意为你的项目添加一点点快捷的话,这是可能的!
重要的是NSArray到[CVarArgType]
的映射,这是va_list
的快速等价物。 如果尝试将[AnyObject]
为[CVarArgType]
则会导致运行时崩溃,但通过map
我们可以明确地创build所需的列表。
其余的代码是我做的包装器,以便我可以从obj-c调用它。 你可以使用这种方式来调用任何你想调用的obj-c函数的包装。
@objc class StringFormat: NSObject { class func format(key: String, args: [AnyObject]) -> String { let locArgs: [CVarArgType] = args.map({ (arg: AnyObject) -> CVarArgType in if let iArg = (arg is NSNumber ? arg.intValue : nil) { return iArg } return arg as! CVarArgType }); return String(format: key, arguments: locArgs) } }