Skip to content

Commit

Permalink
[ABRecord] Subclass NativeObject + numerous other code updates (#13085)
Browse files Browse the repository at this point in the history
* Subclass NativeObject to reuse object lifetime code.
* Enable nullability and fix code accordingly.
* Use 'is' and 'is not' instead of '==' and '!=' for object identity.
* Use CFString.CreateNative/ReleaseNative instead of other means to create
  native strings (the fastest and least memory hungry option).
* Use the null-safe NativeObjectExtensions.GetHandle extension method to get
  the handle instead of checking for null (avoids some code duplication).
* Use 'nameof (parameter)' instead of string constants.
  • Loading branch information
rolfbjarne authored Oct 25, 2021
1 parent 22b8c38 commit 0ede53d
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 63 deletions.
4 changes: 2 additions & 2 deletions src/AddressBook/ABPerson.cs
Original file line number Diff line number Diff line change
Expand Up @@ -944,8 +944,8 @@ public void SetDates (ABMultiValue<NSDate>? value)
}

public ABPersonKind PersonKind {
get {return ABPersonKindId.ToPersonKind (PropertyTo<NSNumber> (ABPersonPropertyId.Kind));}
set {SetValue (ABPersonPropertyId.Kind, ABPersonKindId.FromPersonKind (value));}
get { return ABPersonKindId.ToPersonKind (PropertyTo<NSNumber> (ABPersonPropertyId.Kind!)!); }
set { SetValue (ABPersonPropertyId.Kind!, ABPersonKindId.FromPersonKind (value)); }
}

public ABMultiValue<string>? GetPhones ()
Expand Down
84 changes: 25 additions & 59 deletions src/AddressBook/ABRecord.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
//
//

#nullable enable

#if !MONOMAC

using System;
Expand All @@ -53,32 +55,28 @@ namespace AddressBook {
[Obsolete ("Starting with maccatalyst14.0 use the 'Contacts' API instead.", DiagnosticId = "BI1234", UrlFormat = "https://github.com/xamarin/xamarin-macios/wiki/Obsolete")]
#endif
#endif
public class ABRecord : INativeObject, IDisposable {
public class ABRecord : NativeObject {

public const int InvalidRecordId = -1;
public const int InvalidPropertyId = -1;

IntPtr handle;

[Preserve (Conditional = true)]
internal ABRecord (IntPtr handle, bool owns)
: base (handle, owns)
{
if (!owns)
CFObject.CFRetain (handle);
this.handle = handle;
}

public static ABRecord FromHandle (IntPtr handle)
public static ABRecord? FromHandle (IntPtr handle)
{
if (handle == IntPtr.Zero)
return null;
return FromHandle (handle, null, false);
}

internal static ABRecord FromHandle (IntPtr handle, ABAddressBook addressbook, bool owns = true)
internal static ABRecord FromHandle (IntPtr handle, ABAddressBook? addressbook, bool owns = true)
{
if (handle == IntPtr.Zero)
throw new ArgumentNullException ("handle");
throw new ArgumentNullException (nameof (handle));
// TODO: does ABGroupCopyArrayOfAllMembers() have Create or Get
// semantics for the array elements?
var type = ABRecordGetRecordType (handle);
Expand All @@ -102,45 +100,16 @@ internal static ABRecord FromHandle (IntPtr handle, ABAddressBook addressbook, b
return rec;
}

~ABRecord ()
{
Dispose (false);
}

public void Dispose ()
protected override void Dispose (bool disposing)
{
Dispose (true);
GC.SuppressFinalize (this);
}

protected virtual void Dispose (bool disposing)
{
if (handle != IntPtr.Zero)
CFObject.CFRelease (handle);
handle = IntPtr.Zero;
AddressBook = null;
base.Dispose (disposing);
}

void AssertValid ()
{
if (handle == IntPtr.Zero)
throw new ObjectDisposedException ("");
}

internal ABAddressBook AddressBook {
internal ABAddressBook? AddressBook {
get; set;
}

public IntPtr Handle {
get {
AssertValid ();
return handle;
}
internal set {
handle = value;
}
}

[DllImport (Constants.AddressBookLibrary)]
extern static int ABRecordGetRecordID (IntPtr record);
public int Id {
Expand All @@ -155,10 +124,9 @@ public ABRecordType Type {

[DllImport (Constants.AddressBookLibrary)]
extern static IntPtr ABRecordCopyCompositeName (IntPtr record);
public override string ToString ()
public override string? ToString ()
{
using (var s = new NSString (ABRecordCopyCompositeName (Handle)))
return s.ToString ();
return CFString.FromHandle (ABRecordCopyCompositeName (Handle));
}

// TODO: Should SetValue/CopyValue/RemoveValue be public?
Expand All @@ -173,15 +141,19 @@ internal void SetValue (int property, IntPtr value)
throw CFException.FromCFError (error);
}

internal void SetValue (int property, NSObject value)
internal void SetValue (int property, NSObject? value)
{
SetValue (property, value == null ? IntPtr.Zero : value.Handle);
SetValue (property, value.GetHandle ());
}

internal void SetValue (int property, string value)
internal void SetValue (int property, string? value)
{
using (NSObject v = value == null ? null : new NSString (value))
SetValue (property, v);
var valueHandle = CFString.CreateNative (value);
try {
SetValue (property, valueHandle);
} finally {
CFString.ReleaseNative (valueHandle);
}
}

[DllImport (Constants.AddressBookLibrary)]
Expand All @@ -202,22 +174,16 @@ internal void RemoveValue (int property)
throw CFException.FromCFError (error);
}

internal T PropertyTo<T> (int id)
internal T? PropertyTo<T> (int id)
where T : NSObject
{
IntPtr value = CopyValue (id);
if (value == IntPtr.Zero)
return null;
return (T) Runtime.GetNSObject (value);
return (T?) Runtime.GetNSObject (value);
}

internal string PropertyToString (int id)
internal string? PropertyToString (int id)
{
IntPtr value = CopyValue (id);
if (value == IntPtr.Zero)
return null;
using (var s = new NSString (value))
return s.ToString ();
return CFString.FromHandle (CopyValue (id));
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/generator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2356,8 +2356,8 @@ public void Go ()
marshal_types.Add (new MarshalType (TypeManager.MTAudioProcessingTap, create: "MediaToolbox.MTAudioProcessingTap.FromHandle("));
if (Frameworks.HaveAddressBook) {
marshal_types.Add (TypeManager.ABAddressBook);
marshal_types.Add (new MarshalType (TypeManager.ABPerson, create: "(ABPerson) ABRecord.FromHandle("));
marshal_types.Add (new MarshalType (TypeManager.ABRecord, create: "ABRecord.FromHandle("));
marshal_types.Add (new MarshalType (TypeManager.ABPerson, create: "(ABPerson) ABRecord.FromHandle (", closingCreate: ")!"));
marshal_types.Add (new MarshalType (TypeManager.ABRecord, create: "ABRecord.FromHandle (", closingCreate: ")!"));
}
if (Frameworks.HaveCoreVideo) {
// owns `false` like ptr ctor https://github.com/xamarin/xamarin-macios/blob/6f68ab6f79c5f1d96d2cbb1e697330623164e46d/src/CoreVideo/CVBuffer.cs#L74-L90
Expand Down

5 comments on commit 0ede53d

@vs-mobiletools-engineering-service2
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❌ [CI Build] Tests failed on Build ❌

Tests failed on Build.

API diff

✅ API Diff from stable

View API diff
View dotnet API diff
View dotnet legacy API diff
View dotnet iOS-MacCatalayst API diff

Packages generated

View packages

Test results

1 tests failed, 217 tests passed.

Failed tests

  • monotouch-test/Mac Catalyst [dotnet]/Debug [dotnet]: Failed (Tests run: 2703 Passed: 2500 Inconclusive: 35 Failed: 3 Ignored: 200)

Pipeline on Agent XAMBOT-1027.BigSur'
[ABRecord] Subclass NativeObject + numerous other code updates (#13085)

@vs-mobiletools-engineering-service2
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Tests were not ran (VSTS: device tests tvOS). ⚠️

Results were skipped for this run due to provisioning problems Azure Devops. Please contact the bot administrator.

Pipeline on Agent
[ABRecord] Subclass NativeObject + numerous other code updates (#13085)

@vs-mobiletools-engineering-service2
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Tests were not ran (VSTS: device tests iOS). ⚠️

Results were skipped for this run due to provisioning problems Azure Devops. Please contact the bot administrator.

Pipeline on Agent
[ABRecord] Subclass NativeObject + numerous other code updates (#13085)

@vs-mobiletools-engineering-service2
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Tests passed on macOS M1 - Mac Big Sur (11.5) ✅

Tests passed

All tests on macOS X M1 - Mac Big Sur (11.5) passed.

Pipeline on Agent
[ABRecord] Subclass NativeObject + numerous other code updates (#13085)

@vs-mobiletools-engineering-service2
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Tests passed on macOS Mac Mojave (10.14) ✅

Tests passed

All tests on macOS X Mac Mojave (10.14) passed.

Pipeline on Agent
[ABRecord] Subclass NativeObject + numerous other code updates (#13085)

Please sign in to comment.