1 ////////////////////////////////////////////////////////////////////////////
3 // Copyright 2015 Realm Inc.
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
9 // http://www.apache.org/licenses/LICENSE-2.0
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.
17 ////////////////////////////////////////////////////////////////////////////
19 #import "RLMRealmConfiguration_Private.h"
21 #import "RLMObjectSchema_Private.hpp"
22 #import "RLMRealm_Private.h"
23 #import "RLMSchema_Private.hpp"
27 #import "shared_realm.hpp"
28 #import "sync/sync_config.hpp"
30 static NSString *const c_RLMRealmConfigurationProperties[] = {
32 @"inMemoryIdentifier",
37 @"deleteRealmIfMigrationNeeded",
38 @"shouldCompactOnLaunch",
43 static NSString *const c_defaultRealmFileName = @"default.realm";
44 RLMRealmConfiguration *s_defaultConfiguration;
46 NSString *RLMRealmPathForFileAndBundleIdentifier(NSString *fileName, NSString *bundleIdentifier) {
47 return [RLMDefaultDirectoryForBundleIdentifier(bundleIdentifier)
48 stringByAppendingPathComponent:fileName];
51 NSString *RLMRealmPathForFile(NSString *fileName) {
52 static NSString *directory = RLMDefaultDirectoryForBundleIdentifier(nil);
53 return [directory stringByAppendingPathComponent:fileName];
56 @implementation RLMRealmConfiguration {
57 realm::Realm::Config _config;
60 - (realm::Realm::Config&)config {
64 + (instancetype)defaultConfiguration {
65 return [[self rawDefaultConfiguration] copy];
68 + (void)setDefaultConfiguration:(RLMRealmConfiguration *)configuration {
70 @throw RLMException(@"Cannot set the default configuration to nil.");
72 @synchronized(c_defaultRealmFileName) {
73 s_defaultConfiguration = [configuration copy];
77 + (RLMRealmConfiguration *)rawDefaultConfiguration {
78 RLMRealmConfiguration *configuration;
79 @synchronized(c_defaultRealmFileName) {
80 if (!s_defaultConfiguration) {
81 s_defaultConfiguration = [[RLMRealmConfiguration alloc] init];
83 configuration = s_defaultConfiguration;
88 + (void)resetRealmConfigurationState {
89 @synchronized(c_defaultRealmFileName) {
90 s_defaultConfiguration = nil;
94 - (instancetype)init {
97 static NSURL *defaultRealmURL = [NSURL fileURLWithPath:RLMRealmPathForFile(c_defaultRealmFileName)];
98 self.fileURL = defaultRealmURL;
99 self.schemaVersion = 0;
102 // We have our own caching of RLMRealm instances, so the ObjectStore
103 // cache is at best pointless, and may result in broken behavior when
104 // a realm::Realm instance outlives the RLMRealm (due to collection
105 // notifiers being in the middle of running when the RLMRealm is
106 // dealloced) and then reused for a new RLMRealm
107 _config.cache = false;
113 - (instancetype)copyWithZone:(NSZone *)zone {
114 RLMRealmConfiguration *configuration = [[[self class] allocWithZone:zone] init];
115 configuration->_config = _config;
116 configuration->_cache = _cache;
117 configuration->_dynamic = _dynamic;
118 configuration->_migrationBlock = _migrationBlock;
119 configuration->_shouldCompactOnLaunch = _shouldCompactOnLaunch;
120 configuration->_customSchema = _customSchema;
121 return configuration;
124 - (NSString *)description {
125 NSMutableString *string = [NSMutableString stringWithFormat:@"%@ {\n", self.class];
126 for (NSString *key : c_RLMRealmConfigurationProperties) {
127 NSString *description = [[self valueForKey:key] description];
128 description = [description stringByReplacingOccurrencesOfString:@"\n" withString:@"\n\t"];
130 [string appendFormat:@"\t%@ = %@;\n", key, description];
132 return [string stringByAppendingString:@"}"];
135 static void RLMNSStringToStdString(std::string &out, NSString *in) {
136 out.resize([in maximumLengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
141 NSUInteger size = out.size();
145 encoding:NSUTF8StringEncoding
146 options:0 range:{0, in.length} remainingRange:nullptr];
151 if (_config.in_memory || _config.sync_config) {
154 return [NSURL fileURLWithPath:@(_config.path.c_str())];
157 - (void)setFileURL:(NSURL *)fileURL {
158 NSString *path = fileURL.path;
159 if (path.length == 0) {
160 @throw RLMException(@"Realm path must not be empty");
162 _config.sync_config = nullptr;
164 RLMNSStringToStdString(_config.path, path);
165 _config.in_memory = false;
168 - (NSString *)inMemoryIdentifier {
169 if (!_config.in_memory) {
172 return [@(_config.path.c_str()) lastPathComponent];
175 - (void)setInMemoryIdentifier:(NSString *)inMemoryIdentifier {
176 if (inMemoryIdentifier.length == 0) {
177 @throw RLMException(@"In-memory identifier must not be empty");
179 _config.sync_config = nullptr;
181 RLMNSStringToStdString(_config.path, [NSTemporaryDirectory() stringByAppendingPathComponent:inMemoryIdentifier]);
182 _config.in_memory = true;
185 - (NSData *)encryptionKey {
186 return _config.encryption_key.empty() ? nil : [NSData dataWithBytes:_config.encryption_key.data() length:_config.encryption_key.size()];
189 - (void)setEncryptionKey:(NSData * __nullable)encryptionKey {
190 if (NSData *key = RLMRealmValidatedEncryptionKey(encryptionKey)) {
191 auto bytes = static_cast<const char *>(key.bytes);
192 _config.encryption_key.assign(bytes, bytes + key.length);
193 if (_config.sync_config) {
194 auto& sync_encryption_key = self.config.sync_config->realm_encryption_key;
195 sync_encryption_key = std::array<char, 64>();
196 std::copy_n(_config.encryption_key.begin(), 64, sync_encryption_key->begin());
200 _config.encryption_key.clear();
201 if (_config.sync_config)
202 _config.sync_config->realm_encryption_key = realm::util::none;
207 return _config.immutable();
210 - (void)setReadOnly:(BOOL)readOnly {
212 if (self.deleteRealmIfMigrationNeeded) {
213 @throw RLMException(@"Cannot set `readOnly` when `deleteRealmIfMigrationNeeded` is set.");
214 } else if (self.shouldCompactOnLaunch) {
215 @throw RLMException(@"Cannot set `readOnly` when `shouldCompactOnLaunch` is set.");
217 _config.schema_mode = realm::SchemaMode::Immutable;
219 else if (self.readOnly) {
220 _config.schema_mode = realm::SchemaMode::Automatic;
224 - (uint64_t)schemaVersion {
225 return _config.schema_version;
228 - (void)setSchemaVersion:(uint64_t)schemaVersion {
229 if (schemaVersion == RLMNotVersioned) {
230 @throw RLMException(@"Cannot set schema version to %llu (RLMNotVersioned)", RLMNotVersioned);
232 _config.schema_version = schemaVersion;
235 - (BOOL)deleteRealmIfMigrationNeeded {
236 return _config.schema_mode == realm::SchemaMode::ResetFile;
239 - (void)setDeleteRealmIfMigrationNeeded:(BOOL)deleteRealmIfMigrationNeeded {
240 if (deleteRealmIfMigrationNeeded) {
242 @throw RLMException(@"Cannot set `deleteRealmIfMigrationNeeded` when `readOnly` is set.");
244 _config.schema_mode = realm::SchemaMode::ResetFile;
246 else if (self.deleteRealmIfMigrationNeeded) {
247 _config.schema_mode = realm::SchemaMode::Automatic;
251 - (NSArray *)objectClasses {
252 return [_customSchema.objectSchema valueForKeyPath:@"objectClass"];
255 - (void)setObjectClasses:(NSArray *)objectClasses {
256 self.customSchema = [RLMSchema schemaWithObjectClasses:objectClasses];
259 - (void)setDynamic:(bool)dynamic {
261 self.cache = !dynamic;
264 - (bool)disableFormatUpgrade {
265 return _config.disable_format_upgrade;
268 - (void)setDisableFormatUpgrade:(bool)disableFormatUpgrade {
269 _config.disable_format_upgrade = disableFormatUpgrade;
272 - (realm::SchemaMode)schemaMode {
273 return _config.schema_mode;
276 - (void)setSchemaMode:(realm::SchemaMode)mode {
277 _config.schema_mode = mode;
280 - (NSString *)pathOnDisk {
281 return @(_config.path.c_str());
284 - (void)setShouldCompactOnLaunch:(RLMShouldCompactOnLaunchBlock)shouldCompactOnLaunch {
285 if (shouldCompactOnLaunch) {
287 @throw RLMException(@"Cannot set `shouldCompactOnLaunch` when `readOnly` is set.");
288 } else if (_config.sync_config) {
289 @throw RLMException(@"Cannot set `shouldCompactOnLaunch` when `syncConfiguration` is set.");
291 _config.should_compact_on_launch_function = [=](size_t totalBytes, size_t usedBytes) {
292 return shouldCompactOnLaunch(totalBytes, usedBytes);
296 _config.should_compact_on_launch_function = nullptr;
298 _shouldCompactOnLaunch = shouldCompactOnLaunch;
301 - (void)setCustomSchemaWithoutCopying:(RLMSchema *)schema {
302 _customSchema = schema;