Look for the cheapest way to use std :: wstring with NSLog

I have a library that uses wstring extensively. I need to output changes and external data using NSLog. There is a simple way (not too expensive) for wstring output using an intermediate function. Converting each wstring to an NSString using va_list is the only way I can think of right now.


Edit : Additional fixes. I have a multi-platform library. I added the MYLog registration macro.


Edit I need to call MYLog from C ++, and I do not have access to Objective-C at this point. So the problem is that I cannot convert std :: wstring before calling MYLog.


Through MYLog, I would like to be able to use NSLog or intermediate, for example:

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 (originally from here ) I found this nice addition to 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 

All I could think about without spending too much time (mine) was to create an intermediate function called my 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); } 

But this, it seems to me, is very inefficient. Is there a better way to achieve what I am doing? I know that I can just convert this to:

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

And the problem will be solved. But I would lose the advantage in the movie ... I think.

+4
source share
2 answers

You can convert to NSString and write this. This is the NSString category, taken from here . I don’t know how well this works, but it looks reasonable ...

 @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 
+4
source

Perhaps if you convert it to CFStringRef using CoreFoundation, then pass it either to CFLog (..), or apply it to NSString * (over a free bridged connection) and use NSLog (...)

CFStrings are in CoreFoundation, which is a level C API and therefore must be called from the ground without objc.

<CoreFoundation/CFString.h> contains CFStringCreateWithBytes(...) or possibly CFStringCreateWithCString(...) and passes the corresponding CFStringEncoding

+1
source

Source: https://habr.com/ru/post/1383180/


All Articles