I need to return a collection of strings from Objective-C to C# and can't wrap my head around how to do this properly. When I print the returned pointer on managed side its value is 0.
Objective-c
FOUNDATION_EXPORT int _GetAllKeys(char** pointer)
{
NSArray* array = @[@"key1", @"key2"]; // dummy strings
int size = (int)array.count;
pointer = malloc(size * sizeof(char *));
for (int i = 0; i < size; i++)
{
pointer[i] = MakeStringCopy(array[i]);
}
return size;
}
C#
[DllImport("__Internal")]
private static extern int _GetAllKeys(out IntPtr buffer);
internal static IEnumerable<string> GetAllKeys()
{
int count = _GetAllKeys(out var buffer);
List<string> keys = new List<string>();
for (int i = 0; i < count; i++)
{
keys.Add(Marshal.PtrToStringUTF8(IntPtr.Add(buffer, IntPtr.Size))); //eventually when i make this work the strings will be returned as UTF8 but for now its not even making it to this line, so ignore the encoding.
}
return keys;
}
---------------- SOLUTION ----------------
Objective-c
FOUNDATION_EXPORT int _GetAllKeys(char*** pointer)
{
NSArray* array = @[@"key1", @"key2"];
int size = (int)array.count;
*pointer = malloc(size * sizeof(char *));
for (int i = 0; i < size; i++)
{
(*pointer)[i] = MakeStringCopy(array[i]);
}
return size;
}
C#
[DllImport("__Internal")]
private static extern int _GetAllKeys(out IntPtr buffer);
internal static IEnumerable<string> GetAllKeys()
{
int count = _GetAllKeys(out var buffer);
List<string> keys = new List<string>();
for (int i = 0; i < count; i++)
{
IntPtr ptr = Marshal.ReadIntPtr(buffer);
keys.Add(Marshal.PtrToStringAuto(ptr));
buffer = IntPtr.Add(buffer, IntPtr.Size);
}
return keys;
}
You are trying to return a char**, so the C function parameter needs to be a char***:
FOUNDATION_EXPORT int _GetAllKeys(char*** pointer)
{
NSArray* array = @[@"key1", @"key2"]; // dummy strings
int size = (int)array.count;
*pointer = malloc(size * sizeof(char *));
for (int i = 0; i < size; i++)
{
(*pointer)[i] = MakeStringCopy(array[i]);
}
return size;
}
The C# code looks fine, except that IntPtr.Add returns a new IntPtr, so it has to be:
keys.Add(Marshal.PtrToStringUTF8(buffer));
buffer = IntPtr.Add(buffer, IntPtr.Size);