Limpar NSUserDefaults

285

Estou usando +[NSUserDefaults standardUserDefaults]para armazenar as configurações do aplicativo. Isso consiste em aproximadamente uma dúzia de valores de string. É possível excluir esses valores permanentemente, em vez de apenas defini-los com um valor padrão?

TonyNeallon
fonte

Respostas:

514

Você pode remover o domínio persistente do aplicativo como este:

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

No Swift 3 e posterior:

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

Isso é semelhante à resposta de @samvermette, mas é um IMO um pouco mais limpo.

Christopher Rogers
fonte
Isso funcionou muito bem, obrigado! Só não se esqueça de lançar o appDomain depois.
IcyBlueRose
15
@IcyBlueRose - bundleIdentifier é um objeto liberado automaticamente, uma vez que não começa com init ou novo; portanto, você o lançará em excesso.
Christopher Rogers
1
É bom saber, obrigado! Mas eu estava falando sobre a string appDomain. Esse automóvel também é lançado?
IcyBlueRose 17/10
2
@IcyBlueRose O objeto retornado por bundleIdentifier é o mesmo que o objeto referenciado por appDomain.
9788 Christopher Rogers
2
Parece que não consigo fazer isso funcionar na versão 10.8, alguém poderia confirmar que isso funciona? Aqui está uma pergunta relacionada ao SO: stackoverflow.com/questions/13595415/…
DaGaMs
102

Esse código redefine os padrões para o domínio de registro:

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

Em outras palavras, é removeObjectForKeypara todas as chaves que você já registrou nesse aplicativo.

Créditos a Ken Thomases neste tópico dos Fóruns de desenvolvedores da Apple .

samvermette
fonte
4
Muitíssimo obrigado. Por que [NSUserDefaults resetStandardUserDefaults]isso não está além de mim.
Jakeboxer
2
@jboxer Acabei de passar algum tempo estudando a documentação da Apple e resetStandardUserDefaults basicamente libera o buffer da memória no disco e o limpa. Portanto, na próxima vez que você tentar recuperar um valor, ele precisará pegá-lo do disco. O NSManagedObjectContext da Core Data também usa terminologia de "redefinição" semelhante.
Christopher Rogers
2
Opa, eu quis dizer que ele limpa o buffer da memória sem gravá-lo no disco. Portanto, todas as alterações feitas antes da sincronização com o disco serão perdidas.
Christopher Rogers
4
Christopher, acho que você o retrocede, embora talvez as coisas tenham mudado. resetStandardUserDefaults é a chamada com o nome mais confuso que vi até agora no iOS. Os documentos da Apple dizem "Sincroniza as alterações feitas no objeto de padrões de usuário compartilhado e o libera da memória". portanto, deve realmente ser chamado de flushAndReleaseStandardUserDefaults. Estou reservando um tempo para comentar um comentário antigo, porque acabei de ser pego por essa ligação e quero evitar que outras pessoas sejam queimadas (agora tenho que dizer a um cliente que preciso atualizar 90 aplicativos).
Andy Dent
97

Você tentou usar - removeObjectForKey?

 [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"defunctPreference"];
sbooth
fonte
Cheers sbooth. Muito apreciado.
21410 TonyNeallon
5
Alguma maneira de remover o objeto de todas as chaves existentes?
samvermette
2
Embora eu entenda que isso parece funcionar, por que o DefunctPreference não é algum tipo de constante definida pelo sistema? Eu com certeza ficaria nervoso que isso pararia de funcionar algum dia no futuro.
9309 David H das
Você precisa sincronizar depois?
22415 Travis M.
30

Aqui está a resposta no Swift:

let appDomain = NSBundle.mainBundle().bundleIdentifier!
NSUserDefaults.standardUserDefaults().removePersistentDomainForName(appDomain)
juliensaad
fonte
8
NSUserDefaults.standardUserDefaults().removePersistentDomainForName(NSBundle.mainBundle().bundleIdentifier!)one-liner
Grace Shao
3
Ou mais seguro:if let domainName = NSBundle.mainBundle().bundleIdentifier { NSUserDefaults.standardUserDefaults().removePersistentDomainForName(domainName) }
Valentin Shergin
1
Versão Swift 4 do oneliner de Grace:UserDefaults.standard.removePersistentDomain(forName: Bundle.main.bundleIdentifier!)
Carsten Hagemann
28

Se você precisar dele durante o desenvolvimento, também poderá redefinir seu simulador, excluindo tudo NSUserDefaults.

Simulador iOS -> Redefinir conteúdo e configurações ...

Lembre-se de que ele também excluirá todos os aplicativos e arquivos no simulador.

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

Em Swift:

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

Nota: Esta resposta também foi atualizada para o Swift.

Que tal tê-lo em uma linha?

Extensão da resposta de Christopher Rogers - a aceita.

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

e sim, às vezes você pode precisar synchronize,

[[NSUserDefaults standardUserDefaults] synchronize];

Eu criei um método para fazer isso,

- (void) clearDefaults {
    [[NSUserDefaults standardUserDefaults] removePersistentDomainForName:[[NSBundle mainBundle] bundleIdentifier]];
    [[NSUserDefaults standardUserDefaults] synchronize];
}

Swift ?

Com rápido é ainda mais fácil.

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

E uso :

UserDefaults.clean()
Hemang
fonte
6

Adoro extensões quando elas tornam o código mais limpo:

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()
    }
}
Valentin Shergin
fonte
5

Eu achei isto:

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 "{}"

Fonte: https://gist.github.com/ZevEisenberg/5a172662cb576872d1ab

Daniel Gomez Rico
fonte
2

Todas as respostas acima são muito relevantes, mas se alguém ainda não conseguir redefinir os padrões do usuário para o aplicativo excluído, você poderá redefinir as configurações de conteúdo do seu simulador e ele funcionará.insira a descrição da imagem aqui

iDevAmit
fonte
2

É um bug ou o que seja, mas o removePersistentDomainForNamenão está funcionando enquanto limpa todos os NSUserDefaultsvalores.

Portanto, a melhor opção é redefinir o PersistentDomainque você pode fazer da seguinte maneira:

NSUserDefaults.standardUserDefaults().setPersistentDomain(["":""], forName: NSBundle.mainBundle().bundleIdentifier!)
Sohil R. Memon
fonte
1

Expandindo a resposta da @ folse ... acredito que uma implementação mais correta seria ...

NSString *appDomain = [[NSBundle mainBundle] bundleIdentifier];
NSDictionary *defaultsDictionary = [[NSUserDefaults standardUserDefaults] persistentDomainForName: appDomain];
    for (NSString *key in [defaultsDictionary allKeys]) {
      NSLog(@"removing user pref for %@", key);
      [[NSUserDefaults standardUserDefaults] removeObjectForKey:key];
    }

... chamando o método persistentDomainForName: do NSUserDefault. Como os documentos afirmam, o método "Retorna um dicionário que contém as chaves e os valores no domínio persistente especificado". Chamar dictionaryRepresentation: em vez disso, retornará um dicionário que provavelmente incluirá outras configurações conforme se aplica a um escopo mais amplo.

Se você precisar filtrar qualquer um dos valores a serem redefinidos, a iteração sobre as chaves é a maneira de fazê-lo. Obviamente, se você quiser apenas refinar todas as preferências do aplicativo sem levar em conta, um dos outros métodos publicados acima é o mais eficiente.

markeissler
fonte
0

Tente isso, está funcionando para mim.

Linha de código única

[[NSUserDefaults standardUserDefaults] removePersistentDomainForName:[[NSBundle mainBundle] bundleIdentifier]];
Jaywant Khedkar
fonte