2011-11-21 30 views
16

我需要在iOS應用程序假va_list傳遞到的NSString initWithFormat:arguments:函數來創建,這是我的代碼:假的va_list

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); 

編譯器與投行此消息抱怨:

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; 

我已經嘗試了一切,但仍然無法擺脫這個錯誤...

是否有解決方案創建一個假ARC va_list啓用?我究竟做錯了什麼?

回答

30

編輯:這不再起作用。正如在最初的答案中所預見的那樣,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,但通常它不是便攜式的,也不是一個好方法。

+0

太感謝你了...... 我建設,鑑於字典的plist中包含數組選擇器視圖,打印格式,讓我們說'「(%@ - %@)%@」' ,並使用從plist文件中提取數據的格式化字符串填充選擇器視圖。 我發現使用具有變量列表參數的格式化打印的唯一方法是僞造一個va_list。 我知道它遠不是簡單的編程,但我不能提出更好的解決方案,任何有效的替代方案都非常受歡迎,我想我會發布有關我的問題的另一個問題,以找到更清晰的解決方案。 – Scakko

+0

如果您始終使用%@並且沒有使用任何其他大小的參數,則只需在字符串中搜索%@的實例並將其替換爲每個參數的[對象描述]即可。同樣的效果,沒有假的va_list。但是這不適用於數字格式或其他任何東西,除非你想做很多額外的工作。 – ipmcc

+0

今天我試試看,非常感謝你... – Scakko

0

如果您願意爲您的項目添加一點點快捷,它是可能的!

重要的是NSArray到[CVarArgType]的映射,這是va_list的快速等價物。如果您嘗試將[AnyObject]轉換爲[CVarArgType],則會導致運行時崩潰,但通過map,我們可以明確地創建所需的列表。

其餘的代碼是我所做的包裝,以便我可以從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) 
    } 
}