2014-07-11 8 views
5

Ho questo metodo con un incidente sul [NSKeyedArchiver archivedDataWithRootObject:self.data]:Crash su [NSKeyedArchiver archivedDataWithRootObject: self.data]

- (void) synchronize 
{ 
    @synchronized (self.data) 
    { 
     NSData *encryptedData = [[NSKeyedArchiver archivedDataWithRootObject:self.data] NL_AES256EncryptWithKey:userKey]; //La ça crash 
     BOOL success = [NSKeyedArchiver archiveRootObject:encryptedData toFile:[self filename]]; 

     if (!success) 
     { 
      // we lost some data :(
      NSLog(@"Failed to synchronize to file %@", [self filename]); 
     } 
    } 
} 

Il problema è che tutti gli accessi al metodo dell'oggetto (getter/setter) sono protetti con @synchronized(self.data) e questa proprietà è privata

Qualche idea?

EDIT: Il registro incidente è esplicito:

*** Collection <__NSArrayM: 0x1756a800> was mutated while being enumerated. 

0 CoreFoundation 0x2e95becb __exceptionPreprocess + 131 
1 libobjc.A.dylib 0x390f2ce7 objc_exception_throw + 39 
2 CoreFoundation 0x2e95b9b9 -[NSException name] + 1 
3 Foundation 0x2f2dd647 -[NSKeyedArchiver _encodeArrayOfObjects:forKey:] + 383 
4 Foundation 0x2f2ddc2d -[NSArray(NSArray) encodeWithCoder:] + 189 
5 Foundation 0x2f2dc479 _encodeObject + 1061 
6 Foundation 0x2f2dd657 -[NSKeyedArchiver _encodeArrayOfObjects:forKey:] + 399 
7 Foundation 0x2f2dd329 -[NSDictionary(NSDictionary) encodeWithCoder:] + 921 
8 Foundation 0x2f2dc479 _encodeObject + 1061 
9 Foundation 0x2f2e2899 +[NSKeyedArchiver archivedDataWithRootObject:] + 157 

Ma io non so come procedere per evitare l'incidente.

+0

Si sta utilizzando thread diversi per modificare i dati automatici? – jailani

+0

Stai usando le API di enumerazione ovunque nel codice ?? Se il tuo self.data è di tipo Mutable e se lo stai usando con Enumeration APIs causerà questo tipo di crash. Non è possibile utilizzare entrambi contemporaneamente. – DShah

+0

@jailani: Sì: questa classe è una classe di strumenti utilizzata nel mio progetto per salvare i dati. Ma tutti i metodi di questa classe sono chiamati in thread diversi in tutto il codice. – NiClou

risposta

3

Il problema era l'inserimento di una risorsa (self.data) per diversi thread. La mia soluzione (che funziona) era questo:

@property (nonatomic, assign) dispatch_queue_t persistanceQueue; 

Sul init:

self.persistanceQueue = dispatch_queue_create("com.myApp.savingQueue", NULL); 

Per il metodo di sincronizzazione:

- (void) synchronize 
{ 
    dispatch_sync(self.persistanceQueue, ^(void) { 
     NSData *encryptedData = [NSKeyedArchiver archivedDataWithRootObject:self.data]; 
     BOOL success = [NSKeyedArchiver archiveRootObject:encryptedData toFile:[self filename]]; 

     if (!success) 
     { 
      // we lost some data :(
      NSLog(@"Failed to synchronize to file %@", [self filename]); 
     } 
    }); 
} 

Per Getters:

- (id)objectForKey:(NSString *)defaultName { 
    __block id returnValue = nil; 
    dispatch_sync(self.persistanceQueue, ^{ 
     returnValue = self.data[defaultName]; 
    }); 

    return returnValue; 
} 

E per i setter:

- (void)setObject:(id)value forKey:(NSString *)defaultName 
{ 
    dispatch_sync(self.persistanceQueue, ^{ 
     if (value != nil) 
      self.data[defaultName] = value; 
     else 
      NSLog(@"Failed to save %@", defaultName); 
    }); 
}