Очистка NSUserDefaults

285

Я использую +[NSUserDefaults standardUserDefaults]для хранения настроек приложения. Это состоит примерно из десятка строковых значений. Можно ли удалить эти значения навсегда, вместо того, чтобы просто установить их в значение по умолчанию?

TonyNeallon
источник

Ответы:

514

Вы можете удалить постоянный домен приложения следующим образом:

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

В Swift 3 и позже:

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

Это похоже на ответ @samvermette, но немного чище IMO.

Кристофер Роджерс
источник
Это сработало отлично, спасибо! Только не забудьте потом выпустить appDomain.
IcyBlueRose
15
@IcyBlueRose - bundleIdentifier является автоматически выпущенным объектом, так как он не начинается с init или new, поэтому вы можете перевыпустить его.
Кристофер Роджерс
1
Полезно знать, спасибо! Но я говорил о строке appDomain. Это авто выпущено тоже?
IcyBlueRose
2
@IcyBlueRose Объект, возвращаемый bundleIdentifier, совпадает с объектом, на который ссылается appDomain.
Кристофер Роджерс
2
Кажется, я больше не могу заставить это работать на 10.8, может кто-нибудь подтвердить, что это работает? Вот связанный вопрос SO: stackoverflow.com/questions/13595415/…
DaGaMs
102

Этот код сбрасывает настройки по умолчанию для домена регистрации:

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

Другими словами, это removeObjectForKeyдля каждого ключа, который вы когда-либо регистрировали в этом приложении.

Кредиты Кену Томасесу в этой теме на форуме разработчиков Apple .

samvermette
источник
4
Огромное спасибо. Почему [NSUserDefaults resetStandardUserDefaults]не сделать это вне меня.
jakeboxer
2
@jboxer Я просто потратил некоторое время на изучение документации Apple, и resetStandardUserDefaults в основном сбрасывает буфер в памяти на диск и очищает его. Поэтому в следующий раз, когда вы попытаетесь получить значение, оно должно получить его с диска. NSManagedObjectContext Core Data также использует аналогичную терминологию «перезагрузки».
Кристофер Роджерс
2
К сожалению, я имел в виду, что он стирает буфер в памяти, не записывая его на диск. Поэтому любые изменения, сделанные вами до синхронизации с диском, будут потеряны.
Кристофер Роджерс
4
Кристофер, я думаю, что у вас все наоборот, хотя, возможно, все изменилось. resetStandardUserDefaults - это вызов с самым запутанным названием, который я когда-либо видел в iOS. В Apple Docs говорится: «Синхронизирует любые изменения, внесенные в объект по умолчанию для общего пользователя, и освобождает его из памяти». поэтому он действительно должен называться flushAndReleaseStandardUserDefaults. Я трачу время, чтобы прокомментировать старый комментарий, потому что я только что пойман этим звонком и хочу избежать сожжения кого-либо еще (теперь я должен сказать клиенту, что мне нужно обновить 90 приложений).
Энди Дент
97

Вы пытались использовать - removeObjectForKey?

 [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"defunctPreference"];
sbooth
источник
Ура sbooth. Очень признателен.
TonyNeallon
5
Любой способ удалить объект для всех существующих ключей?
Самвермет
2
Хотя я понимаю, что это работает, почему defunctPreference не является определенной системной константой? Я бы наверняка нервничал, что это когда-нибудь перестанет работать.
Дэвид Х
Вы должны синхронизировать после?
Трэвис М.
30

Вот ответ в Swift:

let appDomain = NSBundle.mainBundle().bundleIdentifier!
NSUserDefaults.standardUserDefaults().removePersistentDomainForName(appDomain)
juliensaad
источник
8
NSUserDefaults.standardUserDefaults().removePersistentDomainForName(NSBundle.mainBundle().bundleIdentifier!)один лайнер
Грейс Шао
3
Или безопаснее:if let domainName = NSBundle.mainBundle().bundleIdentifier { NSUserDefaults.standardUserDefaults().removePersistentDomainForName(domainName) }
Валентин Шергин
1
Версия Swift 4 от Грейс:UserDefaults.standard.removePersistentDomain(forName: Bundle.main.bundleIdentifier!)
Карстен Хагеманн
28

Если вам это нужно во время разработки, вы также можете сбросить симулятор, удалив все NSUserDefaults.

Симулятор iOS -> Сбросить содержимое и настройки ...

Имейте в виду, что он также удалит все приложения и файлы на симуляторе.

Роджер Саноли
источник
15
NSDictionary *defaultsDictionary = [[NSUserDefaults standardUserDefaults] dictionaryRepresentation];
for (NSString *key in [defaultsDictionary allKeys]) {
                    [[NSUserDefaults standardUserDefaults] removeObjectForKey:key];
}
Folse
источник
7

В Свифте:

let defaults = NSUserDefaults.standardUserDefaults()
defaults.dictionaryRepresentation().keys.forEach { defaults.removeObjectForKey($0) }
Адам Уэйт
источник
6

Примечание. Этот ответ также был обновлен для Swift.

Как насчет того, чтобы это было на одной линии?

Расширяя ответ @Christopher Rogers - принятый.

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

и да, иногда тебе это может понадобиться synchronize,

[[NSUserDefaults standardUserDefaults] synchronize];

Я создал метод, чтобы сделать это,

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

Свифт ?

С быстрым его еще проще.

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

И использование :

UserDefaults.clean()
Hemang
источник
6

Я люблю расширения, когда они делают код чище:

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()
    }
}
Валентин Шергин
источник
2

Все вышеприведенные ответы очень актуальны, но если кто-то все еще не может сбросить пользовательские настройки по умолчанию для удаленного приложения, тогда вы можете сбросить настройки контента вашего симулятора, и он будет работать.введите описание изображения здесь

iDevAmit
источник
2

Это ошибка или что-то еще, но removePersistentDomainForNameне работает при очистке всех NSUserDefaultsзначений.

Итак, лучший вариант - сбросить настройки PersistentDomainи сделать это можно следующим образом:

NSUserDefaults.standardUserDefaults().setPersistentDomain(["":""], forName: NSBundle.mainBundle().bundleIdentifier!)
Сохил Р. Мемон
источник
1

Расширяя ответ @ folse ... Я считаю, что более правильная реализация будет ...

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];
    }

... вызов метода NSUserDefault persistentDomainForName:. Как указано в документе, метод «Возвращает словарь, содержащий ключи и значения в указанном постоянном домене». Вызов DictionaryRepresentation: вместо этого будет возвращен словарь, который, вероятно, будет включать другие параметры, поскольку он применяется к более широкой области.

Если вам нужно отфильтровать любое из значений, которые должны быть сброшены, то итерация по ключам - это способ сделать это. Очевидно, что если вы хотите просто обнулить все префы для приложения безотносительно, то один из других методов, опубликованных выше, является наиболее эффективным.

markeissler
источник
0

если настройка приложения, требующая сброса, - это nsuserdefault для доступа к микрофону (в моем случае), простым решением является ответ Энтони Маккормика ( Iphone - Как включить доступ приложения к медиафайлам на устройстве? - ALAssetsLibraryErrorDomain Code = -3312 «Глобальный отказ в доступе» ).

на устройстве перейдите в «Настройки»> «Основные»> «Сброс»> «Сбросить предупреждения о местоположении»

пмр
источник
0

Попробуйте это, это работает для меня.

Одна строка кода

[[NSUserDefaults standardUserDefaults] removePersistentDomainForName:[[NSBundle mainBundle] bundleIdentifier]];
Джейвант Хедкар
источник