diff --git a/docs/website/mmp-errors.md b/docs/website/mmp-errors.md
index d80b4cffeb..c8b9c0c3dc 100644
--- a/docs/website/mmp-errors.md
+++ b/docs/website/mmp-errors.md
@@ -776,6 +776,16 @@ If the managed binding is from a third-party vendor, please contact the vendor.
If the managed binding is shipped with Xamarin.Mac, please [submit an issue](https://github.com/xamarin/xamarin-macios/wiki/Submitting-Bugs-&-Suggestions).
+
+
+### MM8032: Unable to convert from a managed array of {type} to an NSArray.
+
+This usually indicates a bug in Objective-C binding code.
+
+If the managed binding is from a third-party vendor, please contact the vendor.
+
+If the managed binding is shipped with Xamarin.Mac, please [submit an issue](https://github.com/xamarin/xamarin-macios/wiki/Submitting-Bugs-&-Suggestions).
+
### MM8033: Unable to marshal the return value of type {type} to Objective-C.
diff --git a/docs/website/mtouch-errors.md b/docs/website/mtouch-errors.md
index 1a2eaedbfc..72b02fb3b5 100644
--- a/docs/website/mtouch-errors.md
+++ b/docs/website/mtouch-errors.md
@@ -3565,6 +3565,16 @@ If the managed binding is from a third-party vendor, please contact the vendor.
If the managed binding is shipped with Xamarin.iOS, please [submit an issue](https://github.com/xamarin/xamarin-macios/wiki/Submitting-Bugs-&-Suggestions).
+
+
+### MT8032: Unable to convert from a managed array of {type} to an NSArray.
+
+This usually indicates a bug in Objective-C binding code.
+
+If the managed binding is from a third-party vendor, please contact the vendor.
+
+If the managed binding is shipped with Xamarin.iOS, please [submit an issue](https://github.com/xamarin/xamarin-macios/wiki/Submitting-Bugs-&-Suggestions).
+
### MT8033: Unable to marshal the return value of type {type} to Objective-C.
diff --git a/runtime/trampolines.m b/runtime/trampolines.m
index 3dd9a7a7f6..1d5a66b6aa 100644
--- a/runtime/trampolines.m
+++ b/runtime/trampolines.m
@@ -73,38 +73,10 @@ xamarin_marshal_return_value_impl (MonoType *mtype, const char *type, MonoObject
} else if (r_klass == mono_get_string_class ()) {
return xamarin_string_to_nsstring ((MonoString *) retval, retain);
} else if (xamarin_is_class_array (r_klass)) {
- MonoClass *e_klass = mono_class_get_element_class (r_klass);
- bool is_string = e_klass == mono_get_string_class ();
- MonoArray *m_arr = (MonoArray *) retval;
- int length = mono_array_length (m_arr);
- id *buf = (id *) malloc (sizeof (id) * length);
- NSArray *arr;
- int i;
- id v;
-
- for (i = 0; i < length; i++) {
- MonoObject *value = mono_array_get (m_arr, MonoObject *, i);
-
- if (is_string) {
- v = xamarin_string_to_nsstring ((MonoString *) value, false);
- } else {
- v = xamarin_get_handle (value, exception_gchandle);
- if (*exception_gchandle != 0) {
- free (buf);
- return NULL;
- }
- }
- buf[i] = v;
- }
-
- arr = [[NSArray alloc] initWithObjects: buf count: length];
-
- free (buf);
-
- if (!retain)
- [arr autorelease];
-
- return (void *) arr;
+ NSArray *rv = xamarin_managed_array_to_nsarray ((MonoArray *) retval, NULL, r_klass, exception_gchandle);
+ if (retain && rv)
+ [rv retain];
+ return rv;
} else if (xamarin_is_class_nsobject (r_klass)) {
id i = xamarin_get_handle (retval, exception_gchandle);
if (*exception_gchandle != 0)
@@ -133,6 +105,15 @@ xamarin_marshal_return_value_impl (MonoType *mtype, const char *type, MonoObject
}
}
+static guint32
+xamarin_get_exception_for_element_conversion_failure (guint32 inner_exception_gchandle, int index)
+{
+ guint32 exception_gchandle = 0;
+ char *msg = xamarin_strdup_printf ("Failed to marshal the value at index %i.", index);
+ exception_gchandle = xamarin_create_product_exception_with_inner_exception (8036, inner_exception_gchandle, msg);
+ xamarin_free (msg);
+ return exception_gchandle;
+}
static guint32
xamarin_get_exception_for_return_value (int code, guint32 inner_exception_gchandle, SEL sel, MonoMethod *method, MonoType *returnType)
@@ -921,6 +902,72 @@ id xamarin_uioffset_to_nsvalue (MonoObject *value, void *context,
#pragma clang diagnostic pop
+id
+xamarin_convert_string_to_nsstring (MonoObject *obj, void *context, guint32 *exception_gchandle)
+{
+ return xamarin_string_to_nsstring ((MonoString *) obj, false);
+}
+
+id
+xamarin_object_to_nsobject (MonoObject *object, void *context, guint32 *exception_gchandle)
+{
+ return xamarin_get_nsobject_handle (object);
+}
+
+id
+xamarin_inativeobject_to_nsobject (MonoObject *object, void *context, guint32 *exception_gchandle)
+{
+ return xamarin_get_handle_for_inativeobject (object, exception_gchandle);
+}
+
+NSArray *
+xamarin_managed_string_array_to_nsarray (MonoArray *array, guint32 *exception_gchandle)
+{
+ return xamarin_convert_managed_to_nsarray_with_func (array, xamarin_convert_string_to_nsstring, 0, exception_gchandle);
+}
+
+NSArray *
+xamarin_managed_nsobject_array_to_nsarray (MonoArray *array, guint32 *exception_gchandle)
+{
+ return xamarin_convert_managed_to_nsarray_with_func (array, xamarin_object_to_nsobject, 0, exception_gchandle);
+}
+
+NSArray *
+xamarin_managed_inativeobject_array_to_nsarray (MonoArray *array, guint32 *exception_gchandle)
+{
+ return xamarin_convert_managed_to_nsarray_with_func (array, xamarin_inativeobject_to_nsobject, 0, exception_gchandle);
+}
+
+NSArray *
+xamarin_managed_array_to_nsarray (MonoArray *array, MonoType *managed_type, MonoClass *managed_class, guint32 *exception_gchandle)
+{
+ if (array == NULL)
+ return NULL;
+
+ if (managed_class == NULL)
+ managed_class = mono_class_from_mono_type (managed_type);
+
+ MonoClass *e_klass = mono_class_get_element_class (managed_class);
+
+ if (e_klass == mono_get_string_class ()) {
+ return xamarin_managed_string_array_to_nsarray (array, exception_gchandle);
+ } else if (xamarin_is_class_nsobject (e_klass)) {
+ return xamarin_managed_nsobject_array_to_nsarray (array, exception_gchandle);
+ } else if (xamarin_is_class_inativeobject (e_klass)) {
+ return xamarin_managed_inativeobject_array_to_nsarray (array, exception_gchandle);
+ }
+
+ // Don't know how to convert: show an exception.
+ char *element_name = xamarin_type_get_full_name (mono_class_get_type (e_klass), exception_gchandle);
+ if (*exception_gchandle != 0)
+ return NULL;
+ char *msg = xamarin_strdup_printf ("Unable to convert from a managed array of %s to an NSArray.", element_name);
+ *exception_gchandle = xamarin_create_product_exception_with_inner_exception (8032, *exception_gchandle, msg);
+ xamarin_free (msg);
+ xamarin_free (element_name);
+ return NULL;
+}
+
static void *
xamarin_get_nsnumber_converter (MonoClass *managedType, MonoMethod *method, bool to_managed, guint32 *exception_gchandle)
{
diff --git a/runtime/xamarin/trampolines.h b/runtime/xamarin/trampolines.h
index f869af2a7d..0cb5998b43 100644
--- a/runtime/xamarin/trampolines.h
+++ b/runtime/xamarin/trampolines.h
@@ -179,10 +179,21 @@ id xamarin_uiedgeinsets_to_nsvalue (MonoObject *value, void *context,
id xamarin_uioffset_to_nsvalue (MonoObject *value, void *context, guint32 *exception_gchandle);
id xamarin_nsdirectionaledgeinsets_to_nsvalue(MonoObject *value, void *context, guint32 *exception_gchandle);
+// These functions can be passed as xamarin_id_to_managed_func/xamarin_managed_to_id_func parameters
+id xamarin_convert_string_to_nsstring (MonoObject *obj, void *context, guint32 *exception_gchandle);
+
+// These are simpler versions of the above string<->nsstring conversion functions.
NSString * xamarin_string_to_nsstring (MonoString *obj, bool retain);
// domain is optional, if NULL the function will call mono_get_domain.
MonoString * xamarin_nsstring_to_string (MonoDomain *domain, NSString *obj);
+// Either managed_type or managed_class has to be provided
+NSArray * xamarin_managed_array_to_nsarray (MonoArray *array, MonoType *managed_type, MonoClass *managed_class, guint32 *exception_gchandle);
+
+NSArray * xamarin_managed_string_array_to_nsarray (MonoArray *array, guint32 *exception_gchandle);
+NSArray * xamarin_managed_nsobject_array_to_nsarray (MonoArray *array, guint32 *exception_gchandle);
+NSArray * xamarin_managed_inativeobject_array_to_nsarray (MonoArray *array, guint32 *exception_gchandle);
+
/* Copied from SGen */
static inline void