Crash while trying to add an object to a mutable dictionaryy
Crash while trying to add an object to a mutable dictionaryy
- Subject: Crash while trying to add an object to a mutable dictionaryy
- From: Laurent Daudelin <email@hidden>
- Date: Thu, 20 Sep 2012 13:31:16 -0700
I did develop a technique to keep the network activity indicator spinning when multiple sources may request to have it spinning.
In my app delegate, I have those methods:
- (void)startNetworkIndicatorForInstance:(id)anInstance
{
NSString *addressAsString = [NSString stringWithFormat:@"%p", anInstance];
if (addressAsString == nil) {
return;
}
NSNumber *numberOfInvocations = [self.networkIndicatorClients objectForKey:addressAsString];
if (numberOfInvocations == nil) {
numberOfInvocations = [NSNumber numberWithInt:1];
[self.networkIndicatorClients setObject:numberOfInvocations forKey:addressAsString];
}
else {
[self.networkIndicatorClients setObject:[NSNumber numberWithInt:[numberOfInvocations intValue] + 1] forKey:addressAsString];
}
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
_networkIndicatorStack++;
if (_networkIndicatorStack > 0 && ! [UIApplication sharedApplication].networkActivityIndicatorVisible)
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
}];
}
- (void)reallyStopNetworkIndicatorFromTimer:(NSTimer *)aTimer
{
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[aTimer invalidate];
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}];
}
- (void)stopNetworkIndicatorOnMainThread
{
// In case of very short start and stop, we don't want to have the indicator flickering so when we get a stop, we delay
// the hiding by one second
[[self class] cancelPreviousPerformRequestsWithTarget:self selector:@selector(reallyStopNetworkIndicatorFromTimer:) object:NULL];
[self performSelector:@selector(reallyStopNetworkIndicatorFromTimer:) withObject:NULL afterDelay:PERFORM_DELAY];
}
- (void)stopNetworkIndicatorForInstance:(id)anInstance
{
NSString *addressAsString = [[NSString stringWithFormat:@"%p", anInstance] copy];
NSNumber *numberOfInvocations = [self.networkIndicatorClients objectForKey:addressAsString];
if (numberOfInvocations != nil) {
if ([numberOfInvocations intValue] > 1) {
[self.networkIndicatorClients setObject:[NSNumber numberWithInt:[numberOfInvocations intValue] - 1] forKey:addressAsString];
}
else {
[self.networkIndicatorClients removeObjectForKey:addressAsString];
}
}
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
_networkIndicatorStack--;
if (_networkIndicatorStack < 0) {
_networkIndicatorStack = 0;
}
if (_networkIndicatorStack == 0) {
[self stopNetworkIndicatorOnMainThread];
}
}];
}
I have a setup with multiple UITableViewCells that download content from a server. They each send the app delegate startNetworkIndicatorForInstance: and they give their own pointer as the caller. As you can see in that method implementation, the app delegate object converts the address into a string and then check to see if that instance has already sent a startNetworkIndicatorForInstance:. If it hasn't, I create an NSNumber and set this object for the pointer address as a string as the key. I think it's fairly obvious what is happening. When a UITableViewCell is finished with its downloads (can have more than one), it sends the delegate stopNetworkIndicatorForInstance:.
If the UITableViewCell is about to be deallocated and had a download executing, it cancels the download and send the app delegate stopNetworkIndicatorForInstance:
This all works pretty well except that from time to time, the app will crash with a SIGABRT:
• 0 erodr 0x0011cfe6 testflight_backtrace + 238
• 1 erodr 0x0011dcd0 TFSignalHandler + 264
• 2 libsystem_c.dylib 0x3901de92 _sigtramp + 42
• 3 libsystem_c.dylib 0x39014122 pthread_kill + 58
• 4 libsystem_c.dylib 0x39050972 abort + 94
• 5 libsystem_c.dylib 0x3901af18 <redacted> + 0
• 6 libsystem_c.dylib 0x3901b234 <redacted> + 84
• 7 libsystem_c.dylib 0x38fe92de free + 170
• 8 CoreFoundation 0x35262cae <redacted> + 206
• 9 CoreFoundation 0x351c5560 <redacted> + 732
• 10 erodr 0x000d7b06 -[ERAppDelegate startNetworkIndicatorForInstance:] (ERAppDelegate.m:747)
• 11 erodr 0x000f531c __68-[StreamerImageTextCell downloadPictureFromURL:forKey:inDictionary:]_block_invoke_0 (StreamerImageTextCell.m:81)
• 12 Foundation 0x32ca5538 <redacted> + 200
• 13 Foundation 0x32c9cdb8 <redacted> + 840
• 14 Foundation 0x32d153da <redacted> + 102
• 15 libdispatch.dylib 0x33f5411e <redacted> + 10
• 16 libdispatch.dylib 0x33f58960 <redacted> + 252
• 17 libdispatch.dylib 0x33f58ac0 <redacted> + 84
• 18 libsystem_c.dylib 0x38feba10 <redacted> + 360
• 19 libsystem_c.dylib 0x38feb8a3 start_wqthread + 7
Line 747 of ERAppDelegate.m is:
[self.networkIndicatorClients setObject:numberOfInvocations forKey:addressAsString];
I have no idea why this crash is happening. I use the same technique in another app and never had a crash in the startNetworkIndicatorForInstance:.
Anybody has any idea of what is going on?
Thanks!
-Laurent.
--
Laurent Daudelin
AIM/iChat/Skype:LaurentDaudelin http://www.nemesys-soft.com/
Logiciels Nemesys Software email@hidden
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden