RLMAccessor.mm 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197
  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 "RLMAccessor.hpp"
  19. #import "RLMArray_Private.hpp"
  20. #import "RLMDictionary_Private.hpp"
  21. #import "RLMObjectId_Private.hpp"
  22. #import "RLMObjectSchema_Private.hpp"
  23. #import "RLMObjectStore.h"
  24. #import "RLMObject_Private.hpp"
  25. #import "RLMObservation.hpp"
  26. #import "RLMProperty_Private.h"
  27. #import "RLMRealm_Private.hpp"
  28. #import "RLMResults_Private.hpp"
  29. #import "RLMSchema_Private.h"
  30. #import "RLMSet_Private.hpp"
  31. #import "RLMSwiftProperty.h"
  32. #import "RLMUUID_Private.hpp"
  33. #import "RLMUtil.hpp"
  34. #import <realm/object-store/results.hpp>
  35. #import <realm/object-store/property.hpp>
  36. #import <objc/runtime.h>
  37. #import <objc/message.h>
  38. #pragma mark Helper functions
  39. using realm::ColKey;
  40. namespace realm {
  41. template<>
  42. Obj Obj::get<Obj>(ColKey col) const {
  43. ObjKey key = get<ObjKey>(col);
  44. return key ? get_target_table(col)->get_object(key) : Obj();
  45. }
  46. } // namespace realm
  47. namespace {
  48. realm::Property const& getProperty(__unsafe_unretained RLMObjectBase *const obj, NSUInteger index) {
  49. return obj->_info->objectSchema->persisted_properties[index];
  50. }
  51. realm::Property const& getProperty(__unsafe_unretained RLMObjectBase *const obj,
  52. __unsafe_unretained RLMProperty *const prop) {
  53. if (prop.linkOriginPropertyName) {
  54. return obj->_info->objectSchema->computed_properties[prop.index];
  55. }
  56. return obj->_info->objectSchema->persisted_properties[prop.index];
  57. }
  58. template<typename T>
  59. bool isNull(T const& v) {
  60. return !v;
  61. }
  62. template<>
  63. bool isNull(realm::Timestamp const& v) {
  64. return v.is_null();
  65. }
  66. template<>
  67. bool isNull(realm::ObjectId const&) {
  68. return false;
  69. }
  70. template<>
  71. bool isNull(realm::Decimal128 const& v) {
  72. return v.is_null();
  73. }
  74. template<>
  75. bool isNull(realm::Mixed const& v) {
  76. return v.is_null();
  77. }
  78. template<>
  79. bool isNull(realm::UUID const&) {
  80. return false;
  81. }
  82. template<typename T>
  83. T get(__unsafe_unretained RLMObjectBase *const obj, NSUInteger index) {
  84. RLMVerifyAttached(obj);
  85. return obj->_row.get<T>(getProperty(obj, index).column_key);
  86. }
  87. template<typename T>
  88. id getBoxed(__unsafe_unretained RLMObjectBase *const obj, NSUInteger index) {
  89. RLMVerifyAttached(obj);
  90. auto& prop = getProperty(obj, index);
  91. RLMAccessorContext ctx(obj, &prop);
  92. auto value = obj->_row.get<T>(prop.column_key);
  93. return isNull(value) ? nil : ctx.box(std::move(value));
  94. }
  95. template<typename T>
  96. T getOptional(__unsafe_unretained RLMObjectBase *const obj, uint16_t key, bool *gotValue) {
  97. auto ret = get<std::optional<T>>(obj, key);
  98. if (ret) {
  99. *gotValue = true;
  100. }
  101. return ret.value_or(T{});
  102. }
  103. template<typename T>
  104. void setValue(__unsafe_unretained RLMObjectBase *const obj, ColKey key, T val) {
  105. obj->_row.set(key, val);
  106. }
  107. template<typename T>
  108. void setValueOrNull(__unsafe_unretained RLMObjectBase *const obj, ColKey col,
  109. __unsafe_unretained id const value) {
  110. RLMVerifyInWriteTransaction(obj);
  111. RLMTranslateError([&] {
  112. if (value) {
  113. if constexpr (std::is_same_v<T, realm::Mixed>) {
  114. obj->_row.set(col, RLMObjcToMixed(value, obj->_realm, realm::CreatePolicy::SetLink));
  115. }
  116. else {
  117. RLMStatelessAccessorContext ctx;
  118. obj->_row.set(col, ctx.unbox<T>(value));
  119. }
  120. }
  121. else {
  122. obj->_row.set_null(col);
  123. }
  124. });
  125. }
  126. void setValue(__unsafe_unretained RLMObjectBase *const obj,
  127. ColKey key, __unsafe_unretained NSDate *const date) {
  128. setValueOrNull<realm::Timestamp>(obj, key, date);
  129. }
  130. void setValue(__unsafe_unretained RLMObjectBase *const obj, ColKey key,
  131. __unsafe_unretained NSData *const value) {
  132. setValueOrNull<realm::BinaryData>(obj, key, value);
  133. }
  134. void setValue(__unsafe_unretained RLMObjectBase *const obj, ColKey key,
  135. __unsafe_unretained NSString *const value) {
  136. setValueOrNull<realm::StringData>(obj, key, value);
  137. }
  138. void setValue(__unsafe_unretained RLMObjectBase *const obj, ColKey key,
  139. __unsafe_unretained RLMObjectBase *const val) {
  140. if (!val) {
  141. obj->_row.set(key, realm::null());
  142. return;
  143. }
  144. if (!val->_row) {
  145. RLMAccessorContext{obj, key}.createObject(val, {.create = true}, false, {});
  146. }
  147. // make sure it is the correct type
  148. auto table = val->_row.get_table();
  149. if (table != obj->_row.get_table()->get_link_target(key)) {
  150. @throw RLMException(@"Can't set object of type '%@' to property of type '%@'",
  151. val->_objectSchema.className,
  152. obj->_info->propertyForTableColumn(key).objectClassName);
  153. }
  154. if (!table->is_embedded()) {
  155. obj->_row.set(key, val->_row.get_key());
  156. }
  157. else if (obj->_row.get_linked_object(key).get_key() != val->_row.get_key()) {
  158. @throw RLMException(@"Can't set link to existing managed embedded object");
  159. }
  160. }
  161. id RLMCollectionClassForProperty(RLMProperty *prop, bool isManaged) {
  162. Class cls = nil;
  163. if (prop.array) {
  164. cls = isManaged ? [RLMManagedArray class] : [RLMArray class];
  165. } else if (prop.set) {
  166. cls = isManaged ? [RLMManagedSet class] : [RLMSet class];
  167. } else if (prop.dictionary) {
  168. cls = isManaged ? [RLMManagedDictionary class] : [RLMDictionary class];
  169. } else {
  170. @throw RLMException(@"Invalid collection '%@' for class '%@'.",
  171. prop.name, prop.objectClassName);
  172. }
  173. return cls;
  174. }
  175. // collection getter/setter
  176. id<RLMCollection> getCollection(__unsafe_unretained RLMObjectBase *const obj, NSUInteger propIndex) {
  177. RLMVerifyAttached(obj);
  178. auto prop = obj->_info->rlmObjectSchema.properties[propIndex];
  179. Class cls = RLMCollectionClassForProperty(prop, true);
  180. return [[cls alloc] initWithParent:obj property:prop];
  181. }
  182. template <typename Collection>
  183. void assignValue(__unsafe_unretained RLMObjectBase *const obj,
  184. __unsafe_unretained RLMProperty *const prop,
  185. ColKey key,
  186. __unsafe_unretained id<NSFastEnumeration> const value) {
  187. auto info = obj->_info;
  188. Collection collection(obj->_realm->_realm, obj->_row, key);
  189. if (collection.get_type() == realm::PropertyType::Object) {
  190. info = &obj->_info->linkTargetType(prop.index);
  191. }
  192. RLMAccessorContext ctx(*info);
  193. RLMTranslateError([&] {
  194. collection.assign(ctx, value, realm::CreatePolicy::ForceCreate);
  195. });
  196. }
  197. void setValue(__unsafe_unretained RLMObjectBase *const obj, ColKey key,
  198. __unsafe_unretained id<NSFastEnumeration> const value) {
  199. auto prop = obj->_info->propertyForTableColumn(key);
  200. RLMValidateValueForProperty(value, obj->_info->rlmObjectSchema, prop, true);
  201. if (prop.array) {
  202. assignValue<realm::List>(obj, prop, key, value);
  203. }
  204. else if (prop.set) {
  205. assignValue<realm::object_store::Set>(obj, prop, key, value);
  206. }
  207. else if (prop.dictionary) {
  208. assignValue<realm::object_store::Dictionary>(obj, prop, key, value);
  209. }
  210. }
  211. void setValue(__unsafe_unretained RLMObjectBase *const obj, ColKey key,
  212. __unsafe_unretained NSNumber<RLMInt> *const intObject) {
  213. setValueOrNull<int64_t>(obj, key, intObject);
  214. }
  215. void setValue(__unsafe_unretained RLMObjectBase *const obj, ColKey key,
  216. __unsafe_unretained NSNumber<RLMFloat> *const floatObject) {
  217. setValueOrNull<float>(obj, key, floatObject);
  218. }
  219. void setValue(__unsafe_unretained RLMObjectBase *const obj, ColKey key,
  220. __unsafe_unretained NSNumber<RLMDouble> *const doubleObject) {
  221. setValueOrNull<double>(obj, key, doubleObject);
  222. }
  223. void setValue(__unsafe_unretained RLMObjectBase *const obj, ColKey key,
  224. __unsafe_unretained NSNumber<RLMBool> *const boolObject) {
  225. setValueOrNull<bool>(obj, key, boolObject);
  226. }
  227. void setValue(__unsafe_unretained RLMObjectBase *const obj, ColKey key,
  228. __unsafe_unretained RLMDecimal128 *const value) {
  229. setValueOrNull<realm::Decimal128>(obj, key, value);
  230. }
  231. void setValue(__unsafe_unretained RLMObjectBase *const obj, ColKey key,
  232. __unsafe_unretained RLMObjectId *const value) {
  233. setValueOrNull<realm::ObjectId>(obj, key, value);
  234. }
  235. void setValue(__unsafe_unretained RLMObjectBase *const obj, ColKey key,
  236. __unsafe_unretained NSUUID *const value) {
  237. setValueOrNull<realm::UUID>(obj, key, value);
  238. }
  239. void setValue(__unsafe_unretained RLMObjectBase *const obj, ColKey key,
  240. __unsafe_unretained id<RLMValue> const value) {
  241. setValueOrNull<realm::Mixed>(obj, key, value);
  242. }
  243. RLMLinkingObjects *getLinkingObjects(__unsafe_unretained RLMObjectBase *const obj,
  244. __unsafe_unretained RLMProperty *const property) {
  245. RLMVerifyAttached(obj);
  246. auto& objectInfo = obj->_realm->_info[property.objectClassName];
  247. auto& linkOrigin = obj->_info->objectSchema->computed_properties[property.index].link_origin_property_name;
  248. auto linkingProperty = objectInfo.objectSchema->property_for_name(linkOrigin);
  249. auto backlinkView = obj->_row.get_backlink_view(objectInfo.table(), linkingProperty->column_key);
  250. realm::Results results(obj->_realm->_realm, std::move(backlinkView));
  251. return [RLMLinkingObjects resultsWithObjectInfo:objectInfo results:std::move(results)];
  252. }
  253. // any getter/setter
  254. template<typename Type, typename StorageType=Type>
  255. id makeGetter(NSUInteger index) {
  256. return ^(__unsafe_unretained RLMObjectBase *const obj) {
  257. return static_cast<Type>(get<StorageType>(obj, index));
  258. };
  259. }
  260. template<typename Type>
  261. id makeBoxedGetter(NSUInteger index) {
  262. return ^(__unsafe_unretained RLMObjectBase *const obj) {
  263. return getBoxed<Type>(obj, index);
  264. };
  265. }
  266. template<typename Type>
  267. id makeOptionalGetter(NSUInteger index) {
  268. return ^(__unsafe_unretained RLMObjectBase *const obj) {
  269. return getBoxed<std::optional<Type>>(obj, index);
  270. };
  271. }
  272. template<typename Type>
  273. id makeNumberGetter(NSUInteger index, bool boxed, bool optional) {
  274. if (optional) {
  275. return makeOptionalGetter<Type>(index);
  276. }
  277. if (boxed) {
  278. return makeBoxedGetter<Type>(index);
  279. }
  280. return makeGetter<Type>(index);
  281. }
  282. template<typename Type>
  283. id makeWrapperGetter(NSUInteger index, bool optional) {
  284. if (optional) {
  285. return makeOptionalGetter<Type>(index);
  286. }
  287. return makeBoxedGetter<Type>(index);
  288. }
  289. // dynamic getter with column closure
  290. id managedGetter(RLMProperty *prop, const char *type) {
  291. NSUInteger index = prop.index;
  292. if (prop.collection && prop.type != RLMPropertyTypeLinkingObjects) {
  293. return ^id(__unsafe_unretained RLMObjectBase *const obj) {
  294. return getCollection(obj, index);
  295. };
  296. }
  297. bool boxed = *type == '@';
  298. switch (prop.type) {
  299. case RLMPropertyTypeInt:
  300. if (prop.optional || boxed) {
  301. return makeNumberGetter<long long>(index, boxed, prop.optional);
  302. }
  303. switch (*type) {
  304. case 'c': return makeGetter<char, int64_t>(index);
  305. case 's': return makeGetter<short, int64_t>(index);
  306. case 'i': return makeGetter<int, int64_t>(index);
  307. case 'l': return makeGetter<long, int64_t>(index);
  308. case 'q': return makeGetter<long long, int64_t>(index);
  309. default:
  310. @throw RLMException(@"Unexpected property type for Objective-C type code");
  311. }
  312. case RLMPropertyTypeFloat:
  313. return makeNumberGetter<float>(index, boxed, prop.optional);
  314. case RLMPropertyTypeDouble:
  315. return makeNumberGetter<double>(index, boxed, prop.optional);
  316. case RLMPropertyTypeBool:
  317. return makeNumberGetter<bool>(index, boxed, prop.optional);
  318. case RLMPropertyTypeString:
  319. return makeBoxedGetter<realm::StringData>(index);
  320. case RLMPropertyTypeDate:
  321. return makeBoxedGetter<realm::Timestamp>(index);
  322. case RLMPropertyTypeData:
  323. return makeBoxedGetter<realm::BinaryData>(index);
  324. case RLMPropertyTypeObject:
  325. return makeBoxedGetter<realm::Obj>(index);
  326. case RLMPropertyTypeDecimal128:
  327. return makeBoxedGetter<realm::Decimal128>(index);
  328. case RLMPropertyTypeObjectId:
  329. return makeWrapperGetter<realm::ObjectId>(index, prop.optional);
  330. case RLMPropertyTypeAny:
  331. // Mixed is represented as optional in Core,
  332. // but not in Cocoa. We use `makeBoxedGetter` over
  333. // `makeWrapperGetter` becuase Mixed can box a `null` representation.
  334. return makeBoxedGetter<realm::Mixed>(index);
  335. case RLMPropertyTypeLinkingObjects:
  336. return ^(__unsafe_unretained RLMObjectBase *const obj) {
  337. return getLinkingObjects(obj, prop);
  338. };
  339. case RLMPropertyTypeUUID:
  340. return makeWrapperGetter<realm::UUID>(index, prop.optional);
  341. }
  342. }
  343. static realm::ColKey willChange(RLMObservationTracker& tracker,
  344. __unsafe_unretained RLMObjectBase *const obj, NSUInteger index) {
  345. auto& prop = getProperty(obj, index);
  346. if (prop.is_primary) {
  347. @throw RLMException(@"Primary key can't be changed after an object is inserted.");
  348. }
  349. tracker.willChange(RLMGetObservationInfo(obj->_observationInfo, obj->_row.get_key(), *obj->_info),
  350. obj->_objectSchema.properties[index].name);
  351. return prop.column_key;
  352. }
  353. template<typename ArgType, typename StorageType=ArgType>
  354. void kvoSetValue(__unsafe_unretained RLMObjectBase *const obj, NSUInteger index, ArgType value) {
  355. RLMVerifyInWriteTransaction(obj);
  356. RLMObservationTracker tracker(obj->_realm);
  357. auto key = willChange(tracker, obj, index);
  358. if constexpr (std::is_same_v<ArgType, RLMObjectBase *>) {
  359. tracker.trackDeletions();
  360. }
  361. setValue(obj, key, static_cast<StorageType>(value));
  362. }
  363. template<typename ArgType, typename StorageType=ArgType>
  364. id makeSetter(__unsafe_unretained RLMProperty *const prop) {
  365. if (prop.isPrimary) {
  366. return ^(__unused RLMObjectBase *obj, __unused ArgType val) {
  367. @throw RLMException(@"Primary key can't be changed after an object is inserted.");
  368. };
  369. }
  370. NSUInteger index = prop.index;
  371. return ^(__unsafe_unretained RLMObjectBase *const obj, ArgType val) {
  372. kvoSetValue<ArgType, StorageType>(obj, index, val);
  373. };
  374. }
  375. // dynamic setter with column closure
  376. id managedSetter(RLMProperty *prop, const char *type) {
  377. if (prop.collection && prop.type != RLMPropertyTypeLinkingObjects) {
  378. return makeSetter<id<NSFastEnumeration>>(prop);
  379. }
  380. bool boxed = prop.optional || *type == '@';
  381. switch (prop.type) {
  382. case RLMPropertyTypeInt:
  383. if (boxed) {
  384. return makeSetter<NSNumber<RLMInt> *>(prop);
  385. }
  386. switch (*type) {
  387. case 'c': return makeSetter<char, long long>(prop);
  388. case 's': return makeSetter<short, long long>(prop);
  389. case 'i': return makeSetter<int, long long>(prop);
  390. case 'l': return makeSetter<long, long long>(prop);
  391. case 'q': return makeSetter<long long>(prop);
  392. default:
  393. @throw RLMException(@"Unexpected property type for Objective-C type code");
  394. }
  395. case RLMPropertyTypeFloat:
  396. return boxed ? makeSetter<NSNumber<RLMFloat> *>(prop) : makeSetter<float>(prop);
  397. case RLMPropertyTypeDouble:
  398. return boxed ? makeSetter<NSNumber<RLMDouble> *>(prop) : makeSetter<double>(prop);
  399. case RLMPropertyTypeBool:
  400. return boxed ? makeSetter<NSNumber<RLMBool> *>(prop) : makeSetter<BOOL, bool>(prop);
  401. case RLMPropertyTypeString: return makeSetter<NSString *>(prop);
  402. case RLMPropertyTypeDate: return makeSetter<NSDate *>(prop);
  403. case RLMPropertyTypeData: return makeSetter<NSData *>(prop);
  404. case RLMPropertyTypeAny: return makeSetter<id<RLMValue>>(prop);
  405. case RLMPropertyTypeLinkingObjects: return nil;
  406. case RLMPropertyTypeObject: return makeSetter<RLMObjectBase *>(prop);
  407. case RLMPropertyTypeObjectId: return makeSetter<RLMObjectId *>(prop);
  408. case RLMPropertyTypeDecimal128: return makeSetter<RLMDecimal128 *>(prop);
  409. case RLMPropertyTypeUUID: return makeSetter<NSUUID *>(prop);
  410. }
  411. }
  412. // call getter for superclass for property at key
  413. id superGet(RLMObjectBase *obj, NSString *propName) {
  414. typedef id (*getter_type)(RLMObjectBase *, SEL);
  415. RLMProperty *prop = obj->_objectSchema[propName];
  416. Class superClass = class_getSuperclass(obj.class);
  417. getter_type superGetter = (getter_type)[superClass instanceMethodForSelector:prop.getterSel];
  418. return superGetter(obj, prop.getterSel);
  419. }
  420. // call setter for superclass for property at key
  421. void superSet(RLMObjectBase *obj, NSString *propName, id val) {
  422. typedef void (*setter_type)(RLMObjectBase *, SEL, id<RLMCollection> collection);
  423. RLMProperty *prop = obj->_objectSchema[propName];
  424. Class superClass = class_getSuperclass(obj.class);
  425. setter_type superSetter = (setter_type)[superClass instanceMethodForSelector:prop.setterSel];
  426. superSetter(obj, prop.setterSel, val);
  427. }
  428. // getter/setter for unmanaged object
  429. id unmanagedGetter(RLMProperty *prop, const char *) {
  430. // only override getters for RLMCollection and linking objects properties
  431. if (prop.type == RLMPropertyTypeLinkingObjects) {
  432. return ^(RLMObjectBase *) { return [RLMResults emptyDetachedResults]; };
  433. }
  434. if (prop.collection) {
  435. NSString *propName = prop.name;
  436. Class cls = RLMCollectionClassForProperty(prop, false);
  437. if (prop.type == RLMPropertyTypeObject) {
  438. NSString *objectClassName = prop.objectClassName;
  439. RLMPropertyType keyType = prop.dictionaryKeyType;
  440. return ^(RLMObjectBase *obj) {
  441. id val = superGet(obj, propName);
  442. if (!val) {
  443. val = [[cls alloc] initWithObjectClassName:objectClassName keyType:keyType];
  444. superSet(obj, propName, val);
  445. }
  446. return val;
  447. };
  448. }
  449. auto type = prop.type;
  450. auto optional = prop.optional;
  451. auto dictionaryKeyType = prop.dictionaryKeyType;
  452. return ^(RLMObjectBase *obj) {
  453. id val = superGet(obj, propName);
  454. if (!val) {
  455. val = [[cls alloc] initWithObjectType:type optional:optional keyType:dictionaryKeyType];
  456. superSet(obj, propName, val);
  457. }
  458. return val;
  459. };
  460. }
  461. return nil;
  462. }
  463. id unmanagedSetter(RLMProperty *prop, const char *) {
  464. // Only RLMCollection types need special handling for the unmanaged setter
  465. if (!prop.collection) {
  466. return nil;
  467. }
  468. NSString *propName = prop.name;
  469. return ^(RLMObjectBase *obj, id<NSFastEnumeration> values) {
  470. auto prop = obj->_objectSchema[propName];
  471. RLMValidateValueForProperty(values, obj->_objectSchema, prop, true);
  472. Class cls = RLMCollectionClassForProperty(prop, false);
  473. id collection;
  474. // make copy when setting (as is the case for all other variants)
  475. if (prop.type == RLMPropertyTypeObject) {
  476. collection = [[cls alloc] initWithObjectClassName:prop.objectClassName keyType:prop.dictionaryKeyType];
  477. }
  478. else {
  479. collection = [[cls alloc] initWithObjectType:prop.type optional:prop.optional keyType:prop.dictionaryKeyType];
  480. }
  481. if (prop.dictionary)
  482. [collection addEntriesFromDictionary:(id)values];
  483. else
  484. [collection addObjects:values];
  485. superSet(obj, propName, collection);
  486. };
  487. }
  488. void addMethod(Class cls, __unsafe_unretained RLMProperty *const prop,
  489. id (*getter)(RLMProperty *, const char *),
  490. id (*setter)(RLMProperty *, const char *)) {
  491. SEL sel = prop.getterSel;
  492. if (!sel) {
  493. return;
  494. }
  495. auto getterMethod = class_getInstanceMethod(cls, sel);
  496. if (!getterMethod) {
  497. return;
  498. }
  499. const char *getterType = method_getTypeEncoding(getterMethod);
  500. if (id block = getter(prop, getterType)) {
  501. class_addMethod(cls, sel, imp_implementationWithBlock(block), getterType);
  502. }
  503. if (!(sel = prop.setterSel)) {
  504. return;
  505. }
  506. auto setterMethod = class_getInstanceMethod(cls, sel);
  507. if (!setterMethod) {
  508. return;
  509. }
  510. if (id block = setter(prop, getterType)) { // note: deliberately getterType as it's easier to grab the relevant type from
  511. class_addMethod(cls, sel, imp_implementationWithBlock(block), method_getTypeEncoding(setterMethod));
  512. }
  513. }
  514. Class createAccessorClass(Class objectClass,
  515. RLMObjectSchema *schema,
  516. const char *accessorClassName,
  517. id (*getterGetter)(RLMProperty *, const char *),
  518. id (*setterGetter)(RLMProperty *, const char *)) {
  519. REALM_ASSERT_DEBUG(RLMIsObjectOrSubclass(objectClass));
  520. // create and register proxy class which derives from object class
  521. Class accClass = objc_allocateClassPair(objectClass, accessorClassName, 0);
  522. if (!accClass) {
  523. // Class with that name already exists, so just return the pre-existing one
  524. // This should only happen for our standalone "accessors"
  525. return objc_lookUpClass(accessorClassName);
  526. }
  527. // override getters/setters for each propery
  528. for (RLMProperty *prop in schema.properties) {
  529. addMethod(accClass, prop, getterGetter, setterGetter);
  530. }
  531. for (RLMProperty *prop in schema.computedProperties) {
  532. addMethod(accClass, prop, getterGetter, setterGetter);
  533. }
  534. objc_registerClassPair(accClass);
  535. return accClass;
  536. }
  537. bool requiresUnmanagedAccessor(RLMObjectSchema *schema) {
  538. for (RLMProperty *prop in schema.properties) {
  539. if (prop.collection && !prop.swiftIvar) {
  540. return true;
  541. }
  542. }
  543. for (RLMProperty *prop in schema.computedProperties) {
  544. if (prop.collection && !prop.swiftIvar) {
  545. return true;
  546. }
  547. }
  548. return false;
  549. }
  550. } // anonymous namespace
  551. #pragma mark - Public Interface
  552. Class RLMManagedAccessorClassForObjectClass(Class objectClass, RLMObjectSchema *schema, const char *name) {
  553. return createAccessorClass(objectClass, schema, name, managedGetter, managedSetter);
  554. }
  555. Class RLMUnmanagedAccessorClassForObjectClass(Class objectClass, RLMObjectSchema *schema) {
  556. if (!requiresUnmanagedAccessor(schema)) {
  557. return objectClass;
  558. }
  559. return createAccessorClass(objectClass, schema,
  560. [@"RLM:Unmanaged " stringByAppendingString:schema.className].UTF8String,
  561. unmanagedGetter, unmanagedSetter);
  562. }
  563. // implement the class method className on accessors to return the className of the
  564. // base object
  565. void RLMReplaceClassNameMethod(Class accessorClass, NSString *className) {
  566. Class metaClass = object_getClass(accessorClass);
  567. IMP imp = imp_implementationWithBlock(^(Class) { return className; });
  568. class_addMethod(metaClass, @selector(className), imp, "@@:");
  569. }
  570. // implement the shared schema method
  571. void RLMReplaceSharedSchemaMethod(Class accessorClass, RLMObjectSchema *schema) {
  572. REALM_ASSERT(accessorClass != [RealmSwiftObject class]);
  573. Class metaClass = object_getClass(accessorClass);
  574. IMP imp = imp_implementationWithBlock(^(Class cls) {
  575. if (cls == accessorClass) {
  576. return schema;
  577. }
  578. // If we aren't being called directly on the class this was overridden
  579. // for, the class is either a subclass which we haven't initialized yet,
  580. // or it's a runtime-generated class which should use the parent's
  581. // schema. We check for the latter by checking if the immediate
  582. // descendent of the desired class is a class generated by us (there
  583. // may be further subclasses not generated by us for things like KVO).
  584. Class parent = class_getSuperclass(cls);
  585. while (parent != accessorClass) {
  586. cls = parent;
  587. parent = class_getSuperclass(cls);
  588. }
  589. static const char accessorClassPrefix[] = "RLM:";
  590. if (!strncmp(class_getName(cls), accessorClassPrefix, sizeof(accessorClassPrefix) - 1)) {
  591. return schema;
  592. }
  593. return [RLMSchema sharedSchemaForClass:cls];
  594. });
  595. class_addMethod(metaClass, @selector(sharedSchema), imp, "@@:");
  596. }
  597. void RLMDynamicValidatedSet(RLMObjectBase *obj, NSString *propName, id val) {
  598. RLMVerifyAttached(obj);
  599. RLMObjectSchema *schema = obj->_objectSchema;
  600. RLMProperty *prop = schema[propName];
  601. if (!prop) {
  602. @throw RLMException(@"Invalid property name '%@' for class '%@'.",
  603. propName, obj->_objectSchema.className);
  604. }
  605. if (prop.isPrimary) {
  606. @throw RLMException(@"Primary key can't be changed to '%@' after an object is inserted.", val);
  607. }
  608. // Because embedded objects cannot be created directly, we accept anything
  609. // that can be converted to an embedded object for dynamic link set operations.
  610. bool is_embedded = prop.type == RLMPropertyTypeObject && obj->_info->linkTargetType(prop.index).rlmObjectSchema.isEmbedded;
  611. RLMValidateValueForProperty(val, schema, prop, !is_embedded);
  612. RLMDynamicSet(obj, prop, RLMCoerceToNil(val));
  613. }
  614. // Precondition: the property is not a primary key
  615. void RLMDynamicSet(__unsafe_unretained RLMObjectBase *const obj,
  616. __unsafe_unretained RLMProperty *const prop,
  617. __unsafe_unretained id const val) {
  618. REALM_ASSERT_DEBUG(!prop.isPrimary);
  619. realm::Object o(obj->_info->realm->_realm, *obj->_info->objectSchema, obj->_row);
  620. RLMAccessorContext c(obj);
  621. RLMTranslateError([&] {
  622. o.set_property_value(c, getProperty(obj, prop).name, val ?: NSNull.null);
  623. });
  624. }
  625. id RLMDynamicGet(__unsafe_unretained RLMObjectBase *const obj, __unsafe_unretained RLMProperty *const prop) {
  626. if (auto accessor = prop.swiftAccessor; accessor && [obj isKindOfClass:obj->_objectSchema.objectClass]) {
  627. return RLMCoerceToNil([accessor get:prop on:obj]);
  628. }
  629. if (!obj->_realm) {
  630. return [obj valueForKey:prop.name];
  631. }
  632. realm::Object o(obj->_realm->_realm, *obj->_info->objectSchema, obj->_row);
  633. RLMAccessorContext c(obj);
  634. c.currentProperty = prop;
  635. return RLMTranslateError([&] {
  636. return RLMCoerceToNil(o.get_property_value<id>(c, getProperty(obj, prop)));
  637. });
  638. }
  639. id RLMDynamicGetByName(__unsafe_unretained RLMObjectBase *const obj,
  640. __unsafe_unretained NSString *const propName) {
  641. RLMProperty *prop = obj->_objectSchema[propName];
  642. if (!prop) {
  643. @throw RLMException(@"Invalid property name '%@' for class '%@'.",
  644. propName, obj->_objectSchema.className);
  645. }
  646. return RLMDynamicGet(obj, prop);
  647. }
  648. #pragma mark - Swift property getters and setter
  649. #define REALM_SWIFT_PROPERTY_ACCESSOR(objc, swift, rlmtype) \
  650. objc RLMGetSwiftProperty##swift(__unsafe_unretained RLMObjectBase *const obj, uint16_t key) { \
  651. return get<objc>(obj, key); \
  652. } \
  653. objc RLMGetSwiftProperty##swift##Optional(__unsafe_unretained RLMObjectBase *const obj, uint16_t key, bool *gotValue) { \
  654. return getOptional<objc>(obj, key, gotValue); \
  655. } \
  656. void RLMSetSwiftProperty##swift(__unsafe_unretained RLMObjectBase *const obj, uint16_t key, objc value) { \
  657. RLMVerifyAttached(obj); \
  658. kvoSetValue(obj, key, value); \
  659. }
  660. REALM_FOR_EACH_SWIFT_PRIMITIVE_TYPE(REALM_SWIFT_PROPERTY_ACCESSOR)
  661. #undef REALM_SWIFT_PROPERTY_ACCESSOR
  662. #define REALM_SWIFT_PROPERTY_ACCESSOR(objc, swift, rlmtype) \
  663. void RLMSetSwiftProperty##swift(__unsafe_unretained RLMObjectBase *const obj, uint16_t key, objc *value) { \
  664. RLMVerifyAttached(obj); \
  665. kvoSetValue(obj, key, value); \
  666. }
  667. REALM_FOR_EACH_SWIFT_OBJECT_TYPE(REALM_SWIFT_PROPERTY_ACCESSOR)
  668. #undef REALM_SWIFT_PROPERTY_ACCESSOR
  669. NSString *RLMGetSwiftPropertyString(__unsafe_unretained RLMObjectBase *const obj, uint16_t key) {
  670. return getBoxed<realm::StringData>(obj, key);
  671. }
  672. NSData *RLMGetSwiftPropertyData(__unsafe_unretained RLMObjectBase *const obj, uint16_t key) {
  673. return getBoxed<realm::BinaryData>(obj, key);
  674. }
  675. NSDate *RLMGetSwiftPropertyDate(__unsafe_unretained RLMObjectBase *const obj, uint16_t key) {
  676. return getBoxed<realm::Timestamp>(obj, key);
  677. }
  678. NSUUID *RLMGetSwiftPropertyUUID(__unsafe_unretained RLMObjectBase *const obj, uint16_t key) {
  679. return getBoxed<std::optional<realm::UUID>>(obj, key);
  680. }
  681. RLMObjectId *RLMGetSwiftPropertyObjectId(__unsafe_unretained RLMObjectBase *const obj, uint16_t key) {
  682. return getBoxed<std::optional<realm::ObjectId>>(obj, key);
  683. }
  684. RLMDecimal128 *RLMGetSwiftPropertyDecimal128(__unsafe_unretained RLMObjectBase *const obj, uint16_t key) {
  685. return getBoxed<realm::Decimal128>(obj, key);
  686. }
  687. RLMArray *RLMGetSwiftPropertyArray(__unsafe_unretained RLMObjectBase *const obj, uint16_t key) {
  688. return getCollection(obj, key);
  689. }
  690. RLMSet *RLMGetSwiftPropertySet(__unsafe_unretained RLMObjectBase *const obj, uint16_t key) {
  691. return getCollection(obj, key);
  692. }
  693. RLMDictionary *RLMGetSwiftPropertyMap(__unsafe_unretained RLMObjectBase *const obj, uint16_t key) {
  694. return getCollection(obj, key);
  695. }
  696. void RLMSetSwiftPropertyNil(__unsafe_unretained RLMObjectBase *const obj, uint16_t key) {
  697. RLMVerifyInWriteTransaction(obj);
  698. if (getProperty(obj, key).type == realm::PropertyType::Object) {
  699. kvoSetValue(obj, key, (RLMObjectBase *)nil);
  700. }
  701. else {
  702. // The type used here is arbitrary; it simply needs to be any non-object type
  703. kvoSetValue(obj, key, (NSNumber<RLMInt> *)nil);
  704. }
  705. }
  706. void RLMSetSwiftPropertyObject(__unsafe_unretained RLMObjectBase *const obj, uint16_t key,
  707. __unsafe_unretained RLMObjectBase *const target) {
  708. kvoSetValue(obj, key, target);
  709. }
  710. RLMObjectBase *RLMGetSwiftPropertyObject(__unsafe_unretained RLMObjectBase *const obj, uint16_t key) {
  711. return getBoxed<realm::Obj>(obj, key);
  712. }
  713. void RLMSetSwiftPropertyAny(__unsafe_unretained RLMObjectBase *const obj, uint16_t key,
  714. __unsafe_unretained id<RLMValue> const value) {
  715. kvoSetValue(obj, key, value);
  716. }
  717. id<RLMValue> RLMGetSwiftPropertyAny(__unsafe_unretained RLMObjectBase *const obj, uint16_t key) {
  718. return getBoxed<realm::Mixed>(obj, key);
  719. }
  720. #pragma mark - RLMAccessorContext
  721. RLMAccessorContext::~RLMAccessorContext() = default;
  722. RLMAccessorContext::RLMAccessorContext(RLMAccessorContext& parent, realm::Obj const& obj,
  723. realm::Property const& property)
  724. : _realm(parent._realm)
  725. , _info(property.type == realm::PropertyType::Object ? parent._info.linkTargetType(property) : parent._info)
  726. , _parentObject(obj)
  727. , _parentObjectInfo(&parent._info)
  728. , _colKey(property.column_key)
  729. {
  730. }
  731. RLMAccessorContext::RLMAccessorContext(RLMClassInfo& info)
  732. : _realm(info.realm), _info(info)
  733. {
  734. }
  735. RLMAccessorContext::RLMAccessorContext(__unsafe_unretained RLMObjectBase *const parent,
  736. const realm::Property *prop)
  737. : _realm(parent->_realm)
  738. , _info(prop && prop->type == realm::PropertyType::Object ? parent->_info->linkTargetType(*prop)
  739. : *parent->_info)
  740. , _parentObject(parent->_row)
  741. , _parentObjectInfo(parent->_info)
  742. , _colKey(prop ? prop->column_key : ColKey{})
  743. {
  744. }
  745. RLMAccessorContext::RLMAccessorContext(__unsafe_unretained RLMObjectBase *const parent,
  746. realm::ColKey col)
  747. : _realm(parent->_realm)
  748. , _info(_realm->_info[parent->_info->propertyForTableColumn(col).objectClassName])
  749. , _parentObject(parent->_row)
  750. , _parentObjectInfo(parent->_info)
  751. , _colKey(col)
  752. {
  753. }
  754. id RLMAccessorContext::defaultValue(__unsafe_unretained NSString *const key) {
  755. if (!_defaultValues) {
  756. _defaultValues = RLMDefaultValuesForObjectSchema(_info.rlmObjectSchema);
  757. }
  758. return _defaultValues[key];
  759. }
  760. id RLMAccessorContext::propertyValue(id obj, size_t propIndex,
  761. __unsafe_unretained RLMProperty *const prop) {
  762. obj = RLMBridgeSwiftValue(obj) ?: obj;
  763. // Property value from an NSArray
  764. if ([obj respondsToSelector:@selector(objectAtIndex:)]) {
  765. return propIndex < [obj count] ? [obj objectAtIndex:propIndex] : nil;
  766. }
  767. // Property value from an NSDictionary
  768. if ([obj respondsToSelector:@selector(objectForKey:)]) {
  769. return [obj objectForKey:prop.name];
  770. }
  771. // Property value from an instance of this object type
  772. if ([obj isKindOfClass:_info.rlmObjectSchema.objectClass] && prop.swiftAccessor) {
  773. return [prop.swiftAccessor get:prop on:obj];
  774. }
  775. // Property value from some object that's KVC-compatible
  776. id value = RLMValidatedValueForProperty(obj, [obj respondsToSelector:prop.getterSel] ? prop.getterName : prop.name,
  777. _info.rlmObjectSchema.className);
  778. return value ?: NSNull.null;
  779. }
  780. realm::Obj RLMAccessorContext::create_embedded_object() {
  781. if (!_parentObject) {
  782. @throw RLMException(@"Embedded objects cannot be created directly");
  783. }
  784. return _parentObject.create_and_set_linked_object(_colKey);
  785. }
  786. id RLMAccessorContext::box(realm::Mixed v) {
  787. return RLMMixedToObjc(v, _realm, &_info);
  788. }
  789. id RLMAccessorContext::box(realm::List&& l) {
  790. REALM_ASSERT(_parentObjectInfo);
  791. REALM_ASSERT(currentProperty);
  792. return [[RLMManagedArray alloc] initWithBackingCollection:std::move(l)
  793. parentInfo:_parentObjectInfo
  794. property:currentProperty];
  795. }
  796. id RLMAccessorContext::box(realm::object_store::Set&& s) {
  797. REALM_ASSERT(_parentObjectInfo);
  798. REALM_ASSERT(currentProperty);
  799. return [[RLMManagedSet alloc] initWithBackingCollection:std::move(s)
  800. parentInfo:_parentObjectInfo
  801. property:currentProperty];
  802. }
  803. id RLMAccessorContext::box(realm::object_store::Dictionary&& d) {
  804. REALM_ASSERT(_parentObjectInfo);
  805. REALM_ASSERT(currentProperty);
  806. return [[RLMManagedDictionary alloc] initWithBackingCollection:std::move(d)
  807. parentInfo:_parentObjectInfo
  808. property:currentProperty];
  809. }
  810. id RLMAccessorContext::box(realm::Object&& o) {
  811. REALM_ASSERT(currentProperty);
  812. return RLMCreateObjectAccessor(_info.linkTargetType(currentProperty.index), o.obj());
  813. }
  814. id RLMAccessorContext::box(realm::Obj&& r) {
  815. if (!currentProperty) {
  816. // If currentProperty is set, then we're reading from a Collection and
  817. // that reported an audit read for us. If not, we need to report the
  818. // audit read. This happens automatically when creating a
  819. // `realm::Object`, but our object accessors don't wrap that type.
  820. realm::Object(_realm->_realm, *_info.objectSchema, r, _parentObject, _colKey);
  821. }
  822. return RLMCreateObjectAccessor(_info, std::move(r));
  823. }
  824. id RLMAccessorContext::box(realm::Results&& r) {
  825. REALM_ASSERT(currentProperty);
  826. return [RLMResults resultsWithObjectInfo:_realm->_info[currentProperty.objectClassName]
  827. results:std::move(r)];
  828. }
  829. using realm::ObjKey;
  830. using realm::CreatePolicy;
  831. template<typename T>
  832. static T *bridged(__unsafe_unretained id const value) {
  833. return [value isKindOfClass:[T class]] ? value : RLMBridgeSwiftValue(value);
  834. }
  835. template<>
  836. realm::Timestamp RLMStatelessAccessorContext::unbox(__unsafe_unretained id const value) {
  837. id v = RLMCoerceToNil(value);
  838. return RLMTimestampForNSDate(bridged<NSDate>(v));
  839. }
  840. template<>
  841. bool RLMStatelessAccessorContext::unbox(__unsafe_unretained id const v) {
  842. return [bridged<NSNumber>(v) boolValue];
  843. }
  844. template<>
  845. double RLMStatelessAccessorContext::unbox(__unsafe_unretained id const v) {
  846. return [bridged<NSNumber>(v) doubleValue];
  847. }
  848. template<>
  849. float RLMStatelessAccessorContext::unbox(__unsafe_unretained id const v) {
  850. return [bridged<NSNumber>(v) floatValue];
  851. }
  852. template<>
  853. long long RLMStatelessAccessorContext::unbox(__unsafe_unretained id const v) {
  854. return [bridged<NSNumber>(v) longLongValue];
  855. }
  856. template<>
  857. realm::BinaryData RLMStatelessAccessorContext::unbox(id v) {
  858. v = RLMCoerceToNil(v);
  859. return RLMBinaryDataForNSData(bridged<NSData>(v));
  860. }
  861. template<>
  862. realm::StringData RLMStatelessAccessorContext::unbox(id v) {
  863. v = RLMCoerceToNil(v);
  864. return RLMStringDataWithNSString(bridged<NSString>(v));
  865. }
  866. template<>
  867. realm::Decimal128 RLMStatelessAccessorContext::unbox(id v) {
  868. return RLMObjcToDecimal128(v);
  869. }
  870. template<>
  871. realm::ObjectId RLMStatelessAccessorContext::unbox(id v) {
  872. return bridged<RLMObjectId>(v).value;
  873. }
  874. template<>
  875. realm::UUID RLMStatelessAccessorContext::unbox(id v) {
  876. return RLMObjcToUUID(bridged<NSUUID>(v));
  877. }
  878. template<>
  879. realm::Mixed RLMAccessorContext::unbox(__unsafe_unretained id v, CreatePolicy p, ObjKey) {
  880. return RLMObjcToMixed(v, _realm, p);
  881. }
  882. template<typename T>
  883. static auto toOptional(__unsafe_unretained id const value) {
  884. id v = RLMCoerceToNil(value);
  885. return v ? realm::util::make_optional(RLMStatelessAccessorContext::unbox<T>(v))
  886. : realm::util::none;
  887. }
  888. template<>
  889. std::optional<bool> RLMStatelessAccessorContext::unbox(__unsafe_unretained id const v) {
  890. return toOptional<bool>(v);
  891. }
  892. template<>
  893. std::optional<double> RLMStatelessAccessorContext::unbox(__unsafe_unretained id const v) {
  894. return toOptional<double>(v);
  895. }
  896. template<>
  897. std::optional<float> RLMStatelessAccessorContext::unbox(__unsafe_unretained id const v) {
  898. return toOptional<float>(v);
  899. }
  900. template<>
  901. std::optional<int64_t> RLMStatelessAccessorContext::unbox(__unsafe_unretained id const v) {
  902. return toOptional<int64_t>(v);
  903. }
  904. template<>
  905. std::optional<realm::ObjectId> RLMStatelessAccessorContext::unbox(__unsafe_unretained id const v) {
  906. return toOptional<realm::ObjectId>(v);
  907. }
  908. template<>
  909. std::optional<realm::UUID> RLMStatelessAccessorContext::unbox(__unsafe_unretained id const v) {
  910. return toOptional<realm::UUID>(v);
  911. }
  912. std::pair<realm::Obj, bool>
  913. RLMAccessorContext::createObject(id value, realm::CreatePolicy policy,
  914. bool forceCreate, ObjKey existingKey) {
  915. if (!value || value == NSNull.null) {
  916. @throw RLMException(@"Must provide a non-nil value.");
  917. }
  918. if ([value isKindOfClass:[NSArray class]] && [value count] > _info.objectSchema->persisted_properties.size()) {
  919. @throw RLMException(@"Invalid array input: more values (%llu) than properties (%llu).",
  920. (unsigned long long)[value count],
  921. (unsigned long long)_info.objectSchema->persisted_properties.size());
  922. }
  923. RLMObjectBase *objBase = RLMDynamicCast<RLMObjectBase>(value);
  924. realm::Obj obj, *outObj = nullptr;
  925. bool requiresSwiftUIObservers = false;
  926. if (objBase) {
  927. if (objBase.isInvalidated) {
  928. if (policy.create && !policy.copy) {
  929. @throw RLMException(@"Adding a deleted or invalidated object to a Realm is not permitted");
  930. }
  931. else {
  932. @throw RLMException(@"Object has been deleted or invalidated.");
  933. }
  934. }
  935. if (policy.copy) {
  936. if (policy.update || !forceCreate) {
  937. // create(update: true) is a no-op when given an object already in
  938. // the Realm which is of the correct type
  939. if (objBase->_realm == _realm && objBase->_row.get_table() == _info.table() && !_info.table()->is_embedded()) {
  940. return {objBase->_row, true};
  941. }
  942. }
  943. // Otherwise we copy the object
  944. objBase = nil;
  945. }
  946. else {
  947. outObj = &objBase->_row;
  948. // add() on an object already managed by this Realm is a no-op
  949. if (objBase->_realm == _realm) {
  950. return {objBase->_row, true};
  951. }
  952. if (!policy.create) {
  953. return {realm::Obj(), false};
  954. }
  955. if (objBase->_realm) {
  956. @throw RLMException(@"Object is already managed by another Realm. Use create instead to copy it into this Realm.");
  957. }
  958. if (objBase->_observationInfo && objBase->_observationInfo->hasObservers()) {
  959. requiresSwiftUIObservers = [RLMSwiftUIKVO removeObserversFromObject:objBase];
  960. if (!requiresSwiftUIObservers) {
  961. @throw RLMException(@"Cannot add an object with observers to a Realm");
  962. }
  963. }
  964. REALM_ASSERT([objBase->_objectSchema.className isEqualToString:_info.rlmObjectSchema.className]);
  965. REALM_ASSERT([objBase isKindOfClass:_info.rlmObjectSchema.unmanagedClass]);
  966. objBase->_info = &_info;
  967. objBase->_realm = _realm;
  968. objBase->_objectSchema = _info.rlmObjectSchema;
  969. }
  970. }
  971. if (!policy.create) {
  972. return {realm::Obj(), false};
  973. }
  974. if (!outObj) {
  975. outObj = &obj;
  976. }
  977. try {
  978. realm::Object::create(*this, _realm->_realm, *_info.objectSchema,
  979. (id)value, policy, existingKey, outObj).obj();
  980. }
  981. catch (std::exception const& e) {
  982. @throw RLMException(e);
  983. }
  984. if (objBase) {
  985. for (RLMProperty *prop in _info.rlmObjectSchema.properties) {
  986. // set the ivars for object and array properties to nil as otherwise the
  987. // accessors retain objects that are no longer accessible via the properties
  988. // this is mainly an issue when the object graph being added has cycles,
  989. // as it's not obvious that the user has to set the *ivars* to nil to
  990. // avoid leaking memory
  991. if (prop.type == RLMPropertyTypeObject && !prop.swiftIvar) {
  992. ((void(*)(id, SEL, id))objc_msgSend)(objBase, prop.setterSel, nil);
  993. }
  994. }
  995. object_setClass(objBase, _info.rlmObjectSchema.accessorClass);
  996. RLMInitializeSwiftAccessor(objBase, true);
  997. }
  998. if (requiresSwiftUIObservers) {
  999. [RLMSwiftUIKVO addObserversToObject:objBase];
  1000. }
  1001. return {*outObj, false};
  1002. }
  1003. template<>
  1004. realm::Obj RLMAccessorContext::unbox(__unsafe_unretained id const v, CreatePolicy policy, ObjKey key) {
  1005. return createObject(v, policy, false, key).first;
  1006. }
  1007. void RLMAccessorContext::will_change(realm::Obj const& row, realm::Property const& prop) {
  1008. auto obsInfo = RLMGetObservationInfo(nullptr, row.get_key(), _info);
  1009. if (!_observationHelper) {
  1010. if (obsInfo || prop.type == realm::PropertyType::Object) {
  1011. _observationHelper = std::make_unique<RLMObservationTracker>(_info.realm);
  1012. }
  1013. }
  1014. if (_observationHelper) {
  1015. _observationHelper->willChange(obsInfo, _info.propertyForTableColumn(prop.column_key).name);
  1016. if (prop.type == realm::PropertyType::Object) {
  1017. _observationHelper->trackDeletions();
  1018. }
  1019. }
  1020. }
  1021. void RLMAccessorContext::did_change() {
  1022. if (_observationHelper) {
  1023. _observationHelper->didChange();
  1024. }
  1025. }
  1026. RLMOptionalId RLMAccessorContext::value_for_property(__unsafe_unretained id const obj,
  1027. realm::Property const&, size_t propIndex) {
  1028. auto prop = _info.rlmObjectSchema.properties[propIndex];
  1029. id value = propertyValue(obj, propIndex, prop);
  1030. if (value) {
  1031. RLMValidateValueForProperty(value, _info.rlmObjectSchema, prop);
  1032. }
  1033. return RLMOptionalId{value};
  1034. }
  1035. RLMOptionalId RLMAccessorContext::default_value_for_property(realm::ObjectSchema const&,
  1036. realm::Property const& prop)
  1037. {
  1038. return RLMOptionalId{defaultValue(@(prop.name.c_str()))};
  1039. }
  1040. bool RLMStatelessAccessorContext::is_same_list(realm::List const& list,
  1041. __unsafe_unretained id const v) noexcept {
  1042. return [v respondsToSelector:@selector(isBackedByList:)] && [v isBackedByList:list];
  1043. }
  1044. bool RLMStatelessAccessorContext::is_same_set(realm::object_store::Set const& set,
  1045. __unsafe_unretained id const v) noexcept {
  1046. return [v respondsToSelector:@selector(isBackedBySet:)] && [v isBackedBySet:set];
  1047. }
  1048. bool RLMStatelessAccessorContext::is_same_dictionary(realm::object_store::Dictionary const& dict,
  1049. __unsafe_unretained id const v) noexcept {
  1050. return [v respondsToSelector:@selector(isBackedByDictionary:)] && [v isBackedByDictionary:dict];
  1051. }
  1052. #pragma clang diagnostic push
  1053. #pragma clang diagnostic ignored "-Wincomplete-implementation"
  1054. @implementation RLMManagedPropertyAccessor
  1055. // Most types don't need to distinguish between promote and init so provide a default
  1056. + (void)promote:(RLMProperty *)property on:(RLMObjectBase *)parent {
  1057. [self initialize:property on:parent];
  1058. }
  1059. @end
  1060. #pragma clang diagnostic pop