2011-11-26 55 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

相关问题