Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Foundation] Improve the NSAttributedString constructors. Fixes #14489. #21727

Merged
merged 1 commit into from
Dec 2, 2024
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
52 changes: 52 additions & 0 deletions src/Foundation/NSAttributedString.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,58 @@
namespace Foundation {
public partial class NSAttributedString {

/// <summary>Create a new <see cref="NSAttributedString" />.</summary>
/// <param name="url">A url to the document to load.</param>
/// <param name="options">A dictionary of attributes that specifies how to interpret the document contents.</param>
/// <param name="resultDocumentAttributes">Upon return, a dictionary of document-specific keys.</param>
/// <param name="error">The error if an error occurred.</param>
public static NSAttributedString? Create (NSUrl url, NSDictionary options, out NSDictionary resultDocumentAttributes, out NSError error)
{
var rv = new NSAttributedString (NSObjectFlag.Empty);
rv.InitializeHandle (rv._InitWithUrl (url, options, out resultDocumentAttributes, out error), string.Empty, false);
if (rv.Handle == IntPtr.Zero) {
rv.Dispose ();
return null;
}
return rv;
}

/// <summary>Create a new <see cref="NSAttributedString" />.</summary>
/// <param name="url">A url to the document to load.</param>
/// <param name="options">A dictionary of attributes that specifies how to interpret the document contents.</param>
/// <param name="resultDocumentAttributes">Upon return, a dictionary of document-specific keys.</param>
/// <param name="error">The error if an error occurred.</param>
public static NSAttributedString? Create (NSUrl url, NSAttributedStringDocumentAttributes options, out NSDictionary resultDocumentAttributes, out NSError error)
{
return Create (url, options.Dictionary, out resultDocumentAttributes, out error);
}

/// <summary>Create a new <see cref="NSAttributedString" />.</summary>
/// <param name="data">The data to load.</param>
/// <param name="options">A dictionary of attributes that specifies how to interpret the document contents.</param>
/// <param name="resultDocumentAttributes">Upon return, a dictionary of document-specific keys.</param>
/// <param name="error">The error if an error occurred.</param>
public static NSAttributedString? Create (NSData data, NSDictionary options, out NSDictionary resultDocumentAttributes, out NSError error)
{
var rv = new NSAttributedString (NSObjectFlag.Empty);
rv.InitializeHandle (rv._InitWithData (data, options, out resultDocumentAttributes, out error), string.Empty, false);
if (rv.Handle == IntPtr.Zero) {
rv.Dispose ();
return null;
}
return rv;
}

/// <summary>Create a new <see cref="NSAttributedString" />.</summary>
/// <param name="data">The data to load.</param>
/// <param name="options">A dictionary of attributes that specifies how to interpret the document contents.</param>
/// <param name="resultDocumentAttributes">Upon return, a dictionary of document-specific keys.</param>
/// <param name="error">The error if an error occurred.</param>
public static NSAttributedString? Create (NSData data, NSAttributedStringDocumentAttributes options, out NSDictionary resultDocumentAttributes, out NSError error)
{
return Create (data, options.Dictionary, out resultDocumentAttributes, out error);
}

#if __MACOS__ || XAMCORE_5_0
public NSAttributedString (NSUrl url, NSAttributedStringDocumentAttributes documentAttributes, out NSError error)
: this (url, documentAttributes, out var _, out error) {}
Expand Down
12 changes: 9 additions & 3 deletions src/Foundation/NSObject2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -665,19 +665,25 @@ public NativeHandle Handle {
[EditorBrowsable (EditorBrowsableState.Never)]
protected void InitializeHandle (NativeHandle handle)
{
InitializeHandle (handle, "init*");
InitializeHandle (handle, "init*", Class.ThrowOnInitFailure);
}

[EditorBrowsable (EditorBrowsableState.Never)]
protected void InitializeHandle (NativeHandle handle, string initSelector)
{
if (this.handle == NativeHandle.Zero && Class.ThrowOnInitFailure) {
InitializeHandle (handle, initSelector, Class.ThrowOnInitFailure);
}

[EditorBrowsable (EditorBrowsableState.Never)]
internal void InitializeHandle (NativeHandle handle, string initSelector, bool throwOnInitFailure)
{
if (this.handle == NativeHandle.Zero && throwOnInitFailure) {
if (ClassHandle == NativeHandle.Zero)
throw new Exception ($"Could not create an native instance of the type '{GetType ().FullName}': the native class hasn't been loaded.\n{Constants.SetThrowOnInitFailureToFalse}.");
throw new Exception ($"Could not create an native instance of the type '{new Class (ClassHandle).Name}'.\n{Constants.SetThrowOnInitFailureToFalse}.");
}

if (handle == NativeHandle.Zero && Class.ThrowOnInitFailure) {
if (handle == NativeHandle.Zero && throwOnInitFailure) {
Handle = NativeHandle.Zero; // We'll crash if we don't do this.
throw new Exception ($"Could not initialize an instance of the type '{GetType ().FullName}': the native '{initSelector}' method returned nil.\n{Constants.SetThrowOnInitFailureToFalse}.");
}
Expand Down
32 changes: 26 additions & 6 deletions src/foundation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -354,37 +354,57 @@ partial interface NSAttributedString : NSCoding, NSMutableCopying, NSSecureCodin
[Export ("enumerateAttribute:inRange:options:usingBlock:")]
void EnumerateAttribute (NSString attributeName, NSRange inRange, NSAttributedStringEnumeration options, NSAttributedStringCallback callback);

#if !XAMCORE_5_0
[Obsolete ("Use the 'Create' method instead, because there's no way to return an error from a constructor.")]
[Export ("initWithURL:options:documentAttributes:error:")]
#if !(__MACOS__ || XAMCORE_5_0)
#if !__MACOS__
NativeHandle Constructor (NSUrl url, NSDictionary options, out NSDictionary resultDocumentAttributes, ref NSError error);
#else
NativeHandle Constructor (NSUrl url, NSDictionary options, out NSDictionary resultDocumentAttributes, out NSError error);
#endif
#endif // !XAMCORE_5_0

[Internal]
[Sealed]
[Export ("initWithURL:options:documentAttributes:error:")]
NativeHandle _InitWithUrl (NSUrl url, NSDictionary options, out NSDictionary resultDocumentAttributes, out NSError error);

#if !XAMCORE_5_0
[Obsolete ("Use the 'Create' method instead, because there's no way to return an error from a constructor.")]
[Export ("initWithData:options:documentAttributes:error:")]
#if XAMCORE_5_0
NativeHandle Constructor (NSData data, NSDictionary options, out NSDictionary resultDocumentAttributes, out NSError error);
#elif __MACOS__
#if __MACOS__
NativeHandle Constructor (NSData data, NSDictionary options, out NSDictionary docAttributes, out NSError error);
#else
NativeHandle Constructor (NSData data, NSDictionary options, out NSDictionary resultDocumentAttributes, ref NSError error);
#endif
#endif // !XAMCORE_5_0

#if __MACOS__ || XAMCORE_5_0
[Internal]
[Sealed]
[Export ("initWithData:options:documentAttributes:error:")]
NativeHandle _InitWithData (NSData data, NSDictionary options, out NSDictionary resultDocumentAttributes, out NSError error);

#if !XAMCORE_5_0
[Obsolete ("Use the 'Create' method instead, because there's no way to return an error from a constructor.")]
#if __MACOS__
[Wrap ("this (url, options.GetDictionary ()!, out resultDocumentAttributes, out error)")]
NativeHandle Constructor (NSUrl url, NSAttributedStringDocumentAttributes options, out NSDictionary resultDocumentAttributes, out NSError error);
#else
[Wrap ("this (url, options.GetDictionary ()!, out resultDocumentAttributes, ref error)")]
NativeHandle Constructor (NSUrl url, NSAttributedStringDocumentAttributes options, out NSDictionary resultDocumentAttributes, ref NSError error);
#endif
#endif // !XAMCORE_5_0

#if __MACOS__ || XAMCORE_5_0
[Obsolete ("Use the 'Create' method instead, because there's no way to return an error from a constructor.")]
#if !XAMCORE_5_0
#if __MACOS__
[Wrap ("this (data, options.GetDictionary ()!, out resultDocumentAttributes, out error)")]
NativeHandle Constructor (NSData data, NSAttributedStringDocumentAttributes options, out NSDictionary resultDocumentAttributes, out NSError error);
#else
[Wrap ("this (data, options.GetDictionary ()!, out resultDocumentAttributes, ref error)")]
NativeHandle Constructor (NSData data, NSAttributedStringDocumentAttributes options, out NSDictionary resultDocumentAttributes, ref NSError error);
#endif
#endif // !XAMCORE_5_0

[NoiOS]
[NoMacCatalyst]
Expand Down
4 changes: 0 additions & 4 deletions tests/cecil-tests/Documentation.KnownFailures.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33263,18 +33263,14 @@ M:Foundation.NSArray`1.#ctor(Foundation.NSCoder)
M:Foundation.NSArray`1.FromNSObjects(`0[])
M:Foundation.NSArray`1.FromNSObjects(System.Int32,`0[])
M:Foundation.NSArray`1.ToArray
M:Foundation.NSAttributedString.#ctor(Foundation.NSData,Foundation.NSAttributedStringDocumentAttributes,Foundation.NSDictionary@,Foundation.NSError@)
M:Foundation.NSAttributedString.#ctor(Foundation.NSData,Foundation.NSAttributedStringDocumentAttributes,Foundation.NSDictionary@)
M:Foundation.NSAttributedString.#ctor(Foundation.NSData,Foundation.NSAttributedStringDocumentAttributes,Foundation.NSError@)
M:Foundation.NSAttributedString.#ctor(Foundation.NSData,Foundation.NSDictionary,Foundation.NSDictionary@,Foundation.NSError@)
M:Foundation.NSAttributedString.#ctor(Foundation.NSData,Foundation.NSDictionary,Foundation.NSDictionary@)
M:Foundation.NSAttributedString.#ctor(Foundation.NSData,Foundation.NSDictionary@)
M:Foundation.NSAttributedString.#ctor(Foundation.NSData,Foundation.NSError@)
M:Foundation.NSAttributedString.#ctor(Foundation.NSData,Foundation.NSUrl,Foundation.NSDictionary@)
M:Foundation.NSAttributedString.#ctor(Foundation.NSFileWrapper,Foundation.NSDictionary@)
M:Foundation.NSAttributedString.#ctor(Foundation.NSUrl,Foundation.NSAttributedStringDocumentAttributes,Foundation.NSDictionary@,Foundation.NSError@)
M:Foundation.NSAttributedString.#ctor(Foundation.NSUrl,Foundation.NSAttributedStringDocumentAttributes,Foundation.NSError@)
M:Foundation.NSAttributedString.#ctor(Foundation.NSUrl,Foundation.NSDictionary,Foundation.NSDictionary@,Foundation.NSError@)
M:Foundation.NSAttributedString.#ctor(Foundation.NSUrl,Foundation.NSDictionary@)
M:Foundation.NSAttributedString.#ctor(Foundation.NSUrl,Foundation.NSError@)
M:Foundation.NSAttributedString.#ctor(System.String,AppKit.NSFont,AppKit.NSColor,AppKit.NSColor,AppKit.NSColor,AppKit.NSColor,AppKit.NSColor,Foundation.NSUnderlineStyle,Foundation.NSUnderlineStyle,AppKit.NSParagraphStyle,System.Single,AppKit.NSShadow,Foundation.NSUrl,System.Boolean,AppKit.NSTextAttachment,Foundation.NSLigatureType,System.Single,System.Single,System.Single,System.Single,AppKit.NSCursor,System.String,System.Int32,AppKit.NSGlyphInfo,Foundation.NSArray,System.Boolean,AppKit.NSTextLayoutOrientation,AppKit.NSTextAlternatives,AppKit.NSSpellingState)
Expand Down
38 changes: 38 additions & 0 deletions tests/monotouch-test/Foundation/AttributedStringTest.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System;
using System.IO;

using NUnit.Framework;
using Foundation;
#if MONOMAC
Expand Down Expand Up @@ -135,6 +137,42 @@ public void NullDictionary ()
}
}

[Test]
public void Create_Url_Error ()
{
var obj = NSAttributedString.Create (new NSUrl (""), new NSAttributedStringDocumentAttributes (), out var rda, out var e);
Assert.IsNull (obj, "IsNull");
Assert.IsNotNull (e, "Error");
}

[Test]
public void Create_Url ()
{
var textFile = Path.Combine (NSBundle.MainBundle.ResourcePath, "uncompressed.txt");
var textUrl = NSUrl.CreateFileUrl (textFile);
var obj = NSAttributedString.Create (textUrl, new NSAttributedStringDocumentAttributes (), out var rda, out var e);
Assert.IsNull (e, "Error");
Assert.IsNotNull (obj, "IsNull");
}

[Test]
public void Create_Data_Error ()
{
var attributes = new NSAttributedStringDocumentAttributes ();
attributes.DocumentType = NSDocumentType.RTF;
var obj = NSAttributedString.Create (NSData.FromArray (new byte [42]), attributes, out var rda, out var e);
Assert.IsNull (obj, "IsNull");
Assert.IsNotNull (e, "Error");
}

[Test]
public void Create_Data ()
{
var obj = NSAttributedString.Create (new NSData (), new NSAttributedStringDocumentAttributes (), out var rda, out var e);
Assert.IsNotNull (obj, "IsNull");
Assert.IsNull (e, "Error");
}

#if !__WATCHOS__
[Test]
public void IndirectNullDictionary ()
Expand Down