Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 46 additions & 22 deletions src/Foundation/NSArray.cs
Original file line number Diff line number Diff line change
Expand Up @@ -675,6 +675,17 @@ static bool TryGetItem<T> (NativeHandle elementHandle, Converter<NativeHandle, T
return ArrayFromHandle<T> (handle, createObject, NSNullBehavior.Drop, releaseHandle)!;
}

/// <summary>Returns a strongly-typed C# array from a handle to an NSArray, dropping null elements.</summary>
/// <typeparam name="T">Parameter type, determines the kind of array returned.</typeparam>
/// <param name="handle">Pointer (handle) to the unmanaged object.</param>
/// <param name="nsNullElementBehavior">How to handle null and NSNull elements in the native array.</param>
/// <param name="releaseHandle">Whether the native NSArray instance should be released before returning or not.</param>
/// <returns>A C# array with the values (excluding null elements). Returns <see langword="null" /> if the handle is <see cref="NativeHandle.Zero" />.</returns>
internal static T []? ArrayFromHandleDropNullElements<T> (NativeHandle handle, NSNullBehavior nsNullElementBehavior, bool releaseHandle = false) where T : class, INativeObject
{
return ArrayFromHandle<T> (handle, (h) => Runtime.GetINativeObject<T> (h, false)!, nsNullElementBehavior, releaseHandle)!;
}

/// <summary>Returns a strongly-typed C# array from a handle to an NSArray, dropping null elements and guaranteeing a non-null return value.</summary>
/// <typeparam name="T">Parameter type, determines the kind of array returned.</typeparam>
/// <param name="handle">Pointer (handle) to the unmanaged object.</param>
Expand Down Expand Up @@ -751,38 +762,51 @@ internal static T [] NonNullEnumsFromHandle<T> (NativeHandle handle) where T : S
(element) => (T) Enum.ToObject (typeof (T), Runtime.GetNSObject<NSNumber> (element)?.LongValue ?? 0));
}

#nullable disable
/// <typeparam name="T">Parameter type, determines the kind of
/// array returned, limited to NSObject and subclasses of it.</typeparam>
/// <param name="weakArray">Handle to an weakly typed NSArray.</param>
/// <summary>Returns a strongly-typed C# array of the parametrized type from a weakly typed NSArray.</summary>
/// <returns>An C# array with the values.</returns>
/// <remarks>
/// <para>Use this method to get a set of NSObject arrays from an NSArray.</para>
/// <example>
/// <code lang="c#"><![CDATA[
/// <summary>Creates a strongly-typed C# array from a weakly typed <see cref="NSArray" />.</summary>
/// <typeparam name="T">The element type for the returned array, limited to <see cref="NSObject" /> and subclasses.</typeparam>
/// <param name="weakArray">A weakly typed <see cref="NSArray" /> to convert, or <see langword="null" />.</param>
/// <returns>
/// A C# array of <typeparamref name="T" /> elements, or <see langword="null" /> if
/// <paramref name="weakArray" /> is <see langword="null" /> or a conversion error occurs.
/// Elements that are <see cref="NSNull" /> or not compatible with <typeparamref name="T" /> are excluded.
/// </returns>
/// <remarks>
/// <example>
/// <code lang="c#"><![CDATA[
/// NSArray someArray = ...;
///
/// NSString [] values = NSArray.FromArray<CGImage> (someArray);
/// var values = NSArray.FromArray<NSString> (someArray);
/// ]]></code>
/// </example>
/// </remarks>
static public T [] FromArray<T> (NSArray weakArray) where T : NSObject
/// </example>
/// </remarks>
public static T []? FromArray<T> (NSArray? weakArray) where T : NSObject
{
if (weakArray is null || weakArray.Handle == NativeHandle.Zero)
return null;
try {
nuint n = weakArray.Count;
T [] ret = new T [n];
for (nuint i = 0; i < n; i++) {
ret [i] = Runtime.GetNSObject<T> (weakArray.ValueAt (i));
}
return ret;
var rv = ArrayFromHandleDropNullElements<T> (weakArray.GetHandle (), NSNullBehavior.DropIfIncompatible);
GC.KeepAlive (weakArray);
return rv;
} catch {
return null;
}
}

/// <summary>
/// Creates a strongly-typed C# array from a weakly typed <see cref="NSArray" />,
/// dropping null and <see cref="NSNull" /> elements and guaranteeing a non-null return value.
/// </summary>
/// <typeparam name="T">The element type for the returned array, limited to <see cref="NSObject" /> and subclasses.</typeparam>
/// <param name="weakArray">A weakly typed <see cref="NSArray" /> to convert, or <see langword="null" />.</param>
/// <returns>
/// A C# array of <typeparamref name="T" /> elements (excluding null and <see cref="NSNull" /> elements).
/// Returns an empty array if <paramref name="weakArray" /> is <see langword="null" /> or empty.
/// </returns>
internal static T [] ToNonNullArrayDropNullElements<T> (NSArray? weakArray) where T : NSObject
{
var rv = NSArray.NonNullArrayFromHandleDropNullElements<T> (weakArray.GetHandle ());
GC.KeepAlive (weakArray);
return rv;
}
#nullable disable
/// <typeparam name="T">Parameter type, determines the kind of
/// array returned, can be either an NSObject, or other
/// CoreGraphics data types.</typeparam>
Expand Down
2 changes: 1 addition & 1 deletion src/MetalKit/MTKMesh.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public partial class MTKMesh {
/// <summary>Creates and returns a new Metal Kit mesh from the supplied Model IO asset.</summary>
/// <returns>To be added.</returns>
/// <remarks>To be added.</remarks>
public static MTKMesh []? FromAsset (MDLAsset asset, IMTLDevice device, out MDLMesh [] sourceMeshes, out NSError error)
public static MTKMesh []? FromAsset (MDLAsset asset, IMTLDevice device, out MDLMesh []? sourceMeshes, out NSError error)
{
NSArray aret;

Expand Down
4 changes: 1 addition & 3 deletions src/UIKit/UIFontDescriptor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -532,9 +532,7 @@ public NSCharacterSet? CharacterSet {
public UIFontDescriptor [] CascadeList {
get {
var o = GetObject (UIFontDescriptor.CascadeListAttribute) as NSArray;
if (o is null)
return new UIFontDescriptor [0];
return NSArray.FromArray<UIFontDescriptor> (o);
return NSArray.ToNonNullArrayDropNullElements<UIFontDescriptor> (o);
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/bgen/Generator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4068,7 +4068,7 @@ void GenerateProperty (Type type, PropertyInfo pi, List<string> instance_fields_
print ("return src is null ? null! : new {0}(src);", TypeManager.FormatType (pi.DeclaringType, pi.PropertyType));
} else {
if (TypeManager.IsArrayOfWrappedType (pi.PropertyType))
print ("return NSArray.FromArray<{0}>({1} as NSArray);", TypeManager.FormatType (pi.DeclaringType, pi.PropertyType.GetElementType ()), wrap);
print ("return NSArray.FromArray<{0}>({1} as NSArray){2};", TypeManager.FormatType (pi.DeclaringType, pi.PropertyType.GetElementType ()), wrap, nullable ? "" : "!");
else if (pi.PropertyType.IsValueType)
print ("return ({0}) ({1});", TypeManager.FormatType (pi.DeclaringType, pi.PropertyType), wrap);
else
Expand Down
43 changes: 43 additions & 0 deletions tests/monotouch-test/Metal/MTKMeshTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System;
using System.Numerics;

using Foundation;
using Metal;
using MetalKit;
using ModelIO;

using NUnit.Framework;

using Vector3i = global::CoreGraphics.NVector3i;

namespace MonoTouchFixtures.MetalKit {

[TestFixture]
[Preserve (AllMembers = true)]
public class MTKMeshTest {

[Test]
public void FromAsset ()
{
var device = MTLDevice.SystemDefault;
if (device is null)
Assert.Inconclusive ("Metal is not supported on this device.");

using var allocator = new MTKMeshBufferAllocator (device);
using var mesh = MDLMesh.CreateBox (new Vector3 (1, 1, 1), new Vector3i (1, 1, 1), MDLGeometryType.Triangles, false, allocator);
using var asset = new MDLAsset ();
asset.AddObject (mesh);

var result = MTKMesh.FromAsset (asset, device, out var sourceMeshes, out var error);

Assert.IsNull (error, "error");
Assert.IsNotNull (result, "result");
Assert.That (result!.Length, Is.GreaterThan (0), "result length");
Assert.IsNotNull (sourceMeshes, "sourceMeshes");
Assert.AreEqual (result.Length, sourceMeshes!.Length, "sourceMeshes length");
}
}
}
6 changes: 3 additions & 3 deletions tests/monotouch-test/ObjCRuntime/RegistrarTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5720,13 +5720,13 @@ public void DecidePolicy (WKWebView webView, WKNavigationAction navigationAction

// These classes implement Metal* protocols, so that the generated registrar code includes the corresponding Metal* headers.
// https://github.com/dotnet/macios/issues/4422
class MetalKitTypesInTheSimulator : NSObject, MetalKit.IMTKViewDelegate {
public void Draw (MetalKit.MTKView view)
class MetalKitTypesInTheSimulator : NSObject, global::MetalKit.IMTKViewDelegate {
public void Draw (global::MetalKit.MTKView view)
{
throw new NotImplementedException ();
}

public void DrawableSizeWillChange (MetalKit.MTKView view, CGSize size)
public void DrawableSizeWillChange (global::MetalKit.MTKView view, CGSize size)
{
throw new NotImplementedException ();
}
Expand Down
Loading