RLMObjectBase.mm 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747
  1. ////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright 2014 Realm Inc.
  4. //
  5. // Licensed under the Apache License, Version 2.0 (the "License");
  6. // you may not use this file except in compliance with the License.
  7. // You may obtain a copy of the License at
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // Unless required by applicable law or agreed to in writing, software
  12. // distributed under the License is distributed on an "AS IS" BASIS,
  13. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. // See the License for the specific language governing permissions and
  15. // limitations under the License.
  16. //
  17. ////////////////////////////////////////////////////////////////////////////
  18. #import "RLMObject_Private.hpp"
  19. #import "RLMAccessor.h"
  20. #import "RLMArray_Private.hpp"
  21. #import "RLMDecimal128.h"
  22. #import "RLMListBase.h"
  23. #import "RLMObjectSchema_Private.hpp"
  24. #import "RLMObjectStore.h"
  25. #import "RLMObservation.hpp"
  26. #import "RLMOptionalBase.h"
  27. #import "RLMProperty_Private.h"
  28. #import "RLMRealm_Private.hpp"
  29. #import "RLMSchema_Private.h"
  30. #import "RLMSwiftSupport.h"
  31. #import "RLMThreadSafeReference_Private.hpp"
  32. #import "RLMUtil.hpp"
  33. #import <realm/object-store/object.hpp>
  34. #import <realm/object-store/object_schema.hpp>
  35. #import <realm/object-store/shared_realm.hpp>
  36. using namespace realm;
  37. const NSUInteger RLMDescriptionMaxDepth = 5;
  38. static bool isManagedAccessorClass(Class cls) {
  39. const char *className = class_getName(cls);
  40. const char accessorClassPrefix[] = "RLM:Managed";
  41. return strncmp(className, accessorClassPrefix, sizeof(accessorClassPrefix) - 1) == 0;
  42. }
  43. static bool maybeInitObjectSchemaForUnmanaged(RLMObjectBase *obj) {
  44. Class cls = obj.class;
  45. if (isManagedAccessorClass(cls)) {
  46. return false;
  47. }
  48. obj->_objectSchema = [cls sharedSchema];
  49. if (!obj->_objectSchema) {
  50. return false;
  51. }
  52. // set default values
  53. if (!obj->_objectSchema.isSwiftClass) {
  54. NSDictionary *dict = RLMDefaultValuesForObjectSchema(obj->_objectSchema);
  55. for (NSString *key in dict) {
  56. [obj setValue:dict[key] forKey:key];
  57. }
  58. }
  59. // set unmanaged accessor class
  60. object_setClass(obj, obj->_objectSchema.unmanagedClass);
  61. return true;
  62. }
  63. @interface RLMObjectBase () <RLMThreadConfined, RLMThreadConfined_Private>
  64. @end
  65. @implementation RLMObjectBase
  66. // unmanaged init
  67. - (instancetype)init {
  68. if ((self = [super init])) {
  69. maybeInitObjectSchemaForUnmanaged(self);
  70. }
  71. return self;
  72. }
  73. - (void)dealloc {
  74. // This can't be a unique_ptr because associated objects are removed
  75. // *after* c++ members are destroyed and dealloc is called, and we need it
  76. // to be in a validish state when that happens
  77. delete _observationInfo;
  78. _observationInfo = nullptr;
  79. }
  80. static id coerceToObjectType(id obj, Class cls, RLMSchema *schema) {
  81. if ([obj isKindOfClass:cls]) {
  82. return obj;
  83. }
  84. id value = [[cls alloc] init];
  85. RLMInitializeWithValue(value, obj, schema);
  86. return value;
  87. }
  88. static id validatedObjectForProperty(__unsafe_unretained id const obj,
  89. __unsafe_unretained RLMObjectSchema *const objectSchema,
  90. __unsafe_unretained RLMProperty *const prop,
  91. __unsafe_unretained RLMSchema *const schema) {
  92. RLMValidateValueForProperty(obj, objectSchema, prop);
  93. if (!obj || obj == NSNull.null) {
  94. return nil;
  95. }
  96. if (prop.type == RLMPropertyTypeObject) {
  97. Class objectClass = schema[prop.objectClassName].objectClass;
  98. if (prop.array) {
  99. NSMutableArray *ret = [[NSMutableArray alloc] init];
  100. for (id el in obj) {
  101. [ret addObject:coerceToObjectType(el, objectClass, schema)];
  102. }
  103. return ret;
  104. }
  105. return coerceToObjectType(obj, objectClass, schema);
  106. }
  107. else if (prop.type == RLMPropertyTypeDecimal128 && !prop.array) {
  108. return [[RLMDecimal128 alloc] initWithValue:obj];
  109. }
  110. return obj;
  111. }
  112. void RLMInitializeWithValue(RLMObjectBase *self, id value, RLMSchema *schema) {
  113. if (!value || value == NSNull.null) {
  114. @throw RLMException(@"Must provide a non-nil value.");
  115. }
  116. RLMObjectSchema *objectSchema = self->_objectSchema;
  117. if (!objectSchema) {
  118. // Will be nil if we're called during schema init, when we don't want
  119. // to actually populate the object anyway
  120. return;
  121. }
  122. NSArray *properties = objectSchema.properties;
  123. if (NSArray *array = RLMDynamicCast<NSArray>(value)) {
  124. if (array.count > properties.count) {
  125. @throw RLMException(@"Invalid array input: more values (%llu) than properties (%llu).",
  126. (unsigned long long)array.count, (unsigned long long)properties.count);
  127. }
  128. NSUInteger i = 0;
  129. for (id val in array) {
  130. RLMProperty *prop = properties[i++];
  131. [self setValue:validatedObjectForProperty(RLMCoerceToNil(val), objectSchema, prop, schema)
  132. forKey:prop.name];
  133. }
  134. }
  135. else {
  136. // assume our object is an NSDictionary or an object with kvc properties
  137. for (RLMProperty *prop in properties) {
  138. id obj = RLMValidatedValueForProperty(value, prop.name, objectSchema.className);
  139. // don't set unspecified properties
  140. if (!obj) {
  141. continue;
  142. }
  143. [self setValue:validatedObjectForProperty(RLMCoerceToNil(obj), objectSchema, prop, schema)
  144. forKey:prop.name];
  145. }
  146. }
  147. }
  148. id RLMCreateManagedAccessor(Class cls, RLMClassInfo *info) {
  149. RLMObjectBase *obj = [[cls alloc] init];
  150. obj->_info = info;
  151. obj->_realm = info->realm;
  152. obj->_objectSchema = info->rlmObjectSchema;
  153. return obj;
  154. }
  155. - (id)valueForKey:(NSString *)key {
  156. if (_observationInfo) {
  157. return _observationInfo->valueForKey(key);
  158. }
  159. return [super valueForKey:key];
  160. }
  161. // Generic Swift properties can't be dynamic, so KVO doesn't work for them by default
  162. - (id)valueForUndefinedKey:(NSString *)key {
  163. RLMProperty *prop = _objectSchema[key];
  164. if (Class accessor = prop.swiftAccessor) {
  165. return [accessor get:(char *)(__bridge void *)self + ivar_getOffset(prop.swiftIvar)];
  166. }
  167. if (Ivar ivar = prop.swiftIvar) {
  168. return RLMCoerceToNil(object_getIvar(self, ivar));
  169. }
  170. return [super valueForUndefinedKey:key];
  171. }
  172. - (void)setValue:(id)value forUndefinedKey:(NSString *)key {
  173. value = RLMCoerceToNil(value);
  174. RLMProperty *property = _objectSchema[key];
  175. if (Ivar ivar = property.swiftIvar) {
  176. if (property.array) {
  177. value = RLMAsFastEnumeration(value);
  178. RLMArray *array = [object_getIvar(self, ivar) _rlmArray];
  179. [array removeAllObjects];
  180. if (value) {
  181. [array addObjects:validatedObjectForProperty(value, _objectSchema, property,
  182. RLMSchema.partialPrivateSharedSchema)];
  183. }
  184. }
  185. else if (property.optional) {
  186. RLMSetOptional(object_getIvar(self, ivar), value);
  187. }
  188. return;
  189. }
  190. [super setValue:value forUndefinedKey:key];
  191. }
  192. // overridden at runtime per-class for performance
  193. + (NSString *)className {
  194. NSString *className = NSStringFromClass(self);
  195. if ([RLMSwiftSupport isSwiftClassName:className]) {
  196. className = [RLMSwiftSupport demangleClassName:className];
  197. }
  198. return className;
  199. }
  200. // overridden at runtime per-class for performance
  201. + (RLMObjectSchema *)sharedSchema {
  202. return [RLMSchema sharedSchemaForClass:self.class];
  203. }
  204. + (void)initializeLinkedObjectSchemas {
  205. for (RLMProperty *prop in self.sharedSchema.properties) {
  206. if (prop.type == RLMPropertyTypeObject && !RLMSchema.partialPrivateSharedSchema[prop.objectClassName]) {
  207. [[RLMSchema classForString:prop.objectClassName] initializeLinkedObjectSchemas];
  208. }
  209. }
  210. }
  211. + (nullable NSArray<RLMProperty *> *)_getProperties {
  212. return nil;
  213. }
  214. - (NSString *)description {
  215. if (self.isInvalidated) {
  216. return @"[invalid object]";
  217. }
  218. return [self descriptionWithMaxDepth:RLMDescriptionMaxDepth];
  219. }
  220. - (NSString *)descriptionWithMaxDepth:(NSUInteger)depth {
  221. if (depth == 0) {
  222. return @"<Maximum depth exceeded>";
  223. }
  224. NSString *baseClassName = _objectSchema.className;
  225. NSMutableString *mString = [NSMutableString stringWithFormat:@"%@ {\n", baseClassName];
  226. for (RLMProperty *property in _objectSchema.properties) {
  227. id object = [(id)self objectForKeyedSubscript:property.name];
  228. NSString *sub;
  229. if ([object respondsToSelector:@selector(descriptionWithMaxDepth:)]) {
  230. sub = [object descriptionWithMaxDepth:depth - 1];
  231. }
  232. else if (property.type == RLMPropertyTypeData) {
  233. static NSUInteger maxPrintedDataLength = 24;
  234. NSData *data = object;
  235. NSUInteger length = data.length;
  236. if (length > maxPrintedDataLength) {
  237. data = [NSData dataWithBytes:data.bytes length:maxPrintedDataLength];
  238. }
  239. NSString *dataDescription = [data description];
  240. sub = [NSString stringWithFormat:@"<%@ — %lu total bytes>", [dataDescription substringWithRange:NSMakeRange(1, dataDescription.length - 2)], (unsigned long)length];
  241. }
  242. else {
  243. sub = [object description];
  244. }
  245. [mString appendFormat:@"\t%@ = %@;\n", property.name, [sub stringByReplacingOccurrencesOfString:@"\n" withString:@"\n\t"]];
  246. }
  247. [mString appendString:@"}"];
  248. return [NSString stringWithString:mString];
  249. }
  250. - (RLMRealm *)realm {
  251. return _realm;
  252. }
  253. - (RLMObjectSchema *)objectSchema {
  254. return _objectSchema;
  255. }
  256. - (BOOL)isInvalidated {
  257. // if not unmanaged and our accessor has been detached, we have been deleted
  258. return self.class == _objectSchema.accessorClass && !_row.is_valid();
  259. }
  260. - (BOOL)isEqual:(id)object {
  261. if (RLMObjectBase *other = RLMDynamicCast<RLMObjectBase>(object)) {
  262. if (_objectSchema.primaryKeyProperty || _realm.isFrozen) {
  263. return RLMObjectBaseAreEqual(self, other);
  264. }
  265. }
  266. return [super isEqual:object];
  267. }
  268. - (NSUInteger)hash {
  269. if (_objectSchema.primaryKeyProperty) {
  270. // If we have a primary key property, that's an immutable value which we
  271. // can use as the identity of the object.
  272. id primaryProperty = [self valueForKey:_objectSchema.primaryKeyProperty.name];
  273. // modify the hash of our primary key value to avoid potential (although unlikely) collisions
  274. return [primaryProperty hash] ^ 1;
  275. }
  276. else if (_realm.isFrozen) {
  277. // The object key can never change for frozen objects, so that's usable
  278. // for objects without primary keys
  279. return static_cast<NSUInteger>(_row.get_key().value);
  280. }
  281. else {
  282. // Non-frozen objects without primary keys don't have any immutable
  283. // concept of identity that we can hash so we have to fall back to
  284. // pointer equality
  285. return [super hash];
  286. }
  287. }
  288. + (BOOL)shouldIncludeInDefaultSchema {
  289. return RLMIsObjectSubclass(self);
  290. }
  291. + (NSString *)primaryKey {
  292. return nil;
  293. }
  294. + (NSString *)_realmObjectName {
  295. return nil;
  296. }
  297. + (NSDictionary *)_realmColumnNames {
  298. return nil;
  299. }
  300. + (bool)_realmIgnoreClass {
  301. return false;
  302. }
  303. + (bool)isEmbedded {
  304. return false;
  305. }
  306. - (id)mutableArrayValueForKey:(NSString *)key {
  307. id obj = [self valueForKey:key];
  308. if ([obj isKindOfClass:[RLMArray class]]) {
  309. return obj;
  310. }
  311. return [super mutableArrayValueForKey:key];
  312. }
  313. - (void)addObserver:(id)observer
  314. forKeyPath:(NSString *)keyPath
  315. options:(NSKeyValueObservingOptions)options
  316. context:(void *)context {
  317. if (!_observationInfo) {
  318. _observationInfo = new RLMObservationInfo(self);
  319. }
  320. _observationInfo->recordObserver(_row, _info, _objectSchema, keyPath);
  321. [super addObserver:observer forKeyPath:keyPath options:options context:context];
  322. }
  323. - (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath {
  324. [super removeObserver:observer forKeyPath:keyPath];
  325. if (_observationInfo)
  326. _observationInfo->removeObserver();
  327. }
  328. + (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key {
  329. if (isManagedAccessorClass(self) && [class_getSuperclass(self.class) sharedSchema][key]) {
  330. return NO;
  331. }
  332. return [super automaticallyNotifiesObserversForKey:key];
  333. }
  334. #pragma mark - Thread Confined Protocol Conformance
  335. - (realm::ThreadSafeReference)makeThreadSafeReference {
  336. return Object(_realm->_realm, *_info->objectSchema, _row);
  337. }
  338. - (id)objectiveCMetadata {
  339. return nil;
  340. }
  341. + (instancetype)objectWithThreadSafeReference:(realm::ThreadSafeReference)reference
  342. metadata:(__unused id)metadata
  343. realm:(RLMRealm *)realm {
  344. Object object = reference.resolve<Object>(realm->_realm);
  345. if (!object.is_valid()) {
  346. return nil;
  347. }
  348. NSString *objectClassName = @(object.get_object_schema().name.c_str());
  349. return RLMCreateObjectAccessor(realm->_info[objectClassName], object.obj());
  350. }
  351. @end
  352. RLMRealm *RLMObjectBaseRealm(__unsafe_unretained RLMObjectBase *object) {
  353. return object ? object->_realm : nil;
  354. }
  355. RLMObjectSchema *RLMObjectBaseObjectSchema(__unsafe_unretained RLMObjectBase *object) {
  356. return object ? object->_objectSchema : nil;
  357. }
  358. id RLMObjectBaseObjectForKeyedSubscript(RLMObjectBase *object, NSString *key) {
  359. if (!object) {
  360. return nil;
  361. }
  362. if (object->_realm) {
  363. return RLMDynamicGetByName(object, key);
  364. }
  365. else {
  366. return [object valueForKey:key];
  367. }
  368. }
  369. void RLMObjectBaseSetObjectForKeyedSubscript(RLMObjectBase *object, NSString *key, id obj) {
  370. if (!object) {
  371. return;
  372. }
  373. if (object->_realm || object.class == object->_objectSchema.accessorClass) {
  374. RLMDynamicValidatedSet(object, key, obj);
  375. }
  376. else {
  377. [object setValue:obj forKey:key];
  378. }
  379. }
  380. BOOL RLMObjectBaseAreEqual(RLMObjectBase *o1, RLMObjectBase *o2) {
  381. // if not the correct types throw
  382. if ((o1 && ![o1 isKindOfClass:RLMObjectBase.class]) || (o2 && ![o2 isKindOfClass:RLMObjectBase.class])) {
  383. @throw RLMException(@"Can only compare objects of class RLMObjectBase");
  384. }
  385. // if identical object (or both are nil)
  386. if (o1 == o2) {
  387. return YES;
  388. }
  389. // if one is nil
  390. if (o1 == nil || o2 == nil) {
  391. return NO;
  392. }
  393. // if not in realm or differing realms
  394. if (o1->_realm == nil || o1->_realm != o2->_realm) {
  395. return NO;
  396. }
  397. // if either are detached
  398. if (!o1->_row.is_valid() || !o2->_row.is_valid()) {
  399. return NO;
  400. }
  401. // if table and index are the same
  402. return o1->_row.get_table() == o2->_row.get_table()
  403. && o1->_row.get_key() == o2->_row.get_key();
  404. }
  405. id RLMObjectFreeze(RLMObjectBase *obj) {
  406. if (!obj->_realm && !obj.isInvalidated) {
  407. @throw RLMException(@"Unmanaged objects cannot be frozen.");
  408. }
  409. RLMVerifyAttached(obj);
  410. if (obj->_realm.frozen) {
  411. return obj;
  412. }
  413. RLMRealm *frozenRealm = [obj->_realm freeze];
  414. RLMObjectBase *frozen = RLMCreateManagedAccessor(obj.class, &frozenRealm->_info[obj->_info->rlmObjectSchema.className]);
  415. frozen->_row = frozenRealm->_realm->import_copy_of(obj->_row);
  416. if (!frozen->_row.is_valid()) {
  417. @throw RLMException(@"Cannot freeze an object in the same write transaction as it was created in.");
  418. }
  419. RLMInitializeSwiftAccessorGenerics(frozen);
  420. return frozen;
  421. }
  422. id RLMObjectThaw(RLMObjectBase *obj) {
  423. if (!obj->_realm && !obj.isInvalidated) {
  424. @throw RLMException(@"Unmanaged objects cannot be frozen.");
  425. }
  426. RLMVerifyAttached(obj);
  427. if (!obj->_realm.frozen) {
  428. return obj;
  429. }
  430. RLMRealm *liveRealm = [obj->_realm thaw];
  431. RLMObjectBase *live = RLMCreateManagedAccessor(obj.class, &liveRealm->_info[obj->_info->rlmObjectSchema.className]);
  432. live->_row = liveRealm->_realm->import_copy_of(obj->_row);
  433. if (!live->_row.is_valid()) {
  434. return nil;
  435. }
  436. RLMInitializeSwiftAccessorGenerics(live);
  437. return live;
  438. }
  439. id RLMValidatedValueForProperty(id object, NSString *key, NSString *className) {
  440. @try {
  441. return [object valueForKey:key];
  442. }
  443. @catch (NSException *e) {
  444. if ([e.name isEqualToString:NSUndefinedKeyException]) {
  445. @throw RLMException(@"Invalid value '%@' to initialize object of type '%@': missing key '%@'",
  446. object, className, key);
  447. }
  448. @throw;
  449. }
  450. }
  451. #pragma mark - Notifications
  452. namespace {
  453. struct ObjectChangeCallbackWrapper {
  454. RLMObjectNotificationCallback block;
  455. RLMObjectBase *object;
  456. NSArray<NSString *> *propertyNames = nil;
  457. NSArray *oldValues = nil;
  458. bool deleted = false;
  459. void populateProperties(realm::CollectionChangeSet const& c) {
  460. if (propertyNames) {
  461. return;
  462. }
  463. if (!c.deletions.empty()) {
  464. deleted = true;
  465. return;
  466. }
  467. if (c.columns.empty()) {
  468. return;
  469. }
  470. auto properties = [NSMutableArray new];
  471. for (RLMProperty *property in object->_info->rlmObjectSchema.properties) {
  472. if (c.columns.count(object->_info->tableColumn(property).value)) {
  473. [properties addObject:property.name];
  474. }
  475. }
  476. if (properties.count) {
  477. propertyNames = properties;
  478. }
  479. }
  480. NSArray *readValues(realm::CollectionChangeSet const& c) {
  481. if (c.empty()) {
  482. return nil;
  483. }
  484. populateProperties(c);
  485. if (!propertyNames) {
  486. return nil;
  487. }
  488. auto values = [NSMutableArray arrayWithCapacity:propertyNames.count];
  489. for (NSString *name in propertyNames) {
  490. id value = [object valueForKey:name];
  491. if (!value || [value isKindOfClass:[RLMArray class]]) {
  492. [values addObject:NSNull.null];
  493. }
  494. else {
  495. [values addObject:value];
  496. }
  497. }
  498. return values;
  499. }
  500. void before(realm::CollectionChangeSet const& c) {
  501. @autoreleasepool {
  502. oldValues = readValues(c);
  503. }
  504. }
  505. void after(realm::CollectionChangeSet const& c) {
  506. @autoreleasepool {
  507. auto newValues = readValues(c);
  508. if (deleted) {
  509. block(nil, nil, nil, nil, nil);
  510. }
  511. else if (newValues) {
  512. block(object, propertyNames, oldValues, newValues, nil);
  513. }
  514. propertyNames = nil;
  515. oldValues = nil;
  516. }
  517. }
  518. void error(std::exception_ptr err) {
  519. @autoreleasepool {
  520. try {
  521. rethrow_exception(err);
  522. }
  523. catch (...) {
  524. NSError *error = nil;
  525. RLMRealmTranslateException(&error);
  526. block(nil, nil, nil, nil, error);
  527. }
  528. }
  529. }
  530. };
  531. } // anonymous namespace
  532. @interface RLMPropertyChange ()
  533. @property (nonatomic, readwrite, strong) NSString *name;
  534. @property (nonatomic, readwrite, strong, nullable) id previousValue;
  535. @property (nonatomic, readwrite, strong, nullable) id value;
  536. @end
  537. @implementation RLMPropertyChange
  538. - (NSString *)description {
  539. return [NSString stringWithFormat:@"<RLMPropertyChange: %p> %@ %@ -> %@",
  540. (__bridge void *)self, _name, _previousValue, _value];
  541. }
  542. @end
  543. @interface RLMObjectNotificationToken : RLMNotificationToken
  544. @end
  545. @implementation RLMObjectNotificationToken {
  546. std::mutex _mutex;
  547. __unsafe_unretained RLMRealm *_realm;
  548. realm::Object _object;
  549. realm::NotificationToken _token;
  550. }
  551. - (RLMRealm *)realm {
  552. return _realm;
  553. }
  554. - (void)suppressNextNotification {
  555. std::lock_guard<std::mutex> lock(_mutex);
  556. if (_object.is_valid()) {
  557. _token.suppress_next();
  558. }
  559. }
  560. - (void)invalidate {
  561. std::lock_guard<std::mutex> lock(_mutex);
  562. _realm = nil;
  563. _token = {};
  564. _object = {};
  565. }
  566. - (void)addNotificationBlock:(RLMObjectNotificationCallback)block
  567. threadSafeReference:(RLMThreadSafeReference *)tsr
  568. config:(RLMRealmConfiguration *)config
  569. queue:(dispatch_queue_t)queue {
  570. std::lock_guard<std::mutex> lock(_mutex);
  571. if (!_realm) {
  572. // Token was invalidated before we got this far
  573. return;
  574. }
  575. NSError *error;
  576. RLMRealm *realm = _realm = [RLMRealm realmWithConfiguration:config queue:queue error:&error];
  577. if (!realm) {
  578. block(nil, nil, nil, nil, error);
  579. return;
  580. }
  581. RLMObjectBase *obj = [realm resolveThreadSafeReference:tsr];
  582. _object = realm::Object(obj->_realm->_realm, *obj->_info->objectSchema, obj->_row);
  583. _token = _object.add_notification_callback(ObjectChangeCallbackWrapper{block, obj});
  584. }
  585. - (void)addNotificationBlock:(RLMObjectNotificationCallback)block object:(RLMObjectBase *)obj {
  586. _object = realm::Object(obj->_realm->_realm, *obj->_info->objectSchema, obj->_row);
  587. _realm = obj->_realm;
  588. _token = _object.add_notification_callback(ObjectChangeCallbackWrapper{block, obj});
  589. }
  590. RLMNotificationToken *RLMObjectBaseAddNotificationBlock(RLMObjectBase *obj, dispatch_queue_t queue,
  591. RLMObjectNotificationCallback block) {
  592. if (!obj->_realm) {
  593. @throw RLMException(@"Only objects which are managed by a Realm support change notifications");
  594. }
  595. if (!queue) {
  596. [obj->_realm verifyNotificationsAreSupported:true];
  597. auto token = [[RLMObjectNotificationToken alloc] init];
  598. token->_realm = obj->_realm;
  599. [token addNotificationBlock:block object:obj];
  600. return token;
  601. }
  602. RLMThreadSafeReference *tsr = [RLMThreadSafeReference referenceWithThreadConfined:(id)obj];
  603. auto token = [[RLMObjectNotificationToken alloc] init];
  604. token->_realm = obj->_realm;
  605. RLMRealmConfiguration *config = obj->_realm.configuration;
  606. dispatch_async(queue, ^{
  607. @autoreleasepool {
  608. [token addNotificationBlock:block threadSafeReference:tsr config:config queue:queue];
  609. }
  610. });
  611. return token;
  612. }
  613. @end
  614. RLMNotificationToken *RLMObjectAddNotificationBlock(RLMObjectBase *obj, RLMObjectChangeBlock block, dispatch_queue_t queue) {
  615. return RLMObjectBaseAddNotificationBlock(obj, queue, ^(RLMObjectBase *, NSArray<NSString *> *propertyNames,
  616. NSArray *oldValues, NSArray *newValues, NSError *error) {
  617. if (error) {
  618. block(false, nil, error);
  619. }
  620. else if (!propertyNames) {
  621. block(true, nil, nil);
  622. }
  623. else {
  624. auto properties = [NSMutableArray arrayWithCapacity:propertyNames.count];
  625. for (NSUInteger i = 0, count = propertyNames.count; i < count; ++i) {
  626. auto prop = [RLMPropertyChange new];
  627. prop.name = propertyNames[i];
  628. prop.previousValue = RLMCoerceToNil(oldValues[i]);
  629. prop.value = RLMCoerceToNil(newValues[i]);
  630. [properties addObject:prop];
  631. }
  632. block(false, properties, nil);
  633. }
  634. });
  635. }
  636. uint64_t RLMObjectBaseGetCombineId(__unsafe_unretained RLMObjectBase *const obj) {
  637. if (obj.invalidated) {
  638. RLMVerifyAttached(obj);
  639. }
  640. if (obj->_realm) {
  641. return obj->_row.get_key().value;
  642. }
  643. return reinterpret_cast<uint64_t>((__bridge void *)obj);
  644. }
  645. @implementation RealmSwiftObject
  646. @end
  647. @implementation RealmSwiftEmbeddedObject
  648. @end