42

I'm playing around with realm (currently 0.85.0) and my application uses the database to store user-specific data such as the contacts of the current user. When the user decides to log out I need to remove every single bit of information about the user and the most obvious, simple and clean thing in my opinion would be to wipe the complete realm. Unfortunately, the Cocoa lib doesn't provide that functionality.

Currently, I'm stuck with the following

RLMRealm *realm = [RLMRealm defaultRealm];
[realm beginWriteTransaction];
[realm deleteObjects:[MyRealmClass1 allObjectsInRealm:realm]];
[realm deleteObjects:[MyRealmClass2 allObjectsInRealm:realm]];
[realm deleteObjects:[MyRealmClass3 allObjectsInRealm:realm]];
[realm commitWriteTransaction];

any better ideas?

thanks

Michael Alan Huff
  • 3,462
  • 3
  • 28
  • 44
floriankrueger
  • 2,003
  • 2
  • 16
  • 25

6 Answers6

56

Update:

Since posting, a new method has been added to delete all objects (as jpsim has already mentioned):

// Obj-C
[realm beginWriteTransaction];
[realm deleteAllObjects];
[realm commitWriteTransaction];


// Swift
try! realm.write {
  realm.deleteAll()
}

Note that these methods will not alter the data structure; they only delete the existing records. If you are looking to alter the realm model properties without writing a migration (i.e., as you might do in development) the old solution below may still be useful.

Original Answer:

You could simply delete the realm file itself, as they do in their sample code for storing a REST response:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    //...

    // Ensure we start with an empty database
    [[NSFileManager defaultManager] removeItemAtPath:[RLMRealm defaultRealmPath] error:nil];

    //...
}

Update regarding your comment:

If you need to be sure that the realm database is no longer in use, you could put realm's notifications to use. If you were to increment an openWrites counter before each write, then you could run a block when each write completes:

self.notificationToken = [realm addNotificationBlock:^(NSString *notification, RLMRealm * realm) {
    if([notification isEqualToString:RLMRealmDidChangeNotification]) {
        self.openWrites = self.openWrites - 1;

        if(!self.openWrites && self.isUserLoggedOut) {
            [[NSFileManager defaultManager] removeItemAtPath:[RLMRealm defaultRealmPath] error:nil];
        }
    }
}];
uɥƃnɐʌuop
  • 14,022
  • 5
  • 58
  • 61
  • Yes, I already tried that but the problem is that this approach gets really nasty when there are some threads in the background who try to do something on the realm while the user decides to log out. Deleting the file on disk has the disadvantage that it ignores the transactions which might currently be open and eventually causes the app to crash. And I really don't want to start synchronizing all my database accesses .. Thanks anyways :) – floriankrueger Sep 26 '14 at 20:35
  • 2
    Hey Tim from Realm here. DonamiteIsTnt has the right idea but you’re right that there are edge cases to this approach. We will be introducing a method to delete realm files in a safe way very soon. Sorry about this! – timanglade Sep 28 '14 at 03:24
  • @timanglade Any word on how this method is coming along? I can't seem to find it, but it would be a great feature to be able to just delete and recreate a realm file – cjwirth Feb 10 '15 at 01:59
  • @cjwirth as described [below](https://stackoverflow.com/a/26762999/3838010), it’s here: http://realm.io/docs/cocoa/api/Classes/RLMRealm.html#//api/name/deleteAllObjects – timanglade Feb 11 '15 at 07:15
  • Ah, thanks... I was kind of hoping you meant an api to delete the file. We only use it as a cache, and deleting/recreating the file is easier than dealing with migrations. – cjwirth Feb 11 '15 at 10:46
  • It's 2016. @timanglade, is there a safe way to delete the realm file and recreate it? Some of us just wants a clean slate when there is a data model change? – oky_sabeni Jan 25 '16 at 22:19
  • @okysabeni, you are correct, since this answer was posted, a method for just this purpose (check out jpsim's answer above). Namely, `[myRealm deleteAllObjects]` in a write transaction. But the old solution posted in my answer is still useful for development. I've updated to explain this. And thanks for the reminder. – uɥƃnɐʌuop Jan 25 '16 at 22:38
  • Hey Doanamite, Thanks! I did use your code for development. The problem is the edge case that cjwirth was talking about. It would delete a file but on another thread, it is trying to write to it and this causes a crash. It works fine when you restart the app but it's a bad experience for my users if I do this. – oky_sabeni Jan 25 '16 at 22:42
  • Ah, that make sense. Yes in that case it sounds like `deleteAll` would work out better than deleting the file, as it doesn't remove the file or it's data structure. – uɥƃnɐʌuop Jan 25 '16 at 22:49
  • @timanglade we need a safe method to delete realm files. any news on equivalent of deleteRealm that is there in java ? – 2ank3th Feb 03 '16 at 10:07
  • Right now there is no option in Java for deleting all data while keeping the schema. In 0.88 there will be a `Realm.clear()` method that does it. For now you have to iterate all classes and do it manually. You can see how here: https://github.com/realm/realm-java/issues/1796#issuecomment-157763025 – Christian Melchior Feb 04 '16 at 19:26
14

RealmSwift: Simple reset using a flag

Tried the above answers, but posting one more simple way to delete the realm file instead of migrating:

Realm.Configuration.defaultConfiguration.deleteRealmIfMigrationNeeded = true

This simply sets a flag so that Realm can delete the existing file rather than crash on try! Realm()

Instead of manually deleting the file

Thought that was simpler than the Swift version of the answer above:

guard let path = Realm.Configuration.defaultConfiguration.fileURL?.absoluteString else {
    fatalError("no realm path")
}

do {
    try NSFileManager().removeItemAtPath(path)
} catch {
    fatalError("couldn't remove at path")
}
jonchoi
  • 240
  • 2
  • 5
  • 1
    I don't know in which version exactly that was introduced but using `deleteRealmIfMigrationNeeded` is actually the correct way afaik now. – floriankrueger Nov 04 '16 at 11:23
11

As of realm 0.87.0, it's now possible to delete all realm contents by calling [[RLMRealm defaultRealm] deleteAllObjects] from a write transaction.

From Swift, it looks like this: RLMRealm.defaultRealm().deleteAllObjects()

jpsim
  • 14,329
  • 6
  • 51
  • 68
  • 3
    This one won't work if there's pending migration. Use @DonamiteIsTnt answer if you want to bypass migration – Le Duc Duy Jan 24 '15 at 09:09
7

In case someone stumbles on this question looking for a way to do this in Swift, this is just DonamiteIsTnt's answer rewritten. I've added this function to a custom utility class so I can do MyAppUtilities.purgeRealm() during testing & debugging

func purgeRealm() {
    NSFileManager.defaultManager().removeItemAtPath(RLMRealm.defaultRealmPath(), error: nil)
}

Note: If you find yourself in need of clearing data you might just check out Realm's new realm.addOrUpdateObject() feature which allows you to replace existing data by its primary key with the new data. This way you're not continually adding new data. Just replacing "old" data. If you do use addOrUpdateObject() make sure you override your model's primaryKey class function so Realm knows which property is your primary key. In Swift, for example:

override class func primaryKey() -> String {
    return "_id"
}
Glen Selle
  • 3,966
  • 4
  • 37
  • 59
1

I ran into this fun little issue. So instead i queried the schema version directly before running the schemamigration.

NSError *error = NULL;
NSUInteger currentSchemaVersion = [RLMRealm schemaVersionAtPath:[RLMRealm defaultRealmPath] error:&error];
if (currentSchemaVersion == RLMNotVersioned) {
    // new db, skip

} else if (currentSchemaVersion < 26) {
    // kill local db
    [[NSFileManager defaultManager] removeItemAtPath:[RLMRealm defaultRealmPath] error:&error];
    if (error) {
        MRLogError(error);
    }

} else if (error) {
    // for good measure...
    MRLogError(error);
}

// perform realm migration
[RLMRealm setSchemaVersion:26
            forRealmAtPath:[RLMRealm defaultRealmPath]
        withMigrationBlock:^(RLMMigration *migration, NSUInteger oldSchemaVersion) {

        }];
Steve Pascoe
  • 306
  • 3
  • 10
0

You can also go to the location where your realm file is stored, delete that file from there and next time when you open realm after running app, you will see the empty realm database in browser.