RLMRealmConfiguration.mm 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. ////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright 2015 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 "RLMRealmConfiguration_Private.h"
  19. #import "RLMObjectSchema_Private.hpp"
  20. #import "RLMRealm_Private.h"
  21. #import "RLMSchema_Private.hpp"
  22. #import "RLMUtil.hpp"
  23. #import "schema.hpp"
  24. #import "shared_realm.hpp"
  25. #import "sync/sync_config.hpp"
  26. static NSString *const c_RLMRealmConfigurationProperties[] = {
  27. @"fileURL",
  28. @"inMemoryIdentifier",
  29. @"encryptionKey",
  30. @"readOnly",
  31. @"schemaVersion",
  32. @"migrationBlock",
  33. @"deleteRealmIfMigrationNeeded",
  34. @"shouldCompactOnLaunch",
  35. @"dynamic",
  36. @"customSchema",
  37. };
  38. static NSString *const c_defaultRealmFileName = @"default.realm";
  39. RLMRealmConfiguration *s_defaultConfiguration;
  40. NSString *RLMRealmPathForFileAndBundleIdentifier(NSString *fileName, NSString *bundleIdentifier) {
  41. return [RLMDefaultDirectoryForBundleIdentifier(bundleIdentifier)
  42. stringByAppendingPathComponent:fileName];
  43. }
  44. NSString *RLMRealmPathForFile(NSString *fileName) {
  45. static NSString *directory = RLMDefaultDirectoryForBundleIdentifier(nil);
  46. return [directory stringByAppendingPathComponent:fileName];
  47. }
  48. @implementation RLMRealmConfiguration {
  49. realm::Realm::Config _config;
  50. }
  51. - (realm::Realm::Config&)config {
  52. return _config;
  53. }
  54. + (instancetype)defaultConfiguration {
  55. return [[self rawDefaultConfiguration] copy];
  56. }
  57. + (void)setDefaultConfiguration:(RLMRealmConfiguration *)configuration {
  58. if (!configuration) {
  59. @throw RLMException(@"Cannot set the default configuration to nil.");
  60. }
  61. @synchronized(c_defaultRealmFileName) {
  62. s_defaultConfiguration = [configuration copy];
  63. }
  64. }
  65. + (RLMRealmConfiguration *)rawDefaultConfiguration {
  66. RLMRealmConfiguration *configuration;
  67. @synchronized(c_defaultRealmFileName) {
  68. if (!s_defaultConfiguration) {
  69. s_defaultConfiguration = [[RLMRealmConfiguration alloc] init];
  70. }
  71. configuration = s_defaultConfiguration;
  72. }
  73. return configuration;
  74. }
  75. + (void)resetRealmConfigurationState {
  76. @synchronized(c_defaultRealmFileName) {
  77. s_defaultConfiguration = nil;
  78. }
  79. }
  80. - (instancetype)init {
  81. self = [super init];
  82. if (self) {
  83. static NSURL *defaultRealmURL = [NSURL fileURLWithPath:RLMRealmPathForFile(c_defaultRealmFileName)];
  84. self.fileURL = defaultRealmURL;
  85. self.schemaVersion = 0;
  86. self.cache = YES;
  87. // We have our own caching of RLMRealm instances, so the ObjectStore
  88. // cache is at best pointless, and may result in broken behavior when
  89. // a realm::Realm instance outlives the RLMRealm (due to collection
  90. // notifiers being in the middle of running when the RLMRealm is
  91. // dealloced) and then reused for a new RLMRealm
  92. _config.cache = false;
  93. }
  94. return self;
  95. }
  96. - (instancetype)copyWithZone:(NSZone *)zone {
  97. RLMRealmConfiguration *configuration = [[[self class] allocWithZone:zone] init];
  98. configuration->_config = _config;
  99. configuration->_cache = _cache;
  100. configuration->_dynamic = _dynamic;
  101. configuration->_migrationBlock = _migrationBlock;
  102. configuration->_shouldCompactOnLaunch = _shouldCompactOnLaunch;
  103. configuration->_customSchema = _customSchema;
  104. return configuration;
  105. }
  106. - (NSString *)description {
  107. NSMutableString *string = [NSMutableString stringWithFormat:@"%@ {\n", self.class];
  108. for (NSString *key : c_RLMRealmConfigurationProperties) {
  109. NSString *description = [[self valueForKey:key] description];
  110. description = [description stringByReplacingOccurrencesOfString:@"\n" withString:@"\n\t"];
  111. [string appendFormat:@"\t%@ = %@;\n", key, description];
  112. }
  113. return [string stringByAppendingString:@"}"];
  114. }
  115. static void RLMNSStringToStdString(std::string &out, NSString *in) {
  116. out.resize([in maximumLengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
  117. if (out.empty()) {
  118. return;
  119. }
  120. NSUInteger size = out.size();
  121. [in getBytes:&out[0]
  122. maxLength:size
  123. usedLength:&size
  124. encoding:NSUTF8StringEncoding
  125. options:0 range:{0, in.length} remainingRange:nullptr];
  126. out.resize(size);
  127. }
  128. - (NSURL *)fileURL {
  129. if (_config.in_memory || _config.sync_config) {
  130. return nil;
  131. }
  132. return [NSURL fileURLWithPath:@(_config.path.c_str())];
  133. }
  134. - (void)setFileURL:(NSURL *)fileURL {
  135. NSString *path = fileURL.path;
  136. if (path.length == 0) {
  137. @throw RLMException(@"Realm path must not be empty");
  138. }
  139. _config.sync_config = nullptr;
  140. RLMNSStringToStdString(_config.path, path);
  141. _config.in_memory = false;
  142. }
  143. - (NSString *)inMemoryIdentifier {
  144. if (!_config.in_memory) {
  145. return nil;
  146. }
  147. return [@(_config.path.c_str()) lastPathComponent];
  148. }
  149. - (void)setInMemoryIdentifier:(NSString *)inMemoryIdentifier {
  150. if (inMemoryIdentifier.length == 0) {
  151. @throw RLMException(@"In-memory identifier must not be empty");
  152. }
  153. _config.sync_config = nullptr;
  154. RLMNSStringToStdString(_config.path, [NSTemporaryDirectory() stringByAppendingPathComponent:inMemoryIdentifier]);
  155. _config.in_memory = true;
  156. }
  157. - (NSData *)encryptionKey {
  158. return _config.encryption_key.empty() ? nil : [NSData dataWithBytes:_config.encryption_key.data() length:_config.encryption_key.size()];
  159. }
  160. - (void)setEncryptionKey:(NSData * __nullable)encryptionKey {
  161. if (NSData *key = RLMRealmValidatedEncryptionKey(encryptionKey)) {
  162. auto bytes = static_cast<const char *>(key.bytes);
  163. _config.encryption_key.assign(bytes, bytes + key.length);
  164. if (_config.sync_config) {
  165. auto& sync_encryption_key = self.config.sync_config->realm_encryption_key;
  166. sync_encryption_key = std::array<char, 64>();
  167. std::copy_n(_config.encryption_key.begin(), 64, sync_encryption_key->begin());
  168. }
  169. }
  170. else {
  171. _config.encryption_key.clear();
  172. if (_config.sync_config)
  173. _config.sync_config->realm_encryption_key = realm::util::none;
  174. }
  175. }
  176. - (BOOL)readOnly {
  177. return _config.immutable();
  178. }
  179. - (void)setReadOnly:(BOOL)readOnly {
  180. if (readOnly) {
  181. if (self.deleteRealmIfMigrationNeeded) {
  182. @throw RLMException(@"Cannot set `readOnly` when `deleteRealmIfMigrationNeeded` is set.");
  183. } else if (self.shouldCompactOnLaunch) {
  184. @throw RLMException(@"Cannot set `readOnly` when `shouldCompactOnLaunch` is set.");
  185. }
  186. _config.schema_mode = realm::SchemaMode::Immutable;
  187. }
  188. else if (self.readOnly) {
  189. _config.schema_mode = realm::SchemaMode::Automatic;
  190. }
  191. }
  192. - (uint64_t)schemaVersion {
  193. return _config.schema_version;
  194. }
  195. - (void)setSchemaVersion:(uint64_t)schemaVersion {
  196. if (schemaVersion == RLMNotVersioned) {
  197. @throw RLMException(@"Cannot set schema version to %llu (RLMNotVersioned)", RLMNotVersioned);
  198. }
  199. _config.schema_version = schemaVersion;
  200. }
  201. - (BOOL)deleteRealmIfMigrationNeeded {
  202. return _config.schema_mode == realm::SchemaMode::ResetFile;
  203. }
  204. - (void)setDeleteRealmIfMigrationNeeded:(BOOL)deleteRealmIfMigrationNeeded {
  205. if (deleteRealmIfMigrationNeeded) {
  206. if (self.readOnly) {
  207. @throw RLMException(@"Cannot set `deleteRealmIfMigrationNeeded` when `readOnly` is set.");
  208. }
  209. _config.schema_mode = realm::SchemaMode::ResetFile;
  210. }
  211. else if (self.deleteRealmIfMigrationNeeded) {
  212. _config.schema_mode = realm::SchemaMode::Automatic;
  213. }
  214. }
  215. - (NSArray *)objectClasses {
  216. return [_customSchema.objectSchema valueForKeyPath:@"objectClass"];
  217. }
  218. - (void)setObjectClasses:(NSArray *)objectClasses {
  219. self.customSchema = [RLMSchema schemaWithObjectClasses:objectClasses];
  220. }
  221. - (void)setDynamic:(bool)dynamic {
  222. _dynamic = dynamic;
  223. self.cache = !dynamic;
  224. }
  225. - (bool)disableFormatUpgrade {
  226. return _config.disable_format_upgrade;
  227. }
  228. - (void)setDisableFormatUpgrade:(bool)disableFormatUpgrade {
  229. _config.disable_format_upgrade = disableFormatUpgrade;
  230. }
  231. - (realm::SchemaMode)schemaMode {
  232. return _config.schema_mode;
  233. }
  234. - (void)setSchemaMode:(realm::SchemaMode)mode {
  235. _config.schema_mode = mode;
  236. }
  237. - (NSString *)pathOnDisk {
  238. return @(_config.path.c_str());
  239. }
  240. - (void)setShouldCompactOnLaunch:(RLMShouldCompactOnLaunchBlock)shouldCompactOnLaunch {
  241. if (shouldCompactOnLaunch) {
  242. if (self.readOnly) {
  243. @throw RLMException(@"Cannot set `shouldCompactOnLaunch` when `readOnly` is set.");
  244. }
  245. _config.should_compact_on_launch_function = [=](size_t totalBytes, size_t usedBytes) {
  246. return shouldCompactOnLaunch(totalBytes, usedBytes);
  247. };
  248. }
  249. else {
  250. _config.should_compact_on_launch_function = nullptr;
  251. }
  252. _shouldCompactOnLaunch = shouldCompactOnLaunch;
  253. }
  254. - (void)setCustomSchemaWithoutCopying:(RLMSchema *)schema {
  255. _customSchema = schema;
  256. }
  257. @end