10

I am creating an iOS Plugin which needs to return a string (or const char*) to Unity. How do I implement it ?

Rohith Srinivas
  • 155
  • 1
  • 4
  • 12

2 Answers2

7

I'd like to clarify previous answer. C# declaration:

[DllImport("__Internal")]
private static extern string getString();

Returning a string from objc is exactly like @Cabrra said:

char* convertNSStringToCString(const NSString* nsString)
{
    if (nsString == NULL)
        return NULL;

    const char* nsStringUtf8 = [nsString UTF8String];
    //create a null terminated C string on the heap so that our string's memory isn't wiped out right after method's return
    char* cString = (char*)malloc(strlen(nsStringUtf8) + 1);
    strcpy(cString, nsStringUtf8);

    return cString;
}

extern "C" char* getString()
{
    const NSString* str = @"string";
    return convertNSStringToCString(str);
}

Though some people mentioned that this way will lead to a memory leak that is not right. This way works fine in Unity and no leaks occurs (I tested it many times). Unity clearly states that

String values returned from a native method should be UTF–8 encoded and allocated on the heap. Mono marshalling calls free for strings like this.

Shpand
  • 661
  • 9
  • 14
5
    extern "C"
{
    int _pow2(int x)
    {
        // Just a simple example of returning an int value
        return x * x;
    }

    // Returns a char* (a string to Unity)
    char* _helloWorldString()
    {
        // We can use NSString and go to the c string that Unity wants
        NSString *helloString = @"Hello World";
        // UTF8String method gets us a c string. Then we have to malloc a copy to give to Unity. I reuse a method below that makes it easy.
        return cStringCopy([helloString UTF8String]);
    }

    // Here is an example of getting a string from Unity
    char* _combineStrings(const char* cString1, const char* cString2)
    {
        // This shows we can create two NSStrings* from the c strings from Unity
        NSString *string1 = CreateNSString(cString1);
        NSString *string2 = CreateNSString(cString2);
        NSString *combinedString = [NSString stringWithFormat:@"%@ %@", string1, string2];
        // Same as before, have to go to a c string and then malloc a copy of it to give to Unity
        return cStringCopy([combinedString UTF8String]);
    }
}

//I also like to include these two convenience methods to convert between c string and NSString*. You need to return a copy of the c string so that Unity handles the memory and gets a valid value.

char* cStringCopy(const char* string)
{
    if (string == NULL)
        return NULL;

    char* res = (char*)malloc(strlen(string) + 1);
    strcpy(res, string);

    return res;
}

// This takes a char* you get from Unity and converts it to an NSString* to use in your objective c code. You can mix c++ and objective c all in the same file.
static NSString* CreateNSString(const char* string)
{
    if (string != NULL)
        return [NSString stringWithUTF8String:string];
    else
        return [NSString stringWithUTF8String:""];
}
Vinny Coyne
  • 2,365
  • 15
  • 24
Cabrra
  • 644
  • 3
  • 14
  • 28
  • 2
    Remember to free the string again after the bytes are turned into a managed string or there will be memory leaks if you keep using malloc, the string needs to be freed in the c# code with Marshal.FreeHGlobal I believe. – Chris May 05 '16 at 15:20
  • "You need to return a copy of the c string so that Unity handles the memory and gets a valid value". Does it mean that Unity automatically handles memory management? I agree with @Chris that malloc needs be freed to avoid memory leaks. Chris how can I free the C-malloced memory within C#? Can you give more details about Marhsal.FreeGlobal? – Andrea Gorrieri Jul 08 '19 at 11:49
  • cStringCopy helped me a lot for passing Objective-C NSString back to C# (Unity) – Michael DiCioccio Sep 23 '19 at 22:02
  • 1
    @AndreaGorrieri Only to clarify: the signature of ```_helloWorldString``` in C# code would be: ```static extern string _helloWorldString();```. So the `char*` returns to Unity as a managed `string` and no free is needed, it will be deallocated automatically by the system. – LoDani Dec 02 '19 at 18:25
  • 1
    BTW `cStringCopy()` is exactly the same as `strdup()` that's been in the standard C library since the late 1960's. – trojanfoe Apr 08 '20 at 06:34