【问题标题】:How to convert from char* to id* with ARC enabled如何在启用 ARC 的情况下从 char* 转换为 id*
【发布时间】:2011-10-27 16:15:01
【问题描述】:

我正在尝试使用here 描述的技术构建“假”变量参数列表,但对于启用 ARC 的项目,我无法弄清楚如何摆脱我遇到的错误。

这是有问题的代码:

NSMutableArray* argumentsArray = [NSMutableArray array];

// ... Here I fill argumentsArray with some elements
// And then, I want to construct a "fake" variable argument list

char* fakeArgList = (char*) malloc( sizeof(NSString*) * [argumentsArray count]); 
[argumentsArray getObjects: (id*) fakeArgList];

NSString* content = [[NSString alloc] initWithFormat: formatString arguments:fakeArgList]; 

XCode 抱怨 (id) fakeArgList* 转换,说:

将非 Objective-C 指针类型 'char *' 转换为 '_autoreleasing id *' ARC 不允许使用

我最初的理论是我只需要添加 __unsafe_unretained 到 (id*) 转换告诉 ARC 我负责该内存块并且它不应该保留/释放它,但这不起作用并且我不知道如何解决这个问题。

更新:这是完整的功能。它应该采用 printf 样式的格式字符串和 .plist 中的字段名称变量列表,并输出带有从 .plist 加载的数据的格式化字符串。即,如果我有一个带有字段“field1”=“foo”和“field2”=3 的 .plist 文件并且我调用[loadStringFromFixture: @"?param1=%@&param2=%d", @"field1", @field2],那么我应该得到字符串“?param1=foo&param2=3”

- (NSString*) loadStringFromFixture:(NSString*) format, ...
{
    NSString* path = [[NSBundle mainBundle] bundlePath];
    NSString* finalPath = [path stringByAppendingPathComponent:@"MockAPI-Fixtures.plist"];
    NSDictionary* plistData = [NSDictionary dictionaryWithContentsOfFile:finalPath];

    va_list argumentsList;    
    va_start(argumentsList, format);

    NSString* nextArgument;
    NSMutableArray* argumentsArray = [NSMutableArray array];

    while((nextArgument = va_arg(argumentsList, NSString*)))
    {
        [argumentsArray addObject: [plistData objectForKey:nextArgument]];
    }

    NSRange myRange = NSMakeRange(0, [argumentsArray count]);

    id* fakeArgList = (__bridge id *)malloc(sizeof(NSString *) * [argumentsArray count]); 
    [argumentsArray getObjects:fakeArgList range:myRange];
    NSString * content = [[NSString alloc] initWithFormat:formatString
                                                arguments:(__bridge va_list)fakeArgList];

    free(fakeArgList);

    return content;
}

【问题讨论】:

  • 必须有更好的方法来做到这一点......
  • 说真的;快速阅读源文章让我认为它只是巧合,超出了 ABI 或规范的范围。
  • 没错,但我只需要它用于我的单元测试代码,所以我不太关心它是一个非常“肮脏的黑客”这一事实。虽然如果有人能指出构建变量参数列表的更好方法,我真的很感兴趣。
  • 试试__builtin_va_arg_pack 记录在Constructing Calls 中,也许? ARC 始终将对象指针限制为有效或 nil
  • 更笼统地说:您应该问一个关于您正在尝试做什么以及如何完成的问题。这是一种方法,但另一种方法可能根本不需要这样做。

标签: objective-c automatic-ref-counting


【解决方案1】:

看看这段代码,这似乎是一个非常肮脏的黑客,但我想如果它在没有 ARC 的情况下工作,它也应该在 ARC 下工作。这里的问题是你正在从 C 指针转换为 Objective-C 指针,如果没有桥接,你就无法做到这一点:

NSMutableArray * argumentsArray = [NSMutableArray array];

// ... Here I fill argumentsArray with some elements
// And then, I want to construct a "fake" variable argument list

NSRange myRange = NSMakeRange(0, [argumentsArray count]);
id * fakeArgList = (__bridge id *)malloc(sizeof(NSString *) * [argumentsArray count]); 
[argumentsArray getObjects:fakeArgList range:myRange];
NSString * content = [[NSString alloc] initWithFormat:formatString
                                            arguments:(__bridge va_list)fakeArgList];
free(fakeArgList);

这还是挺难看的,真心希望有更好的方法来做,不过既然是单元测试,估计还是得做吧。

编辑:桥接演员可能应该这样做:

id __autoreleasing * fakeArgList = (__bridge id __autoreleasing *)malloc(sizeof(NSString *) * [argumentsArray count]);

【讨论】:

  • 该代码仍然出现编译器错误。它抱怨“不兼容的类型将“void *”转换为“__autoreleasing id *”,并在 malloc 行上使用 __bridge cast。
  • 我的编辑可能是您的解决方案,也可能完全关闭。看看就知道了。
猜你喜欢
  • 2012-06-20
  • 2016-03-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-27
  • 2011-12-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多