清除NSUserDefaults

292

我正在使用+[NSUserDefaults standardUserDefaults]来存储应用程序设置,其中包含大约十几个字符串值。是否可能永久删除这些值而不仅仅是将它们设置为默认值?


1
从NSUserDefaults中删除所有键 - Hemang
15个回答

524

您可以通过以下方式删除应用程序的持久域:

NSString *appDomain = [[NSBundle mainBundle] bundleIdentifier];
[[NSUserDefaults standardUserDefaults] removePersistentDomainForName:appDomain];

在 Swift 3 及以后的版本中:

if let bundleID = Bundle.main.bundleIdentifier {
    UserDefaults.standard.removePersistentDomain(forName: bundleID)
}

这与@samvermette的答案类似,但在我看来更加简洁。


这个很好用,谢谢!只是别忘了之后释放appDomain。 - IcyBlueRose
16
@IcyBlueRose - bundleIdentifier 是一个自动释放对象,因为它没有以 init 或 new 开头,所以你可能会过度释放它。 - Christopher Rogers
1
好的,谢谢!但是我在谈论字符串appDomain。它也会自动释放吗? - IcyBlueRose
2
@IcyBlueRose,bundleIdentifier返回的对象与appDomain引用的对象相同。 - Christopher Rogers
3
请确认一下这个是否有效,我似乎无法在10.8上使其工作。这里有一个相关的Stack Overflow问题:http://stackoverflow.com/questions/13595415/osx-preferences-file-removepersistentdomainforname-has-different-functionality - DaGaMs
显示剩余3条评论

103

这段代码将默认值重置为注册域:

[[NSUserDefaults standardUserDefaults] setPersistentDomain:[NSDictionary dictionary] forName:[[NSBundle mainBundle] bundleIdentifier]];

换句话说,它会删除您在该应用程序中注册的每个键的removeObjectForKey

感谢Ken Thomases在此苹果开发者论坛主题上的贡献。


4
非常感谢。为什么[NSUserDefaults resetStandardUserDefaults]无法做到这一点,我无法理解。 - jakeboxer
2
@jboxer 我刚花了一些时间研究苹果的文档,resetStandardUserDefaults 基本上会将内存缓冲区刷新到磁盘并将其清除。因此,下次尝试检索值时,它必须从磁盘中获取。Core Data 的 NSManagedObjectContext 也使用类似的“重置”术语。 - Christopher Rogers
2
哎呀,我的意思是它会清除内存缓存而不将其写入磁盘。因此,在同步到磁盘之前所做的任何更改都将丢失。 - Christopher Rogers
6
克里斯托弗,我认为你搞错了,虽然或许事情有所改变。resetStandardUserDefaults是我在iOS中看到的最令人困惑的调用。苹果文档中说,“同步对共享用户默认对象所做的任何更改,并将其从内存中释放。” 所以它实际上应该被称为flushAndReleaseStandardUserDefaults。我花时间评论一个旧评论,因为我刚刚被这个调用卡住了,想要避免其他人受到伤害(现在我必须告诉客户我需要更新90个应用程序)。 - Andy Dent

97

你尝试过使用-removeObjectForKey吗?

 [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"defunctPreference"];

感谢 sbooth。非常感激。 - TonyNeallon
5
有没有办法删除所有现有键的对象? - samvermette
2
虽然我理解这似乎可以工作,但为什么defunctPreference不是某种系统定义的常量呢?我肯定会担心它在未来某一天停止工作。 - David H
你需要在之后进行同步吗? - Travis M.

30

以下是 Swift 的答案:

let appDomain = NSBundle.mainBundle().bundleIdentifier!
NSUserDefaults.standardUserDefaults().removePersistentDomainForName(appDomain)

8
NSUserDefaults.standardUserDefaults().removePersistentDomainForName(NSBundle.mainBundle().bundleIdentifier!) 一行代码。 - Grace Huang
3
更安全的写法:如果 let domainName = NSBundle.mainBundle().bundleIdentifier { NSUserDefaults.standardUserDefaults().removePersistentDomainForName(domainName) }。该代码用于移除应用程序的持久化存储数据,若存在 domainName 变量则执行移除操作。 - Valentin Shergin
1
Grace的一行代码的Swift 4版本:UserDefaults.standard.removePersistentDomain(forName: Bundle.main.bundleIdentifier!) - Carsten Hagemann

29

在开发过程中,如果需要的话,您也可以重置模拟器并删除所有的NSUserDefaults

iOS 模拟器 -> 重置内容和设置...

请记住,这将同时删除模拟器上的所有应用程序和文件。


15
NSDictionary *defaultsDictionary = [[NSUserDefaults standardUserDefaults] dictionaryRepresentation];
for (NSString *key in [defaultsDictionary allKeys]) {
                    [[NSUserDefaults standardUserDefaults] removeObjectForKey:key];
}

7

在Swift中:

let defaults = NSUserDefaults.standardUserDefaults()
defaults.dictionaryRepresentation().keys.forEach { defaults.removeObjectForKey($0) }

7

当扩展程序使代码更加整洁时,我很喜欢它们:

extension NSUserDefaults {
    func clear() {
        guard let domainName = NSBundle.mainBundle().bundleIdentifier else {
            return
        }

        self.removePersistentDomainForName(domainName)
    }
}

Swift 5

extension UserDefaults {
    func clear() {
        guard let domainName = Bundle.main.bundleIdentifier else {
            return
        }
        removePersistentDomain(forName: domainName)
        synchronize()
    }
}

6

注意:本答案已更新适用于Swift。

把它放在一行上怎么样?

扩展@Christopher Rogers的答案 - 接受的答案。

[[NSUserDefaults standardUserDefaults] removePersistentDomainForName:[[NSBundle mainBundle] bundleIdentifier]];

有时候你可能需要同步它,

[[NSUserDefaults standardUserDefaults] synchronize];

我已经创建了一种方法来实现此功能。
- (void) clearDefaults {
    [[NSUserDefaults standardUserDefaults] removePersistentDomainForName:[[NSBundle mainBundle] bundleIdentifier]];
    [[NSUserDefaults standardUserDefaults] synchronize];
}

Swift?

使用Swift,这将更加容易。

extension UserDefaults {
    class func clean() {
        guard let aValidIdentifier = Bundle.main.bundleIdentifier else { return }
        standard.removePersistentDomain(forName: aValidIdentifier)
        standard.synchronize()
    }
}

使用方法:

UserDefaults.clean()

5
我找到了这个:
osascript -e 'tell application "iOS Simulator" to quit'
xcrun simctl list devices | grep -v '^[-=]' | cut -d "(" -f2 | cut -d ")" -f1 | xargs -I {} xcrun simctl erase "{}"

来源:https://gist.github.com/ZevEisenberg/5a172662cb576872d1ab

这是一份关于使用Swift实现线程安全单例模式的示例代码。单例模式是一种常见的设计模式,用于创建只有一个实例的类。在多线程环境下使用单例模式时需要特别小心,因为同时访问可能导致竞争条件并破坏单例模式的原则。在这个示例中,通过使用dispatch_once_t机制来确保只有一个实例被创建并且只会在需要时才会创建。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接