Dan Watkins
Dan Watkins

Reputation: 998

Implicitly construct NSString with std::string

When working with Objective-C++, I often find myself using initWithCString to convert from std::string to NSString. To simplify the process, I created a category on NSString as follows:

@implementation NSString (NSStringFromCPP)

+(NSString*)stringFromCppString:(std::string)cppString
{
    return [[NSString alloc] initWithCString:cppString.c_str() encoding:NSStringEncodingConversionAllowLossy];
}


-(std::string)cppString
{
    return std::string([self cStringUsingEncoding:NSStringEncodingConversionAllowLossy]);
}

@end

This allows for a fairly easy conversion between NSString and std::string in both directions. It seems there has to be a way to implicitly convert from std::string to NSString though. I understand that there is no such thing as a constructor in Objective-C, so how might the following be accomplished without having to use stringFromCppString

-(void)something:(NSString*)someString
{
    NSLog(@"%@", someString);
}


-(void)activity
{
    std::string activityName = "Calculator";
    [self something:[NSString stringFromCppString:activityName]];
}

In most cases, code making use of std::string can be separated from code using NSString. However, there is a fair amount of bridging that occurs, and the code becomes distracting with stringFromCppString all over the place.

Upvotes: 3

Views: 2263

Answers (2)

Jody Hagins
Jody Hagins

Reputation: 28349

You should pass std::string const & as the type for the parameter in your Obj-C method.

+(NSString*)stringFromCppString:(std::string const &)cppString;

Also, do not forget that when compiled as .mm, you can use normal C++, so you may want to consider something as simple as overloading...

std::string
cppString(char const *s)
{
  return s;
}

std::string const &
cppString(std::string const &s)
{
  return s;
}

std::string
cppString(NSString *s)
{
  return [self cStringUsingEncoding:DESIRED_ENCODING];
}

And the other way...

NSString *
objcString(char const *s)
{
  return [NSString stringWithCString:s encoding:DESIRED_ENCODING];
}

NSString *
objcString(std::string const &s)
{
  return objcString(s.c_str());
}

NSString *
objcString(NSString *s)
{
  return s;
}

Now, whenever you want a C++ std::string, just call cppString and whenever you want a Obj-C NSString, just call objcString, and you don't really have to care what the "real" string is...

Or, you could make your own string wrapper, with conversion operators, that you use... it would be pretty simple to do as well.

However, in general, you want probably your C++ to be C++, and your ObjC to be ObjC, and use .mm to act as a lightweight glue.

Upvotes: 3

Chuck
Chuck

Reputation: 237010

Objective-C doesn't provide any facilities to implicitly convert between types. In fact, it doesn't even have the concept of casting an object — since all objects are referred to by pointers, casts are just pointer casts that don't change the underlying data. The only way the language provides to convert an object into some other type is to call a method on the object.

Upvotes: 2

Related Questions