123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415 |
- #import "RLMObject_Private.hpp"
- #import "RLMAccessor.h"
- #import "RLMArray.h"
- #import "RLMCollection_Private.hpp"
- #import "RLMObjectBase_Private.h"
- #import "RLMObjectSchema_Private.hpp"
- #import "RLMObjectStore.h"
- #import "RLMProperty.h"
- #import "RLMQueryUtil.hpp"
- #import "RLMRealm_Private.hpp"
- #import "RLMSchema_Private.h"
- #import "collection_notifications.hpp"
- #import "object.hpp"
- @interface RLMPropertyChange ()
- @property (nonatomic, readwrite, strong) NSString *name;
- @property (nonatomic, readwrite, strong, nullable) id previousValue;
- @property (nonatomic, readwrite, strong, nullable) id value;
- @end
- @implementation RLMObject
- @dynamic invalidated, realm, objectSchema;
- #pragma mark - Designated Initializers
- - (instancetype)init {
- return [super init];
- }
- - (instancetype)initWithValue:(id)value schema:(RLMSchema *)schema {
- return [super initWithValue:value schema:schema];
- }
- - (instancetype)initWithRealm:(__unsafe_unretained RLMRealm *const)realm schema:(RLMObjectSchema *)schema {
- return [super initWithRealm:realm schema:schema];
- }
- #pragma mark - Convenience Initializers
- - (instancetype)initWithValue:(id)value {
- return [super initWithValue:value schema:RLMSchema.partialPrivateSharedSchema];
- }
- #pragma mark - Class-based Object Creation
- + (instancetype)createInDefaultRealmWithValue:(id)value {
- return (RLMObject *)RLMCreateObjectInRealmWithValue([RLMRealm defaultRealm], [self className], value, RLMUpdatePolicyError);
- }
- + (instancetype)createInRealm:(RLMRealm *)realm withValue:(id)value {
- return (RLMObject *)RLMCreateObjectInRealmWithValue(realm, [self className], value, RLMUpdatePolicyError);
- }
- + (instancetype)createOrUpdateInDefaultRealmWithValue:(id)value {
- return [self createOrUpdateInRealm:[RLMRealm defaultRealm] withValue:value];
- }
- + (instancetype)createOrUpdateModifiedInDefaultRealmWithValue:(id)value {
- return [self createOrUpdateModifiedInRealm:[RLMRealm defaultRealm] withValue:value];
- }
- + (instancetype)createOrUpdateInRealm:(RLMRealm *)realm withValue:(id)value {
- RLMVerifyHasPrimaryKey(self);
- return (RLMObject *)RLMCreateObjectInRealmWithValue(realm, [self className], value, RLMUpdatePolicyUpdateAll);
- }
- + (instancetype)createOrUpdateModifiedInRealm:(RLMRealm *)realm withValue:(id)value {
- RLMVerifyHasPrimaryKey(self);
- return (RLMObject *)RLMCreateObjectInRealmWithValue(realm, [self className], value, RLMUpdatePolicyUpdateChanged);
- }
- #pragma mark - Subscripting
- - (id)objectForKeyedSubscript:(NSString *)key {
- return RLMObjectBaseObjectForKeyedSubscript(self, key);
- }
- - (void)setObject:(id)obj forKeyedSubscript:(NSString *)key {
- RLMObjectBaseSetObjectForKeyedSubscript(self, key, obj);
- }
- #pragma mark - Getting & Querying
- + (RLMResults *)allObjects {
- return RLMGetObjects(RLMRealm.defaultRealm, self.className, nil);
- }
- + (RLMResults *)allObjectsInRealm:(__unsafe_unretained RLMRealm *const)realm {
- return RLMGetObjects(realm, self.className, nil);
- }
- + (RLMResults *)objectsWhere:(NSString *)predicateFormat, ... {
- va_list args;
- va_start(args, predicateFormat);
- RLMResults *results = [self objectsWhere:predicateFormat args:args];
- va_end(args);
- return results;
- }
- + (RLMResults *)objectsWhere:(NSString *)predicateFormat args:(va_list)args {
- return [self objectsWithPredicate:[NSPredicate predicateWithFormat:predicateFormat arguments:args]];
- }
- + (RLMResults *)objectsInRealm:(RLMRealm *)realm where:(NSString *)predicateFormat, ... {
- va_list args;
- va_start(args, predicateFormat);
- RLMResults *results = [self objectsInRealm:realm where:predicateFormat args:args];
- va_end(args);
- return results;
- }
- + (RLMResults *)objectsInRealm:(RLMRealm *)realm where:(NSString *)predicateFormat args:(va_list)args {
- return [self objectsInRealm:realm withPredicate:[NSPredicate predicateWithFormat:predicateFormat arguments:args]];
- }
- + (RLMResults *)objectsWithPredicate:(NSPredicate *)predicate {
- return RLMGetObjects(RLMRealm.defaultRealm, self.className, predicate);
- }
- + (RLMResults *)objectsInRealm:(RLMRealm *)realm withPredicate:(NSPredicate *)predicate {
- return RLMGetObjects(realm, self.className, predicate);
- }
- + (instancetype)objectForPrimaryKey:(id)primaryKey {
- return RLMGetObject(RLMRealm.defaultRealm, self.className, primaryKey);
- }
- + (instancetype)objectInRealm:(RLMRealm *)realm forPrimaryKey:(id)primaryKey {
- return RLMGetObject(realm, self.className, primaryKey);
- }
- #pragma mark - Other Instance Methods
- - (BOOL)isEqualToObject:(RLMObject *)object {
- return [object isKindOfClass:RLMObject.class] && RLMObjectBaseAreEqual(self, object);
- }
- - (RLMNotificationToken *)addNotificationBlock:(RLMObjectChangeBlock)block {
- return RLMObjectAddNotificationBlock(self, ^(NSArray<NSString *> *propertyNames,
- NSArray *oldValues, NSArray *newValues, NSError *error) {
- if (error) {
- block(false, nil, error);
- }
- else if (!propertyNames) {
- block(true, nil, nil);
- }
- else {
- auto properties = [NSMutableArray arrayWithCapacity:propertyNames.count];
- for (NSUInteger i = 0, count = propertyNames.count; i < count; ++i) {
- auto prop = [RLMPropertyChange new];
- prop.name = propertyNames[i];
- prop.previousValue = RLMCoerceToNil(oldValues[i]);
- prop.value = RLMCoerceToNil(newValues[i]);
- [properties addObject:prop];
- }
- block(false, properties, nil);
- }
- });
- }
- + (NSString *)className {
- return [super className];
- }
- #pragma mark - Default values for schema definition
- + (NSArray *)indexedProperties {
- return @[];
- }
- + (NSDictionary *)linkingObjectsProperties {
- return @{};
- }
- + (NSDictionary *)defaultPropertyValues {
- return nil;
- }
- + (NSString *)primaryKey {
- return nil;
- }
- + (NSArray *)ignoredProperties {
- return nil;
- }
- + (NSArray *)requiredProperties {
- return @[];
- }
- @end
- @implementation RLMDynamicObject
- + (BOOL)shouldIncludeInDefaultSchema {
- return NO;
- }
- - (id)valueForUndefinedKey:(NSString *)key {
- return RLMDynamicGetByName(self, key, false);
- }
- - (void)setValue:(id)value forUndefinedKey:(NSString *)key {
- RLMDynamicValidatedSet(self, key, value);
- }
- @end
- @implementation RLMWeakObjectHandle {
- realm::Row _row;
- RLMClassInfo *_info;
- Class _objectClass;
- }
- - (instancetype)initWithObject:(RLMObjectBase *)object {
- if (!(self = [super init])) {
- return nil;
- }
- _row = object->_row;
- _info = object->_info;
- _objectClass = object.class;
- return self;
- }
- - (RLMObjectBase *)object {
- RLMObjectBase *object = RLMCreateManagedAccessor(_objectClass, _info->realm, _info);
- object->_row = std::move(_row);
- return object;
- }
- - (id)copyWithZone:(__unused NSZone *)zone {
- RLMWeakObjectHandle *copy = [[RLMWeakObjectHandle alloc] init];
- copy->_row = _row;
- copy->_info = _info;
- copy->_objectClass = _objectClass;
- return copy;
- }
- @end
- static bool treatFakeObjectAsRLMObject = false;
- void RLMSetTreatFakeObjectAsRLMObject(BOOL flag) {
- treatFakeObjectAsRLMObject = flag;
- }
- BOOL RLMIsObjectOrSubclass(Class klass) {
- if (RLMIsKindOfClass(klass, RLMObjectBase.class)) {
- return YES;
- }
- if (treatFakeObjectAsRLMObject) {
- static Class FakeObjectClass = NSClassFromString(@"FakeObject");
- return RLMIsKindOfClass(klass, FakeObjectClass);
- }
- return NO;
- }
- BOOL RLMIsObjectSubclass(Class klass) {
- auto isSubclass = [](Class class1, Class class2) {
- class1 = class_getSuperclass(class1);
- return RLMIsKindOfClass(class1, class2);
- };
- if (isSubclass(class_getSuperclass(klass), RLMObjectBase.class)) {
- return YES;
- }
- if (treatFakeObjectAsRLMObject) {
- static Class FakeObjectClass = NSClassFromString(@"FakeObject");
- return isSubclass(klass, FakeObjectClass);
- }
- return NO;
- }
- @interface RLMObjectNotificationToken : RLMCancellationToken
- @end
- @implementation RLMObjectNotificationToken {
- @public
- realm::Object _object;
- }
- @end
- RLMNotificationToken *RLMObjectAddNotificationBlock(RLMObjectBase *obj, RLMObjectNotificationCallback block) {
- if (!obj->_realm) {
- @throw RLMException(@"Only objects which are managed by a Realm support change notifications");
- }
- [obj->_realm verifyNotificationsAreSupported:true];
- struct {
- void (^block)(NSArray<NSString *> *, NSArray *, NSArray *, NSError *);
- RLMObjectBase *object;
- NSArray<NSString *> *propertyNames = nil;
- NSArray *oldValues = nil;
- bool deleted = false;
- void populateProperties(realm::CollectionChangeSet const& c) {
- if (propertyNames) {
- return;
- }
- if (!c.deletions.empty()) {
- deleted = true;
- return;
- }
- if (c.columns.empty()) {
- return;
- }
- auto properties = [NSMutableArray new];
- for (size_t i = 0; i < c.columns.size(); ++i) {
- if (c.columns[i].empty()) {
- continue;
- }
- if (auto prop = object->_info->propertyForTableColumn(i)) {
- [properties addObject:prop.name];
- }
- }
- if (properties.count) {
- propertyNames = properties;
- }
- }
- NSArray *readValues(realm::CollectionChangeSet const& c) {
- if (c.empty()) {
- return nil;
- }
- populateProperties(c);
- if (!propertyNames) {
- return nil;
- }
- auto values = [NSMutableArray arrayWithCapacity:propertyNames.count];
- for (NSString *name in propertyNames) {
- id value = [object valueForKey:name];
- if (!value || [value isKindOfClass:[RLMArray class]]) {
- [values addObject:NSNull.null];
- }
- else {
- [values addObject:value];
- }
- }
- return values;
- }
- void before(realm::CollectionChangeSet const& c) {
- @autoreleasepool {
- oldValues = readValues(c);
- }
- }
- void after(realm::CollectionChangeSet const& c) {
- @autoreleasepool {
- auto newValues = readValues(c);
- if (deleted) {
- block(nil, nil, nil, nil);
- }
- else if (newValues) {
- block(propertyNames, oldValues, newValues, nil);
- }
- propertyNames = nil;
- oldValues = nil;
- }
- }
- void error(std::exception_ptr err) {
- @autoreleasepool {
- try {
- rethrow_exception(err);
- }
- catch (...) {
- NSError *error = nil;
- RLMRealmTranslateException(&error);
- block(nil, nil, nil, error);
- }
- }
- }
- } callback{block, obj};
- realm::Object object(obj->_realm->_realm, *obj->_info->objectSchema, obj->_row);
- auto token = [[RLMObjectNotificationToken alloc] initWithToken:object.add_notification_callback(callback) realm:obj->_realm];
- token->_object = std::move(object);
- return token;
- }
- @implementation RLMPropertyChange
- @end
|