RLMRealmConfiguration.mm 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  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 <realm/object-store/schema.hpp>
  24. #import <realm/object-store/shared_realm.hpp>
  25. #if REALM_ENABLE_SYNC
  26. #import <realm/sync/config.hpp>
  27. #else
  28. @class RLMSyncConfiguration;
  29. #endif
  30. static NSString *const c_RLMRealmConfigurationProperties[] = {
  31. @"fileURL",
  32. @"inMemoryIdentifier",
  33. @"encryptionKey",
  34. @"readOnly",
  35. @"schemaVersion",
  36. @"migrationBlock",
  37. @"deleteRealmIfMigrationNeeded",
  38. @"shouldCompactOnLaunch",
  39. @"dynamic",
  40. @"customSchema",
  41. };
  42. static NSString *const c_defaultRealmFileName = @"default.realm";
  43. RLMRealmConfiguration *s_defaultConfiguration;
  44. NSString *RLMRealmPathForFileAndBundleIdentifier(NSString *fileName, NSString *bundleIdentifier) {
  45. return [RLMDefaultDirectoryForBundleIdentifier(bundleIdentifier)
  46. stringByAppendingPathComponent:fileName];
  47. }
  48. NSString *RLMRealmPathForFile(NSString *fileName) {
  49. static NSString *directory = RLMDefaultDirectoryForBundleIdentifier(nil);
  50. return [directory stringByAppendingPathComponent:fileName];
  51. }
  52. @implementation RLMRealmConfiguration {
  53. realm::Realm::Config _config;
  54. }
  55. - (realm::Realm::Config&)config {
  56. return _config;
  57. }
  58. + (instancetype)defaultConfiguration {
  59. return [[self rawDefaultConfiguration] copy];
  60. }
  61. + (void)setDefaultConfiguration:(RLMRealmConfiguration *)configuration {
  62. if (!configuration) {
  63. @throw RLMException(@"Cannot set the default configuration to nil.");
  64. }
  65. @synchronized(c_defaultRealmFileName) {
  66. s_defaultConfiguration = [configuration copy];
  67. }
  68. }
  69. + (RLMRealmConfiguration *)rawDefaultConfiguration {
  70. RLMRealmConfiguration *configuration;
  71. @synchronized(c_defaultRealmFileName) {
  72. if (!s_defaultConfiguration) {
  73. s_defaultConfiguration = [[RLMRealmConfiguration alloc] init];
  74. }
  75. configuration = s_defaultConfiguration;
  76. }
  77. return configuration;
  78. }
  79. + (void)resetRealmConfigurationState {
  80. @synchronized(c_defaultRealmFileName) {
  81. s_defaultConfiguration = nil;
  82. }
  83. }
  84. - (instancetype)init {
  85. self = [super init];
  86. if (self) {
  87. static NSURL *defaultRealmURL = [NSURL fileURLWithPath:RLMRealmPathForFile(c_defaultRealmFileName)];
  88. self.fileURL = defaultRealmURL;
  89. self.schemaVersion = 0;
  90. self.cache = YES;
  91. }
  92. return self;
  93. }
  94. - (instancetype)copyWithZone:(NSZone *)zone {
  95. RLMRealmConfiguration *configuration = [[[self class] allocWithZone:zone] init];
  96. configuration->_config = _config;
  97. configuration->_cache = _cache;
  98. configuration->_dynamic = _dynamic;
  99. configuration->_migrationBlock = _migrationBlock;
  100. configuration->_shouldCompactOnLaunch = _shouldCompactOnLaunch;
  101. configuration->_customSchema = _customSchema;
  102. return configuration;
  103. }
  104. - (NSString *)description {
  105. NSMutableString *string = [NSMutableString stringWithFormat:@"%@ {\n", self.class];
  106. for (NSString *key : c_RLMRealmConfigurationProperties) {
  107. NSString *description = [[self valueForKey:key] description];
  108. description = [description stringByReplacingOccurrencesOfString:@"\n" withString:@"\n\t"];
  109. [string appendFormat:@"\t%@ = %@;\n", key, description];
  110. }
  111. return [string stringByAppendingString:@"}"];
  112. }
  113. - (NSURL *)fileURL {
  114. if (_config.in_memory) {
  115. return nil;
  116. }
  117. return [NSURL fileURLWithPath:@(_config.path.c_str())];
  118. }
  119. - (void)setFileURL:(NSURL *)fileURL {
  120. NSString *path = fileURL.path;
  121. if (path.length == 0) {
  122. @throw RLMException(@"Realm path must not be empty");
  123. }
  124. RLMNSStringToStdString(_config.path, path);
  125. _config.in_memory = false;
  126. }
  127. - (NSString *)inMemoryIdentifier {
  128. if (!_config.in_memory) {
  129. return nil;
  130. }
  131. return [@(_config.path.c_str()) lastPathComponent];
  132. }
  133. - (void)setInMemoryIdentifier:(NSString *)inMemoryIdentifier {
  134. if (inMemoryIdentifier.length == 0) {
  135. @throw RLMException(@"In-memory identifier must not be empty");
  136. }
  137. _config.sync_config = nullptr;
  138. RLMNSStringToStdString(_config.path, [NSTemporaryDirectory() stringByAppendingPathComponent:inMemoryIdentifier]);
  139. _config.in_memory = true;
  140. }
  141. - (NSData *)encryptionKey {
  142. return _config.encryption_key.empty() ? nil : [NSData dataWithBytes:_config.encryption_key.data() length:_config.encryption_key.size()];
  143. }
  144. - (void)setEncryptionKey:(NSData * __nullable)encryptionKey {
  145. if (NSData *key = RLMRealmValidatedEncryptionKey(encryptionKey)) {
  146. auto bytes = static_cast<const char *>(key.bytes);
  147. _config.encryption_key.assign(bytes, bytes + key.length);
  148. #if REALM_ENABLE_SYNC
  149. if (_config.sync_config) {
  150. auto& sync_encryption_key = self.config.sync_config->realm_encryption_key;
  151. sync_encryption_key = std::array<char, 64>();
  152. std::copy_n(_config.encryption_key.begin(), 64, sync_encryption_key->begin());
  153. }
  154. #endif
  155. }
  156. else {
  157. _config.encryption_key.clear();
  158. #if REALM_ENABLE_SYNC
  159. if (_config.sync_config)
  160. _config.sync_config->realm_encryption_key = realm::util::none;
  161. #endif
  162. }
  163. }
  164. - (BOOL)readOnly {
  165. return _config.immutable() || _config.read_only_alternative();
  166. }
  167. static bool isSync(realm::Realm::Config const& config) {
  168. #if REALM_ENABLE_SYNC
  169. return !!config.sync_config;
  170. #endif
  171. return false;
  172. }
  173. - (void)updateSchemaMode {
  174. if (self.deleteRealmIfMigrationNeeded) {
  175. if (isSync(_config)) {
  176. @throw RLMException(@"Cannot set 'deleteRealmIfMigrationNeeded' when sync is enabled ('syncConfig' is set).");
  177. }
  178. }
  179. else if (self.readOnly) {
  180. _config.schema_mode = isSync(_config) ? realm::SchemaMode::ReadOnlyAlternative : realm::SchemaMode::Immutable;
  181. }
  182. else if (isSync(_config)) {
  183. if (_customSchema) {
  184. _config.schema_mode = realm::SchemaMode::AdditiveExplicit;
  185. }
  186. else {
  187. _config.schema_mode = realm::SchemaMode::AdditiveDiscovered;
  188. }
  189. }
  190. else {
  191. _config.schema_mode = realm::SchemaMode::Automatic;
  192. }
  193. }
  194. - (void)setReadOnly:(BOOL)readOnly {
  195. if (readOnly) {
  196. if (self.deleteRealmIfMigrationNeeded) {
  197. @throw RLMException(@"Cannot set `readOnly` when `deleteRealmIfMigrationNeeded` is set.");
  198. } else if (self.shouldCompactOnLaunch) {
  199. @throw RLMException(@"Cannot set `readOnly` when `shouldCompactOnLaunch` is set.");
  200. }
  201. _config.schema_mode = isSync(_config) ? realm::SchemaMode::ReadOnlyAlternative : realm::SchemaMode::Immutable;
  202. }
  203. else if (self.readOnly) {
  204. _config.schema_mode = realm::SchemaMode::Automatic;
  205. [self updateSchemaMode];
  206. }
  207. }
  208. - (uint64_t)schemaVersion {
  209. return _config.schema_version;
  210. }
  211. - (void)setSchemaVersion:(uint64_t)schemaVersion {
  212. if (schemaVersion == RLMNotVersioned) {
  213. @throw RLMException(@"Cannot set schema version to %llu (RLMNotVersioned)", RLMNotVersioned);
  214. }
  215. _config.schema_version = schemaVersion;
  216. }
  217. - (BOOL)deleteRealmIfMigrationNeeded {
  218. return _config.schema_mode == realm::SchemaMode::ResetFile;
  219. }
  220. - (void)setDeleteRealmIfMigrationNeeded:(BOOL)deleteRealmIfMigrationNeeded {
  221. if (deleteRealmIfMigrationNeeded) {
  222. if (self.readOnly) {
  223. @throw RLMException(@"Cannot set `deleteRealmIfMigrationNeeded` when `readOnly` is set.");
  224. }
  225. if (isSync(_config)) {
  226. @throw RLMException(@"Cannot set 'deleteRealmIfMigrationNeeded' when sync is enabled ('syncConfig' is set).");
  227. }
  228. _config.schema_mode = realm::SchemaMode::ResetFile;
  229. }
  230. else if (self.deleteRealmIfMigrationNeeded) {
  231. _config.schema_mode = realm::SchemaMode::Automatic;
  232. }
  233. }
  234. - (NSArray *)objectClasses {
  235. return [_customSchema.objectSchema valueForKeyPath:@"objectClass"];
  236. }
  237. - (void)setObjectClasses:(NSArray *)objectClasses {
  238. self.customSchema = objectClasses ? [RLMSchema schemaWithObjectClasses:objectClasses] : nil;
  239. [self updateSchemaMode];
  240. }
  241. - (NSUInteger)maximumNumberOfActiveVersions {
  242. if (_config.max_number_of_active_versions > std::numeric_limits<NSUInteger>::max()) {
  243. return std::numeric_limits<NSUInteger>::max();
  244. }
  245. return static_cast<NSUInteger>(_config.max_number_of_active_versions);
  246. }
  247. - (void)setMaximumNumberOfActiveVersions:(NSUInteger)maximumNumberOfActiveVersions {
  248. if (maximumNumberOfActiveVersions == 0) {
  249. _config.max_number_of_active_versions = std::numeric_limits<uint_fast64_t>::max();
  250. }
  251. else {
  252. _config.max_number_of_active_versions = maximumNumberOfActiveVersions;
  253. }
  254. }
  255. - (void)setDynamic:(bool)dynamic {
  256. _dynamic = dynamic;
  257. self.cache = !dynamic;
  258. }
  259. - (bool)disableFormatUpgrade {
  260. return _config.disable_format_upgrade;
  261. }
  262. - (void)setDisableFormatUpgrade:(bool)disableFormatUpgrade {
  263. _config.disable_format_upgrade = disableFormatUpgrade;
  264. }
  265. - (realm::SchemaMode)schemaMode {
  266. return _config.schema_mode;
  267. }
  268. - (void)setSchemaMode:(realm::SchemaMode)mode {
  269. _config.schema_mode = mode;
  270. }
  271. - (NSString *)pathOnDisk {
  272. return @(_config.path.c_str());
  273. }
  274. - (void)setShouldCompactOnLaunch:(RLMShouldCompactOnLaunchBlock)shouldCompactOnLaunch {
  275. if (shouldCompactOnLaunch) {
  276. if (_config.immutable()) {
  277. @throw RLMException(@"Cannot set `shouldCompactOnLaunch` when `readOnly` is set.");
  278. }
  279. _config.should_compact_on_launch_function = [=](size_t totalBytes, size_t usedBytes) {
  280. return shouldCompactOnLaunch(totalBytes, usedBytes);
  281. };
  282. }
  283. else {
  284. _config.should_compact_on_launch_function = nullptr;
  285. }
  286. _shouldCompactOnLaunch = shouldCompactOnLaunch;
  287. }
  288. - (void)setCustomSchemaWithoutCopying:(RLMSchema *)schema {
  289. _customSchema = schema;
  290. }
  291. #if !REALM_ENABLE_SYNC
  292. - (RLMSyncConfiguration *)syncConfiguration {
  293. return nil;
  294. }
  295. #endif
  296. @end