I have this method with a crash on [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]);
}
}
}
The problem is that all access to the object method (getter/setter) are protected with @synchronized(self.data)
and this property is private.
Any idea?
EDIT: The crash log is explicit:
*** 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
But I don't know how to proceed to prevent the crash.
The problem was due to enter a resource (self.data) for several different thread. My solution (which works) was this:
@property (nonatomic, assign) dispatch_queue_t persistanceQueue;
On the init:
self.persistanceQueue = dispatch_queue_create("com.myApp.savingQueue", NULL);
For the sync method:
- (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]);
}
});
}
For getters:
- (id)objectForKey:(NSString *)defaultName {
__block id returnValue = nil;
dispatch_sync(self.persistanceQueue, ^{
returnValue = self.data[defaultName];
});
return returnValue;
}
And for Setters:
- (void)setObject:(id)value forKey:(NSString *)defaultName
{
dispatch_sync(self.persistanceQueue, ^{
if (value != nil)
self.data[defaultName] = value;
else
NSLog(@"Failed to save %@", defaultName);
});
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With