123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364 |
- ////////////////////////////////////////////////////////////////////////////
- //
- // Copyright 2014 Realm Inc.
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- //
- ////////////////////////////////////////////////////////////////////////////
- #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_Private.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
- // We declare things in RLMObject which are actually implemented in RLMObjectBase
- // for documentation's sake, which leads to -Wunimplemented-method warnings.
- // Other alternatives to this would be to disable -Wunimplemented-method for this
- // file (but then we could miss legitimately missing things), or declaring the
- // inherited things in a category (but they currently aren't nicely grouped for
- // that).
- @implementation RLMObject
- // synthesized in RLMObjectBase
- @dynamic invalidated, realm, objectSchema;
- #pragma mark - Designated Initializers
- - (instancetype)init {
- return [super init];
- }
- #pragma mark - Convenience Initializers
- - (instancetype)initWithValue:(id)value {
- if (!(self = [self init])) {
- return nil;
- }
- RLMInitializeWithValue(self, value, RLMSchema.partialPrivateSharedSchema);
- return self;
- }
- #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 @[];
- }
- + (bool)_realmIgnoreClass {
- return false;
- }
- @end
- @implementation RLMDynamicObject
- + (bool)_realmIgnoreClass {
- return true;
- }
- + (BOOL)shouldIncludeInDefaultSchema {
- return NO;
- }
- - (id)valueForUndefinedKey:(NSString *)key {
- return RLMDynamicGetByName(self, key);
- }
- - (void)setValue:(id)value forUndefinedKey:(NSString *)key {
- RLMDynamicValidatedSet(self, key, value);
- }
- + (RLMObjectSchema *)sharedSchema {
- return nil;
- }
- @end
- BOOL RLMIsObjectOrSubclass(Class klass) {
- return RLMIsKindOfClass(klass, RLMObjectBase.class);
- }
- BOOL RLMIsObjectSubclass(Class klass) {
- return RLMIsKindOfClass(class_getSuperclass(class_getSuperclass(klass)), RLMObjectBase.class);
- }
- @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
|