Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
15 changes: 4 additions & 11 deletions src/AudioToolbox/AudioToolbox.cs
Original file line number Diff line number Diff line change
Expand Up @@ -129,21 +129,14 @@ public static class SoundBank {
if (url is null)
ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (url));

InstrumentInfo []? result = null;
IntPtr array = IntPtr.Zero;
OSStatus error;
unsafe {
error = CopyInstrumentInfoFromSoundBank (url.Handle, &array);
var error = CopyInstrumentInfoFromSoundBank (url.Handle, &array);
GC.KeepAlive (url);
if (error != 0)
return null;
}
if (array != IntPtr.Zero) {
var dicts = NSArray.ArrayFromHandle<NSDictionary> (array);
result = new InstrumentInfo [dicts.Length];
for (int i = 0; i < dicts.Length; i++)
result [i] = new InstrumentInfo (dicts [i]);
CFObject.CFRelease (array);
}
return (error != 0) ? null : result;
return NSArray.DictionaryArrayFromHandleDropNullElements<InstrumentInfo> (array, dict => new InstrumentInfo (dict), releaseHandle: true);
}
}
}
2 changes: 1 addition & 1 deletion src/AudioUnit/AudioComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -671,7 +671,7 @@ public AudioComponentInfo []? ComponentList {
get {
using var nameHandle = new TransientCFString (Name);
var cHandle = AudioUnitExtensionCopyComponentList (nameHandle);
return NSArray.ArrayFromHandle<AudioComponentInfo> (cHandle, h => new AudioComponentInfo (Runtime.GetNSObject<NSDictionary> (h)!), releaseHandle: true);
return NSArray.DictionaryArrayFromHandleDropNullElements<AudioComponentInfo> (cHandle, h => new AudioComponentInfo (h), releaseHandle: true);
}
set {
using var nameHandle = new TransientCFString (Name);
Expand Down
44 changes: 10 additions & 34 deletions src/CoreFoundation/CFProxySupport.cs
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ public static partial class CFNetwork {
/* CFStringRef __nonnull */ IntPtr proxyAutoConfigurationScript,
/* CFURLRef __nonnull */ IntPtr targetURL, /* CFErrorRef __nullable * __nullable */ IntPtr* error);

static NSArray? CopyProxiesForAutoConfigurationScript (NSString proxyAutoConfigurationScript, NSUrl targetURL)
static IntPtr CopyProxiesForAutoConfigurationScript (NSString proxyAutoConfigurationScript, NSUrl targetURL)
{
IntPtr err;
IntPtr native;
Expand All @@ -272,7 +272,7 @@ public static partial class CFNetwork {
GC.KeepAlive (proxyAutoConfigurationScript);
GC.KeepAlive (targetURL);
}
return native == IntPtr.Zero ? null : new NSArray (native);
return native;
}

/// <param name="proxyAutoConfigurationScript">JavaScript source to be executed to obtain a list of proxies to use.</param>
Expand All @@ -288,21 +288,9 @@ public static partial class CFNetwork {
if (targetURL is null)
ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (targetURL));

using (var array = CopyProxiesForAutoConfigurationScript (proxyAutoConfigurationScript, targetURL)) {
if (array is null)
return null;

NSDictionary [] dictionaries = NSArray.ArrayFromHandle<NSDictionary> (array.Handle);
GC.KeepAlive (array);
if (dictionaries is null)
return null;

CFProxy [] proxies = new CFProxy [dictionaries.Length];
for (int i = 0; i < dictionaries.Length; i++)
proxies [i] = new CFProxy (dictionaries [i]);

return proxies;
}
var array = CopyProxiesForAutoConfigurationScript (proxyAutoConfigurationScript, targetURL);
var proxies = NSArray.DictionaryArrayFromHandleDropNullElements (array, (dict) => new CFProxy (dict), releaseHandle: true);
return proxies;
}

/// <include file="../../docs/api/CoreFoundation/CFNetwork.xml" path="/Documentation/Docs[@DocId='M:CoreFoundation.CFNetwork.GetProxiesForAutoConfigurationScript(Foundation.NSString,System.Uri)']/*" />
Expand All @@ -325,12 +313,12 @@ public static partial class CFNetwork {
/* CFURLRef __nonnull */ IntPtr url,
/* CFDictionaryRef __nonnull */ IntPtr proxySettings);

static NSArray? CopyProxiesForURL (NSUrl url, NSDictionary proxySettings)
static IntPtr CopyProxiesForURL (NSUrl url, NSDictionary proxySettings)
{
IntPtr native = CFNetworkCopyProxiesForURL (url.Handle, proxySettings.Handle);
GC.KeepAlive (url);
GC.KeepAlive (proxySettings);
return native == IntPtr.Zero ? null : new NSArray (native);
return native;
}

/// <param name="url">The target URL to connect to.</param>
Expand All @@ -349,21 +337,9 @@ public static partial class CFNetwork {
if (proxySettings is null)
return null;

using (NSArray? array = CopyProxiesForURL (url, proxySettings.Dictionary)) {
if (array is null)
return null;

NSDictionary [] dictionaries = NSArray.ArrayFromHandle<NSDictionary> (array.Handle);
GC.KeepAlive (array);
if (dictionaries is null)
return null;

CFProxy [] proxies = new CFProxy [dictionaries.Length];
for (int i = 0; i < dictionaries.Length; i++)
proxies [i] = new CFProxy (dictionaries [i]);

return proxies;
}
var array = CopyProxiesForURL (url, proxySettings.Dictionary);
var proxies = NSArray.DictionaryArrayFromHandleDropNullElements (array, (dict) => new CFProxy (dict), releaseHandle: true);
return proxies;
}

/// <param name="uri">The target Uri to connect to.</param>
Expand Down
17 changes: 5 additions & 12 deletions src/CoreText/CTFont.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3475,10 +3475,7 @@ public nint GetLigatureCaretPositions (CGGlyph glyph, nfloat [] positions)
public CTFontVariationAxes [] GetVariationAxes ()
{
var cfArrayRef = CTFontCopyVariationAxes (Handle);
if (cfArrayRef == IntPtr.Zero)
return Array.Empty<CTFontVariationAxes> ();
return NSArray.ArrayFromHandle (cfArrayRef,
d => new CTFontVariationAxes (Runtime.GetNSObject<NSDictionary> (d)!), true);
return NSArray.NonNullDictionaryArrayFromHandleDropNullElements (cfArrayRef, d => new CTFontVariationAxes (d), true);
}

[DllImport (Constants.CoreTextLibrary)]
Expand Down Expand Up @@ -3507,10 +3504,8 @@ public CTFontVariationAxes [] GetVariationAxes ()
public CTFontFeatures [] GetFeatures ()
{
var cfArrayRef = CTFontCopyFeatures (Handle);
if (cfArrayRef == IntPtr.Zero)
return Array.Empty<CTFontFeatures> ();
return NSArray.ArrayFromHandle (cfArrayRef,
d => new CTFontFeatures (Runtime.GetNSObject<NSDictionary> (d)!), true);
return NSArray.NonNullDictionaryArrayFromHandleDropNullElements (cfArrayRef,
d => new CTFontFeatures (d), true);
}

[DllImport (Constants.CoreTextLibrary)]
Expand All @@ -3523,10 +3518,8 @@ public CTFontFeatures [] GetFeatures ()
public CTFontFeatureSettings [] GetFeatureSettings ()
{
var cfArrayRef = CTFontCopyFeatureSettings (Handle);
if (cfArrayRef == IntPtr.Zero)
return Array.Empty<CTFontFeatureSettings> ();
return NSArray.ArrayFromHandle (cfArrayRef,
d => new CTFontFeatureSettings (Runtime.GetNSObject<NSDictionary> (d)!), true);
return NSArray.NonNullDictionaryArrayFromHandleDropNullElements (cfArrayRef,
d => new CTFontFeatureSettings (d), true);
}
#endregion

Expand Down
58 changes: 58 additions & 0 deletions src/Foundation/NSArray.cs
Original file line number Diff line number Diff line change
Expand Up @@ -623,6 +623,64 @@ public static T [] ArrayFromHandleFunc<T> (NativeHandle handle, Func<NativeHandl
return rv;
}

/// <summary>Creates a managed array from a pointer to a native NSArray of NSDictionary objects, dropping null and NSNull elements.</summary>
/// <typeparam name="T">The type of objects to create from the dictionaries.</typeparam>
/// <param name="handle">The pointer to the native NSArray instance containing NSDictionary objects.</param>
/// <param name="createObjectFromDictionary">A factory function that creates an instance of type T from an NSDictionary.</param>
/// <param name="releaseHandle">Whether the native NSArray instance should be released before returning or not. Defaults to false.</param>
/// <returns>A C# array with the values, or null if the handle is zero. Null and NSNull elements are excluded from the result.</returns>
/// <remarks>
/// <para>This method converts a native NSArray of NSDictionary objects into a managed array. Any null or NSNull elements in the source array are skipped, and the resulting array is resized accordingly.</para>
/// </remarks>
#nullable enable
internal static T []? DictionaryArrayFromHandleDropNullElements<T> (NativeHandle handle, Func<NSDictionary, T> createObjectFromDictionary, bool releaseHandle = false)
{
if (handle == NativeHandle.Zero)
return null;

try {
var count = GetCount (handle);
var ret = new T [count];
nuint nextIndex = 0;

for (nuint i = 0; i < count; i++) {
var val = GetAtIndex (handle, i);
if (val == IntPtr.Zero || val == NSNull.Null.Handle)
continue;
var dict = Runtime.GetNSObject<NSDictionary> (val);
if (dict is null)
continue;
ret [nextIndex++] = createObjectFromDictionary (dict);
}

if (nextIndex != count)
Array.Resize<T> (ref ret, (int) nextIndex);

return ret;
} finally {
if (releaseHandle)
NSObject.DangerousRelease (handle);
}
}

/// <summary>Creates a managed array from a pointer to a native NSArray of NSDictionary objects, dropping null and NSNull elements. Always returns a non-null array.</summary>
/// <typeparam name="T">The type of objects to create from the dictionaries.</typeparam>
/// <param name="handle">The pointer to the native NSArray instance containing NSDictionary objects.</param>
/// <param name="createObjectFromDictionary">A factory function that creates an instance of type T from an NSDictionary.</param>
/// <param name="releaseHandle">Whether the native NSArray instance should be released before returning or not. Defaults to false.</param>
/// <returns>A C# array with the values. Returns an empty array if the handle is zero. Null and NSNull elements are excluded from the result.</returns>
/// <remarks>
/// <para>This method is a wrapper around <see cref="DictionaryArrayFromHandleDropNullElements{T}"/> that guarantees a non-null return value. If the handle is zero or null, an empty array is returned instead of null.</para>
/// </remarks>
internal static T [] NonNullDictionaryArrayFromHandleDropNullElements<T> (NativeHandle handle, Func<NSDictionary, T> createObjectFromDictionary, bool releaseHandle = false)
{
var rv = DictionaryArrayFromHandleDropNullElements<T> (handle, createObjectFromDictionary, releaseHandle);
if (rv is null)
return Array.Empty<T> ();
return rv;
}
#nullable disable

/// <typeparam name="T">Parameter type, determines the kind of array returned.</typeparam>
/// <param name="handle">Pointer (handle) to the unmanaged object.</param>
/// <param name="creator">Method that can create objects of type T from a given IntPtr.</param>
Expand Down
8 changes: 1 addition & 7 deletions src/VideoToolbox/VTVideoEncoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,7 @@ public class VTVideoEncoder {
return null;
}

var dicts = NSArray.ArrayFromHandle<NSDictionary> (array);
var ret = new VTVideoEncoder [dicts.Length];
int i = 0;
foreach (var dict in dicts)
ret [i++] = new VTVideoEncoder (dict);
CFObject.CFRelease (array);
return ret;
return NSArray.DictionaryArrayFromHandleDropNullElements<VTVideoEncoder> (array, dict => new VTVideoEncoder (dict), releaseHandle: true);
}

/// <summary>To be added.</summary>
Expand Down
11 changes: 11 additions & 0 deletions tests/monotouch-test/CoreText/FontTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -163,5 +163,16 @@ class AdaptiveImageProvider : NSObject, ICTAdaptiveImageProviding {
return null;
}
}

[Test]
public void GetVariationAxes ()
{
using (var font = new CTFont ("HoeflerText-Regular", 10)) {
var axes = font.GetVariationAxes ();
Assert.IsNotNull (axes, "axes");
// HoeflerText-Regular has no variation axes, so we expect an empty array
Assert.That (axes.Length, Is.EqualTo (0), "Length");
}
}
}
}
Loading