va_list 在 iOS 64 位模拟器上输入
va_list type on iOS 64-bit Simulator
我的以下代码在 64 位 iOS 模拟器上不起作用。它在以下行 EXC_BAD_ACCESS
[invocation setArgument:args atIndex:index];
中崩溃
但此代码适用于所有 32 位和 64 位 iPhone 和 iPad 设备,甚至适用于 32 位模拟器。
到目前为止,我发现转换为 char*
可能是错误的来源。 va_list
似乎是 char*
类型,除了在 64 位 iOS 模拟器上。
我该如何避免这个错误?这会导致设备出现问题吗?
+(NSInvocation*)invocationWithTarget:(id)target selector:(SEL)aSelector
retainArguments:(BOOL)retainArguments, ...;
{
va_list ap;
va_start(ap, retainArguments);
char* args = (char*)ap;
NSMethodSignature* signature = [target methodSignatureForSelector:aSelector];
NSInvocation* invocation = [NSInvocation invocationWithMethodSignature:signature];
if (retainArguments) {
[invocation retainArguments];
}
[invocation setTarget:target];
[invocation setSelector:aSelector];
for (int index = 2; index < [signature numberOfArguments]; index++) {
const char *type = [signature getArgumentTypeAtIndex:index];
NSUInteger size, align;
NSGetSizeAndAlignment(type, &size, &align);
NSUInteger mod = (NSUInteger)args % align;
if (mod != 0) {
args += (align - mod);
}
[invocation setArgument:args atIndex:index];
args += size;
}
va_end(ap);
return invocation;
}
我认为问题出在 args += (align - mod);
,va_arg
的工作原理未知,可能是两个版本的编译器不同。我建议使用 va_arg
而不是自己移动 args
的指针。
这种方式你必须使用Objective-C对象作为参数,因为我们假设它们的类型是id
。
+ (NSInvocation*)invocationWithTarget:(id)target selector:(SEL)aSelector
retainArguments:(BOOL)retainArguments, ...
{
va_list ap;
va_start(ap, retainArguments);
NSMethodSignature* signature = [target methodSignatureForSelector:aSelector];
NSInvocation* invocation = [NSInvocation invocationWithMethodSignature:signature];
if (retainArguments) {
[invocation retainArguments];
}
[invocation setTarget:target];
[invocation setSelector:aSelector];
for (int index = 2; index < [signature numberOfArguments]; index++) {
id argument = va_arg(ap, id) ;
[invocation setArgument:&argument atIndex:index];
}
va_end(ap);
return invocation;
}
我相信我们可以更好地使用 const char *type = [signature getArgumentTypeAtIndex:index];
并使用一些方法来解码可以传递给 va_arg
的类型,但我没有找到实现该目标的解决方案。
我的以下代码在 64 位 iOS 模拟器上不起作用。它在以下行 EXC_BAD_ACCESS
[invocation setArgument:args atIndex:index];
但此代码适用于所有 32 位和 64 位 iPhone 和 iPad 设备,甚至适用于 32 位模拟器。
到目前为止,我发现转换为 char*
可能是错误的来源。 va_list
似乎是 char*
类型,除了在 64 位 iOS 模拟器上。
我该如何避免这个错误?这会导致设备出现问题吗?
+(NSInvocation*)invocationWithTarget:(id)target selector:(SEL)aSelector
retainArguments:(BOOL)retainArguments, ...;
{
va_list ap;
va_start(ap, retainArguments);
char* args = (char*)ap;
NSMethodSignature* signature = [target methodSignatureForSelector:aSelector];
NSInvocation* invocation = [NSInvocation invocationWithMethodSignature:signature];
if (retainArguments) {
[invocation retainArguments];
}
[invocation setTarget:target];
[invocation setSelector:aSelector];
for (int index = 2; index < [signature numberOfArguments]; index++) {
const char *type = [signature getArgumentTypeAtIndex:index];
NSUInteger size, align;
NSGetSizeAndAlignment(type, &size, &align);
NSUInteger mod = (NSUInteger)args % align;
if (mod != 0) {
args += (align - mod);
}
[invocation setArgument:args atIndex:index];
args += size;
}
va_end(ap);
return invocation;
}
我认为问题出在 args += (align - mod);
,va_arg
的工作原理未知,可能是两个版本的编译器不同。我建议使用 va_arg
而不是自己移动 args
的指针。
这种方式你必须使用Objective-C对象作为参数,因为我们假设它们的类型是id
。
+ (NSInvocation*)invocationWithTarget:(id)target selector:(SEL)aSelector
retainArguments:(BOOL)retainArguments, ...
{
va_list ap;
va_start(ap, retainArguments);
NSMethodSignature* signature = [target methodSignatureForSelector:aSelector];
NSInvocation* invocation = [NSInvocation invocationWithMethodSignature:signature];
if (retainArguments) {
[invocation retainArguments];
}
[invocation setTarget:target];
[invocation setSelector:aSelector];
for (int index = 2; index < [signature numberOfArguments]; index++) {
id argument = va_arg(ap, id) ;
[invocation setArgument:&argument atIndex:index];
}
va_end(ap);
return invocation;
}
我相信我们可以更好地使用 const char *type = [signature getArgumentTypeAtIndex:index];
并使用一些方法来解码可以传递给 va_arg
的类型,但我没有找到实现该目标的解决方案。