2012-03-13 6 views
30

Prima di iniziare, dovrei dirti che questo solo avviene in iOS 5.1. Prima dell'aggiornamento più recente, questo non era mai successo e non si verifica ancora su nessuna altra versione. Detto questo, ecco cosa sta succedendo.Perché la cancellazione di NSUserDefaults causa EXC_CRASH in seguito durante la creazione di UIWebView?

Quando un utente si disconnette dalla mia app, una delle cose che succede è che tutti gli NSUserDefaults vengono cancellati. Invece di rimuovere manualmente ogni chiave potrei aggiungere ai valori predefiniti dell'utente, ho appena completamente eliminare tutti i NSUserDefaults, utilizzando il metodo suggerito in this SO question:

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

quello che sembra accadere, però, è che ogni volta che cerco di creare un UIWebView dopo aver rimosso NSUserDefaults, ottengo un EXC_CRASH (SIGABRT). L'arresto si verifica quando chiamo [[UIWebView alloc] initWithFrame:frame]. Strano, vero? Chiudere e riaprire completamente l'app consente di creare nuovamente UIWebView s.

Quindi, sono riuscito a capire che la rimozione dei valori predefiniti avrebbe causato il problema UIWebView, ma per essere sicuro, ho aggiunto un punto di interruzione simbolico per -[NSUserDefaults setObject:forKey:].

-[NSUserDefaults setObject:forKey:] breakpoint

Creazione di un UIWebView fa infatti scattare il punto di interruzione.

Frugando attraverso i log di crash mi dà la ragione eccezione:

-[__NSCFDictionary setObject:forKey:]: attempt to insert nil value (key: WebKitLocalStorageDatabasePathPreferenceKey) 

Ed ecco l'inizio della traccia dello stack:

0 CoreFoundation 0x3340688f __exceptionPreprocess + 163 
1 libobjc.A.dylib 0x37bd4259 objc_exception_throw + 33 
2 CoreFoundation 0x33406789 +[NSException raise:format:] + 1 
3 CoreFoundation 0x334067ab +[NSException raise:format:] + 35 
4 CoreFoundation 0x3337368b -[__NSCFDictionary setObject:forKey:] + 235 
5 WebKit 0x3541e043 -[WebPreferences _setStringValue:forKey:] + 151 
6 UIKit 0x32841f8f -[UIWebView _webViewCommonInit:] + 1547 
7 UIKit 0x328418d7 -[UIWebView initWithFrame:] + 75 
8 MyApp 0x0007576f + 0 
9 UIKit 0x326d4dbf -[UIViewController view] + 51 
10 UIKit 0x327347e5 -[UITabBarController transitionFromViewController:toViewController:transition:shouldSetSelected:] + 93 
11 UIKit 0x32734783 -[UITabBarController transitionFromViewController:toViewController:] + 31 
12 UIKit 0x327340bd -[UITabBarController _setSelectedViewController:] + 301 
13 UIKit 0x327bd5d9 -[UITabBarController _tabBarItemClicked:] + 345 

quello che sto facendo per ora, e ciò che funziona, è solo tenere traccia dei tasti NSUserDefaults che ho impostato e rimuoverli tutti manualmente quando è necessario. Ma c'è sempre il rischio che io possa dimenticare una chiave sensibile, quindi semplicemente cancellare tutto NSUserDefaults mi sembra più sensato. Quindi, vorrei sapere perché non posso farlo. È un bug o sto facendo qualcosa di sbagliato?

Se desideri ulteriori informazioni, fammelo sapere! Grazie.

MODIFICA: l'eliminazione di [[NSUserDefaults standardUserDefaults] synchronize] dopo l'eliminazione di NSUserDefaults non è di aiuto.

+0

Mostra più codice che si sta utilizzando nello stesso controller. UIWebView dipende da qualsiasi valore memorizzato nelle preferenze? – WrightsCS

+0

Il 'EXC_CRASH' succede indipendentemente da quale controller sta caricando UIWebView. Ho avvolto tutti gli UIWebView nei blocchi '@try {} @catch {}' e tutti mi danno la stessa eccezione. Non riesco a pensare a nessun valore su cui UIWebView possa dipendere, specialmente al momento dell'inizializzazione. Se desideri ancora un codice da uno dei controller contenenti UIWebView, fammelo sapere. – cbrauchli

+0

sì, pubblica qualsiasi codice pertinente. – WrightsCS

risposta

24

Vedo anche questo problema, penso che sia necessario aver creato un UIWebView prima di cancellare i valori predefiniti dell'utente perché si verifichi. Un progetto pulito con quanto segue causerà l'arresto anomalo in iOS5.1, funziona perfettamente con iOS5.0 e precedenti:

UIWebView *webView = [[UIWebView alloc] init]; 
[webView release]; 

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

UIWebView *anotherWebView = [[UIWebView alloc] init]; 
[anotherWebView release]; 

posso risolvere l'incidente in questo modo, invece, che evita di dover ricordare tutte le vostre chiavi di impostazioni:

id workaround51Crash = [[NSUserDefaults standardUserDefaults] objectForKey:@"WebKitLocalStorageDatabasePathPreferenceKey"]; 
NSDictionary *emptySettings = (workaround51Crash != nil) 
       ? [NSDictionary dictionaryWithObject:workaround51Crash forKey:@"WebKitLocalStorageDatabasePathPreferenceKey"] 
       : [NSDictionary dictionary]; 
[[NSUserDefaults standardUserDefaults] setPersistentDomain:emptySettings forName:[[NSBundle mainBundle] bundleIdentifier]]; 

a nessuno di vedere eventuali problemi con facendo in questo modo?

+0

Ah sì, quello riproduce l'errore. Grazie per il consiglio! Inoltre, sembra un modo ragionevole per evitare il crash; L'ho usato e non ho notato alcun problema. Saluti :) lo ha fatto – cbrauchli

+0

e sembra funzionare. Sono sicuro che tutti abbiamo questo problema quando gestiamo un utente disconnettersi. –

+1

Questa è una buona soluzione, ma sembra troppo specifica e potrebbe non proteggersi da altre chiavi sconosciute su cui il sistema potrebbe fare affidamento. Ci ho messo un po 'di tempo, ma ho invece raccolto tutte le chiavi che stavo usando e le ho rimosse manualmente quando l'utente si è disconnesso. – Snowman

3

Sembra che tu stia rimuovendo una sorta di preferenza privata, che probabilmente è un nuovo bug, con NSUserDefaults (non dovresti essere in grado di rimuoverlo) o UIWebView (dovrebbe far fronte a una voce mancante).

Hai provato il metodo dall'altra risposta (impostazione di un dizionario vuoto?). Questo dà gli stessi risultati?

Cosa succede se si ottiene la rappresentazione del dizionario di NSUserDefaults, si ottengono tutte le chiavi e si scorre tra quelle, rimuovendo gli oggetti? (fammi sapere se hai bisogno di un esempio di codice per questo).

+0

Questo ha senso. Avevo provato l'altro metodo di impostare un dizionario vuoto inutilmente. Ho appena provato il tuo suggerimento di scorrere tutte le chiavi e questo produce lo stesso risultato. Guardando il dizionario, vedo un mazzo di chiavi che non ho impostato, principalmente nel formato 'WebKit *'. 'WebKitLocalStorageDatabasePathPreferenceKey' è tra quelli impostati. – cbrauchli

+0

Questo suona come un insetto, quindi. Se usi iOS 5.0 o versioni precedenti, le chiavi che vedi sono diverse? Quel genere di informazioni sarà necessario quando archivi il bug. – jrturton

+1

Ci scusiamo per il ritardo nel tornare a voi. Ho creato un'app pulita che imposta una chiave in NSUserDefaults, quindi elimina tutti gli NSUserDefaults, quindi tenta di creare UIWebView. Non sono ancora riuscito a riprodurre il bug, quindi posso solo supporre che qualcos'altro stia andando male nella mia app. Presenterò una segnalazione di bug e continuerò a cercare di riprodurre il bug. Inserirò qui con eventuali aggiornamenti. Grazie! – cbrauchli

0

funziona per me

NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; 

NSDictionary *userDefaultsDictionary = [userDefaults dictionaryRepresentation]; 
NSString *strWebDatabaseDirectory = [userDefaultsDictionary objectForKey:@"WebDatabaseDirectory"]; 
NSString *strWebKitLocalStorageDatabasePathPreferenceKey = [userDefaultsDictionary objectForKey:@"WebKitLocalStorageDatabasePathPreferenceKey"]; 

[userDefaults removePersistentDomainForName:[[NSBundle mainBundle] bundleIdentifier]]; 

if (strWebDatabaseDirectory) { 
    [userDefaults setObject:strWebDatabaseDirectory forKey:@"WebDatabaseDirectory"];} 
if (strWebKitLocalStorageDatabasePathPreferenceKey) { 
    [userDefaults setObject:strWebKitLocalStorageDatabasePathPreferenceKey forKey:@"WebKitLocalStorageDatabasePathPreferenceKey"];} 

[userDefaults synchronize]; 
0

semplice sarà quella di utilizzare il codice qui sotto:

[self saveValue:@"" forKey:@"WebKitLocalStorageDatabasePathPreferenceKey"]; 
[[NSUserDefaults standardUserDefaults] synchronize]; 

E 'più facile.