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

Handle change notifications originating from Core #909

Merged
merged 16 commits into from
Nov 21, 2016

Conversation

nirinchev
Copy link
Member

@nirinchev nirinchev commented Nov 8, 2016

TODO:

  • Unregister observed items (event unsubscribe, remove object)
  • Unregister observed items on deletion (invalidated vector)
  • Handle changes for same-thread realms (I'm thinking of adding NotifyChanges() at the end of each set_xxx method)
  • Lookup property index, instead of using the column index
  • Decide whether we want to support [MapTo]
  • Moar unit tests 👺
  • Tests for object deletion

Resolves #886

@nirinchev nirinchev added this to the v1.0 milestone Nov 8, 2016
@nirinchev nirinchev force-pushed the ni/object-notifications branch 2 times, most recently from 7105d17 to 34b25f2 Compare November 11, 2016 23:15
Copy link
Contributor

@kristiandupont kristiandupont left a comment

Choose a reason for hiding this comment

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

Looks good

@@ -271,7 +270,7 @@ private void UnsubscribeFromNotifications()
{
Debug.Assert(_notificationToken != null, "_notificationToken must not be null to unsubscribe.");

_notificationToken.Dispose();
_notificationToken?.Dispose();
Copy link
Contributor

Choose a reason for hiding this comment

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

We've just asserted that it wasn't null above -- is this defensive programming?

Copy link
Member Author

Choose a reason for hiding this comment

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

It's a Debug.Assert, meaning it won't run in released apps and just wanted to avoid potential crash in unsubscribing over which users usually have no control.


static RealmObject()
{
NativeCommon.register_notify_realm_object_changed(NotifyRealmObjectPropertyChanged);
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there any advantage to keeping this here rather than in the static Realm constructor? I get that it's slightly more related to this, but it seems to me that it would be nice to keep static initialization grouped together, if for no other reason then because it makes the execution order deterministic.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, I don't have strong feelings about where it should go - as you said, it's slightly more related to object, so I left it here, but I don't mind moving it to Realm.

@nirinchev nirinchev force-pushed the ni/object-notifications branch from 5a08867 to 692aa9d Compare November 21, 2016 15:17
{
var gch = GCHandle.FromIntPtr(realmObjectHandle);
var realmObject = (RealmObject)gch.Target;
var propertyName = realmObject.ObjectSchema.ElementAtOrDefault((int)propertyIndex).PropertyInfo.Name;
Copy link
Member

Choose a reason for hiding this comment

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

Realms.Schema.Property.PropertyInfo will be null for dynamic realms.

Debug.Assert(_notificationsHandle.HasValue, "Notification handle must not be null to unsubscribe");

_realm.SharedRealmHandle.RemoveObservedObject(GCHandle.ToIntPtr(_notificationsHandle.Value));
_notificationsHandle = null;
Copy link
Member

Choose a reason for hiding this comment

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

I think you are going to have to call GCHandle.Free() on both handles you create in SubscribeForNotifications to prevent the handles from being leaked.

auto observer_state = BindingContext::ObserverState();
observer_state.row_ndx = object.row().get_index();
observer_state.table_ndx = object.row().get_table()->get_index_in_group();
observer_state.info = new ObservedObjectDetails(object.get_object_schema(), managed_object_handle);
Copy link
Member

Choose a reason for hiding this comment

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

this needs to be deleted later.

observer_state.row_ndx = object.row().get_index();
observer_state.table_ndx = object.row().get_table()->get_index_in_group();
observer_state.info = new ObservedObjectDetails(object.get_object_schema(), managed_object_handle);
observed_rows.push_back(observer_state);
Copy link
Member

Choose a reason for hiding this comment

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

use std::move to prevent a copy.

}
}

void* CSharpBindingContext::get_managed_realm_handle()
Copy link
Member

Choose a reason for hiding this comment

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

define in header instead so that the getter can be inlined in other translation units.

private:
void* m_managed_realm_handle;
std::vector<BindingContext::ObserverState> observed_rows;
Copy link
Member

Choose a reason for hiding this comment

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

use the m_ prefix for fields.

#if __IOS__
[MonoPInvokeCallback(typeof(NativeCommon.NotifyRealmCallback))]
#endif
private static void NotifyRealmObjectPropertyChanged(IntPtr realmObjectHandle, IntPtr propertyIndex)
public static void NotifyRealmObjectPropertyChanged(IntPtr realmObjectHandle, IntPtr propertyIndex)
Copy link
Member

Choose a reason for hiding this comment

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

this should be internal

@@ -65,7 +61,7 @@ namespace binding {

CSharpBindingContext::CSharpBindingContext(void* managed_realm_handle) : m_managed_realm_handle(managed_realm_handle)
{
observed_rows = std::vector<ObserverState>();
m_observed_rows = std::vector<ObserverState>();
Copy link
Member

Choose a reason for hiding this comment

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

You don't need to initialize this - the compiler will have added the necessary code to invoke the std::vector constructor in the CSharpBindingContext constructor.

@nirinchev nirinchev merged commit f9be43f into master Nov 21, 2016
@nirinchev nirinchev deleted the ni/object-notifications branch November 21, 2016 22:52
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 15, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants