2011-11-26 58 views
4

我有一個廣泛使用wstring的庫。我需要使用NSLog輸出更改和外部數據是否有一種簡單的方法(不太昂貴)使用中間函數輸出wstring。 使用va_list將每個wstring轉換爲NSString是我現在能想到的唯一方法。尋找使用NSLog的最便宜的方式使用std :: wstring


編輯:更多精度。我有一個多平臺庫。我添加了一個日誌宏MYLog。


編輯 我必須從C++調用我的MYLog,我沒有在這一點上獲得的Objective-C。所以問題是我不能在調用MYLog之前轉換std :: wstring。


通過MYLog我希望能夠使用的NSLog或中間像如下:

MYLog("Received %ls(%d) from user %ls %ls cp: %ls /nRAW:/t%ls", 
     &d.name, d.id, &d.user.firstName, &d.user.lastName, 
     &d.caption, &d.rawText); 

Here(最初從here)我發現這個很好的補充的NSString:

@interface NSString (cppstring_additions) 
+(NSString*) stringWithwstring:(const std::wstring&)string; 
+(NSString*) stringWithstring:(const std::string&)string; 
-(std::wstring) getwstring; 
-(std::string) getstring; 
@end 


@implementation NSString (cppstring_additions) 

#if TARGET_RT_BIG_ENDIAN 
const NSStringEncoding kEncoding_wchar_t = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingUTF32BE); 
#else 
const NSStringEncoding kEncoding_wchar_t = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingUTF32LE); 
#endif 

+(NSString*) stringWithwstring:(const std::wstring&)ws 
{ 
    char* data = (char*)ws.data(); 
    unsigned size = ws.size() * sizeof(wchar_t); 

    NSString* result = [[NSString alloc] initWithBytes:data length:size encoding:kEncoding_wchar_t]; 
    return result; 
} 

+(NSString*) stringWithstring:(const std::string&)s 
{ 
    NSString* result = [[NSString alloc] initWithUTF8String:s.c_str()]; 
    return result; 
} 

-(std::wstring) getwstring 
{ 
    NSData* asData = [self dataUsingEncoding:kEncoding_wchar_t]; 
    return std::wstring((wchar_t*)[asData bytes], [asData length]/sizeof(wchar_t)); 
} 

-(std::string) getstring 
{ 
    return [self UTF8String]; 
} 

@end 

所有我能想到的並不會浪費太多時間(我的)是創建一箇中間函數,由我的MYLog調用:

#define LAD(data) [logString appendFormat:[NSString stringWithFormat:@"%%%@", c], data] 
#define LAP(type) LAD(va_arg(listPointer, type)) 

void MyLogImplementation(NSString* message, ...) 
{ 
NSMutableString* logString = [[NSMutableString alloc] init]; 

    va_list listPointer; 
    va_start(listPointer, message); 

NSArray* lmc = [message componentsSeparatedByString:@"%"]; 

int counter = 0; 
//NSLog(@"there are %d components in %@.", [lmc count], message); 
BOOL ignoreNext = NO; 
for (NSString* c in lmc) 
{ 
    //NSLog(@"Testing %@", c); 

    if (ignoreNext) 
    { 
     [logString appendFormat:@"%%%@", c]; 
     ignoreNext = NO; 
    } 
    if (0 == [c length]) 
    { 
     ignoreNext = !ignoreNext; 
    } 
    else if (0 == counter && '%' != [message characterAtIndex:0]) 
    { 
     [logString appendFormat:@"%@", c]; 
    } 
    else 
    { 
     switch ([c characterAtIndex:0]) 
     { 
      case 'd': 
      case 'i': 
       LAP(int); 
       break; 

      case 'X': 
      case 'x': 
       LAP(int); 
       break; 

      case '@': 
       LAP(NSObject*); 
       break; 

      case 'f': 
       LAP(double); 
       break; 

      case 'c': 
       LAP(char); 
       break; 

      case 'l': 
       switch ([c characterAtIndex:1]) 
      { 
       case 's': 
       { 
        std::wstring* str = va_arg(listPointer, std::wstring*); 
        NSString* nstr = [NSString stringWithwstring:str]; 

        [logString appendFormat:@"%@", nstr]; 

        [nstr release]; 
        if (2 < [c length]) 
        { 
         [logString appendString:[c substringFromIndex:2]]; 
        } 
       } 
        break; 
      } 
       break; 
      default: 
       [logString appendFormat:[NSString stringWithFormat:@"%%%@", c]]; 

     } 
    } 
    ++counter; 
} 


    NSLog(@"%@", logString); 
[logString release]; 
    va_end(listPointer); 
} 

但是這個 - 在我看來 - 是非常低效的。有沒有更好的方式來實現我在做什麼?我知道我可以簡單地將其轉換爲:

NSLog(@"Received %@(%d) from user %@ %@ cp: %@ /nRAW:/t%@", 
     [NSString stringWithwstring:d.name], d.id, 
     [NSString stringWithwstring:d.user.firstName], 
     [NSString stringWithwstring:d.user.lastName], 
     [NSString stringWithwstring:d.caption], 
     [NSString stringWithwstring:d.rawText]); 

並且問題將被解決。但我會放棄多方面的優勢......我想。

+0

路過你能在的NSLog的詳細信息填寫要求 –

+0

@ AlfP.Steinbach是的......我說關於這個問題的更多細節。我知道我忽視了最明顯的解決方案,隱藏在多平臺修辭學背後,但是我真的很感謝能夠儘可能多地保留我的應用程序代碼,使其免受平臺依賴性的影響,並且儘可能多地隱藏我的實現層。 – Coyote

回答

4

你可以轉換爲NSString並記錄它。這是取自here的NSString類別。不知道是否能正常工作,但它看上去很聰明......

@interface NSString (wstring_additions) 
+(NSString*) stringWithwstring:(const std::wstring&)string; 
-(std::wstring) getwstring; 
@end 

@implementation NSString (wstring_additions) 

#if TARGET_RT_BIG_ENDIAN 
const NSStringEncoding kEncoding_wchar_t = 
CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingUTF32BE); 
#else 
const NSStringEncoding kEncoding_wchar_t = 
CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingUTF32LE); 
#endif 

+(NSString*) stringWithwstring:(const std::wstring&)ws 
{ 
    char* data = (char*)ws.data(); 
    unsigned size = ws.size() * sizeof(wchar_t); 

    NSString* result = [[[NSString alloc] initWithBytes:data length:size encoding:kEncoding_wchar_t] autorelease]; 
    return result; 
} 

-(std::wstring) getwstring 
{ 
    NSData* asData = [self dataUsingEncoding:kEncoding_wchar_t]; 
    return std::wstring((wchar_t*)[asData bytes], [asData length]/sizeof(wchar_t)); 
} 

@end 
+0

問題是,在大多數地方,我無法訪問NSLog和NSString(它主要是C++代碼,它應該是跨平臺的),我現在正在使用OSX實現,但它應該保持跨平臺。現在必須處理std :: wstring是我必須承擔的一個負擔,直到我找到另一個解決方案。目前我調用MYLog(blahblah),它調用一個可以訪問Objective C的extern C++函數。這就是爲什麼我不能簡單地使用'NSLog(@「Received%@」,[NSString stringWithwstring:d.name]); ' – Coyote

1

或許,如果你將其轉換爲CFStringRef使用的CoreFoundation,然後傳遞到任何CFLog(..)或將其轉換爲的NSString *(免費橋接)以及使用NSLog(...)

CFStrings位於CoreFoundation中,它是一個C級API,因此應該可以從非objc域調用。

<CoreFoundation/CFString.h>包含CFStringCreateWithBytes(...)或許CFStringCreateWithCString(...)並在適當的CFStringEncoding

+0

我會盡量擺脫wstring ...但在此期間,我會嘗試你的解決方案。也許有一些宏,我應該能夠擺脫它... – Coyote

+0

我不認爲你需要擺脫wstring。如果你可以根據目標條件包含(也許在iOS/MacOS上使用#define標記),那麼只要包含核心基礎頭文件(如果已設置),然後在同一個定義中使用#ifdef以使日誌記錄函數調用CF例程和CFLog (..)電話。請記住,如果使用CFStringCreate ...(使用CFRelease)創建該字符串並檢查從創建例程(失敗情況)返回的NULL,則釋放該字符串,因此您不會將NULL傳遞給CFLog(..)或CFRelease(.. )。 – Dad