I recently started testing my application using a release build (Manage Schemes and set run from debug to release). What I've noticed is that occasionally I get the following error pop up inside the stream method and I can't seem to figure out a way to find the error. This works perfectly in debug mode, but in the release build I am not getting any notification aside from the SIGABRT message. Nor am I aware of how to check the crash logs on the simulator to see what the issue can be. Below I've attached a stack trace of the crash:
#0 0x918749c6 in __pthread_kill ()
#1 0x916c0f78 in pthread_kill ()
#2 0x916b1ce3 in __abort ()
#3 0x916ae64a in __stack_chk_fail ()
#4 0x00006d0d in -[MainViewController processMessage:len:] (_cmd=0x9ceb9, msg=0xdfd7004 "Login="User" Pass="Pass" Id="1234" PlayerId="345" Location="12,35" Color="Red" PlayerId="65" Location="180,0" Color="Blue" PlayerId="29" Location="0,200" Color="..., len=333295) at /Users/seb/Desktop/Tutorials/Networking/MainViewController.m:850
#5 0x000044b3 in -[MainViewController stream:handleEvent:] (_cmd=0x17a0410, stream=<value temporarily unavailable, due to optimizations>, eventCode=<value temporarily unavailable, due to optimizations>) at /Users/seb/Desktop/Tutorials/Networking/MainViewController.m:260
#6 0x01716501 in _inputStreamCallbackFunc ()
#7 0x016e606d in _signalEventSync ()
#8 0x016e67ca in _cfstream_solo_signalEventSync ()
#9 0x016e5e71 in _CFStreamSignalEvent ()
#10 0x016e6727 in CFReadStreamSignalEvent ()
#11 0x020083ad in SocketStream::dispatchSignalFromSocketCallbackUnlocked ()
#12 0x01f64191 in SocketStream::socketCallback ()
#13 0x01f640a1 in SocketStream::_SocketCallBack_stream ()
#14 0x016b3e44 in __CFSocketPerformV0 ()
#15 0x0171997f in __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ ()
#16 0x0167cb73 in __CFRunLoopDoSources0 ()
#17 0x0167c454 in __CFRunLoopRun ()
#18 0x0167bdb4 in CFRunLoopRunSpecific ()
#19 0x0167bccb in CFRunLoopRunInMode ()
#20 0x0226f879 in GSEventRunModal ()
#21 0x0226f93e in GSEventRun ()
#22 0x0066aa9b in UIApplicationMain ()
#23 0x0000201b in main (argc=1, argv=0xbffff5e0) at /Users/seb/Desktop/Tutorials/Networking/main.m:14
Case statement from stream:handleevent in where the crash happens:
case NSStreamEventHasBytesAvailable:
{
if (stream == inputStream)
{
NSLog(#"NSStreamEventHasBytesAvailable");
uint8_t buffer[4096];
unsigned int len = 0;
NSInputStream* inputstream = (NSInputStream*)stream;
len = [inputstream read:buffer maxLength:sizeof(buffer)];
// Check if our stream is still valid
if([inputstream streamError] != nil)
{
//We lost our connection to the host
NSError *theError = [stream streamError];
[self setConnectError:[NSString stringWithFormat:#"Error %i: %#",
[theError code], [theError localizedDescription]]];
break;
}
[streamIncomingData appendBytes:buffer length:len];
int processedBytes = 0;
while (true)
{
if ([streamIncomingData length] >= processedBytes + sizeof(uint32_t))
{
const char* bufferstart = ((const char*)[streamIncomingData mutableBytes]) + processedBytes;
uint32_t sz_n;
memcpy(&sz_n, bufferstart, sizeof(sz_n));
uint32_t sz_h = htonl(sz_n);
if ([streamIncomingData length] >= processedBytes + sz_h + sizeof(uint32_t))
{
[self processMessage:bufstart + sizeof(uint32_t) len:sz_h];
processedBytes += sz_h + sizeof(uint32_t);
}
else
{
break;
}
}
else
{
break;
}
}
if (processedBytes)
{
if (processedBytes < [streamIncomingData length])
{
NSMutableData *newdata = [NSMutableData dataWithBytes:[streamIncomingData bytes] + processedBytes length:[streamIncomingData length] - processedBytes];
[streamIncomingData setData:newdata];
}
else
{
[streamIncomingData setLength:0];
}
}
}
break;
}
processMessage method:
- (void)processMessage:(const char*)msg len:(int)len
{
NSLog(#"processMessage start (%d)", len);
{
char buffer[len + 1];
memcpy(buffer, msg, len);
buffer[len + 1] = '\0';
NSLog(#"%s", buffer);
}
NSLog(#"processMessage end");
}
Any advice is greatly appreciated.
You have corrupted the stack by overflowing the buffer by trying to assign the null terminator outside of the bounds len + 1. The correct code would be:
char buffer[len + 1];
memcpy(buffer, msg, len);
buffer[len] = '\0';
NSLog(#"%s", buffer);
What you were doing was undefined behavior and combining undefined behavior with the optimizations that are done for release mode is most likely the reason you only saw this issue in release mode.
Related
I receive about 5,000 reported issue for reason "Received a notification with no notification name" everyday.
Application Specific Information:
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException' reason: 'Received a notification with no notification name'
Last Exception Backtrace:
0 CoreFoundation 0x000000018206e950 __exceptionPreprocess + 132
1 libobjc.A.dylib 0x000000018e5741fc objc_exception_throw + 60
2 CoreFoundation 0x000000018206e810 +[NSException raise:format:arguments:] + 116
3 Foundation 0x0000000182ba6db4 -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 112
4 CoreTelephony 0x00000001827ca39c -[CTTelephonyNetworkInfo handleNotificationFromConnection:ofType:withInfo:] + 272
5 CoreTelephony 0x00000001827c9784 _ServerConnectionCallback(__CTServerConnection*, __CFString const*, __CFDictionary const*, void*) + 152
6 CoreTelephony 0x00000001827de958 ___ZNK13CTServerState21sendNotification_syncE7CTEventPK10__CFStringPK14__CFDictionary_block_invoke15 + 32
7 libdispatch.dylib 0x000000018eb4c014 _dispatch_call_block_and_release + 24
8 libdispatch.dylib 0x000000018eb4bfd4 _dispatch_client_callout + 16
9 libdispatch.dylib 0x000000018eb524a8 _dispatch_queue_drain + 640
10 libdispatch.dylib 0x000000018eb4e4c0 _dispatch_queue_invoke + 68
11 libdispatch.dylib 0x000000018eb530f4 _dispatch_root_queue_drain + 104
12 libdispatch.dylib 0x000000018eb534fc _dispatch_worker_thread2 + 76
13 libsystem_pthread.dylib 0x000000018ece16bc _pthread_wqthread + 356
14 libsystem_pthread.dylib 0x000000018ece154c start_wqthread + 4
I found all CoreTelephony notification and tried to reproduce the issue but failed.
/* For use with the CoreTelephony notification system. */
extern CFStringRef kCTRegistrationStatusChangedNotification;
extern CFStringRef kCTRegistrationStateDurationReportNotification;
extern CFStringRef kCTRegistrationServiceProviderNameChangedNotification;
extern CFStringRef kCTRegistrationOperatorNameChangedNotification;
extern CFStringRef kCTRegistrationNewServingNetworkNotification;
extern CFStringRef kCTRegistrationDataStatusChangedNotification;
extern CFStringRef kCTRegistrationDataActivateFailedNotification;
extern CFStringRef kCTRegistrationCellularDataPlanHideIndicatorNotification;
extern CFStringRef kCTRegistrationCellularDataPlanActivateFailedNotification;
extern CFStringRef kCTRegistrationCustomerServiceProfileUpdateNotification;
extern CFStringRef kCTRegistrationCellChangedNotification;
extern CFStringRef kCTRegistrationCauseCodeNotification;
Why do I get this crash?
And how can I change my code so that I do not get this issue anymore?
Any help is highly appreciated.
EDIT:
I am using Reachability class (https://github.com/tonymillion/Reachability) to detect network type.
+ (NSString *)networkName
{
Reachability *reach = [Reachability reachabilityForInternetConnection];
[reach startNotifier];
NetworkStatus networkStatus = [reach currentReachabilityStatus];
CTTelephonyNetworkInfo *telephonyInfo = [[CTTelephonyNetworkInfo alloc] init];
if (networkStatus == ReachableViaWiFi) {
return #"WIFI";
} else if (networkStatus == ReachableViaWWAN) {
if ([telephonyInfo respondsToSelector:#selector(currentRadioAccessTechnology)]) {
if ([[telephonyInfo currentRadioAccessTechnology] isEqualToString:CTRadioAccessTechnologyGPRS]) {
return #"GPRS";
} else if ([[telephonyInfo currentRadioAccessTechnology] isEqualToString:CTRadioAccessTechnologyEdge]) {
return #"EDGE";
} else if ([[telephonyInfo currentRadioAccessTechnology] isEqualToString:CTRadioAccessTechnologyWCDMA]) {
return #"WCDMA";
} else if ([[telephonyInfo currentRadioAccessTechnology] isEqualToString:CTRadioAccessTechnologyHSDPA]) {
return #"HSDPA";
} else if ([[telephonyInfo currentRadioAccessTechnology] isEqualToString:CTRadioAccessTechnologyHSUPA]) {
return #"HSUPA";
} else if ([[telephonyInfo currentRadioAccessTechnology] isEqualToString:CTRadioAccessTechnologyCDMA1x]) {
return #"CDMA1X";
} else if ([[telephonyInfo currentRadioAccessTechnology] isEqualToString:CTRadioAccessTechnologyCDMAEVDORev0]) {
return #"CDMAEVDOREV0";
} else if ([[telephonyInfo currentRadioAccessTechnology] isEqualToString:CTRadioAccessTechnologyCDMAEVDORevA]) {
return #"CDMAEVDOREVA";
} else if ([[telephonyInfo currentRadioAccessTechnology] isEqualToString:CTRadioAccessTechnologyCDMAEVDORevB]) {
return #"CDMAEVDOREVB";
} else if ([[telephonyInfo currentRadioAccessTechnology] isEqualToString:CTRadioAccessTechnologyeHRPD]) {
return #"HRPD";
} else if ([[telephonyInfo currentRadioAccessTechnology] isEqualToString:CTRadioAccessTechnologyLTE]) {
return #"LTE";
}
return #"UNKNOWN";
} else {
return #"WWAN";
}
} else {
return #"NotReachable";
}
}
I wonder if this is related to this similar issue with the old version of TestFlight:
There is an iOS bug that causes instances of the CTTelephonyNetworkInfo class to sometimes get notifications after they have been deallocated. Instead of instantiating, using, and releasing instances you must instead retain and never release them to work around the bug.
This smells like a zombie from the looks of your backtrace. Why not try using a static instance of CTTelephonyNetworkInfo that is never released as suggested in the linked question?
#import CoreTelephony;
// ...
static CTTelephonyNetworkInfo *netInfo;
static dispatch_once_t dispatchToken;
if (!netInfo) {
dispatch_once(&dispatchToken, ^{
netInfo = [[CTTelephonyNetworkInfo alloc] init];
});
}
To fix this issue, I use method swizzling to re-routing all calls that were originally sent to -[CTTelephonyNetworkInfo handleNotificationFromConnection:ofType:withInfo:] .
It works fine.
#import <CoreTelephony/CTTelephonyNetworkInfo.h>
struct __CTServerConnection {
int a;
int b;
CFMachPortRef myport;
int c;
int d;
int e;
int f;
int g;
int h;
int i;
};
typedef struct __CTServerConnection CTServerConnection;
typedef CTServerConnection* CTServerConnectionRef;
#implementation CTTelephonyNetworkInfo (Fixed)
- (void)fixed_handleNotificationFromConnection:(CTServerConnectionRef)connection
ofType:(NSString *)notificationName
withInfo:(NSDictionary *)info
{
if ([notificationName length]) {
return [self fixed_handleNotificationFromConnection:connection
ofType:notificationName
withInfo:info];
}
}
This only seems to happen when running unit tests against one of my view controllers, and it's pretty random. Sometimes the test will pass, but most of the time it crashes in the same place.
The following is the stack trace from Xcode:
#0 0x000000010e66727c in CFRelease ()
#1 0x000000011b4b1e00 in 0x11b4b1e00 ()
#2 0x000000010e667268 in CFRelease ()
#3 0x000000010de060b8 in (anonymous namespace)::AutoreleasePoolPage::pop(void*) ()
#4 0x000000011b325c23 in -[XCTestCase performTest:] ()
#5 0x000000011b3238d1 in -[XCTestSuite performTest:] ()
#6 0x000000011b3238d1 in -[XCTestSuite performTest:] ()
#7 0x000000011b3238d1 in -[XCTestSuite performTest:] ()
#8 0x000000011b310adc in __25-[XCTestDriver _runSuite]_block_invoke ()
#9 0x000000011b3312e3 in -[XCTestObservationCenter _observeTestExecutionForBlock:] ()
#10 0x000000011b310a28 in -[XCTestDriver _runSuite] ()
#11 0x000000011b311787 in -[XCTestDriver _checkForTestManager] ()
#12 0x000000011b359b23 in _XCTestMain ()
#13 0x000000010e6c2ffc in __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ ()
#14 0x000000010e6b8c85 in __CFRunLoopDoBlocks ()
#15 0x000000010e6b83e2 in __CFRunLoopRun ()
#16 0x000000010e6b7e08 in CFRunLoopRunSpecific ()
#17 0x0000000111687ad2 in GSEventRunModal ()
#18 0x000000010efad30d in UIApplicationMain ()
#19 0x000000010b76c134 in main at /Users/abc/Projects/xyz/Supporting Files/main.m:14
#20 0x000000011060292d in start ()
#21 0x000000011060292d in start ()
The assembly code near the breakpoint has a reference to a string that seems to be suggesting that a NULL argument was passed to CFRelease:
0x10e667252 <+1170>: callq 0x10e653af0 ; CFAllocatorDeallocate
0x10e667257 <+1175>: cmpq %rbx, %r13
0x10e66725a <+1178>: je 0x10e667013 ; <+595>
0x10e667260 <+1184>: movq %rbx, %rdi
0x10e667263 <+1187>: callq 0x10e666dc0 ; <+0>
0x10e667268 <+1192>: jmp 0x10e667013 ; <+595>
0x10e66726d <+1197>: leaq 0x329469(%rip), %rax ; "*** CFRelease() called with NULL ***"
0x10e667274 <+1204>: movq %rax, 0x35994d(%rip) ; gCRAnnotations + 8
0x10e66727b <+1211>: int3
-> 0x10e66727c <+1212>: jmp 0x10e667282 ; <+1218>
Does anybody have any idea why this could possibly happen?
I'm using Xcode 7.1.
Thanks.
EDIT:
This is roughly what the crashing test looks like:
self.navigationController = [[UINavigationController alloc] init];
self.viewControllerMocks = #{
FixtureViewControllerKey: OCMClassMock([UIViewController class]),
// ... more UIViewController mocks
};
self.menuViewController = [[MenuViewController alloc] initWithInnerNavigationController:self.navigationController initialViewControllerKey:FixtureViewControllerKey viewControllers:self.viewControllerMocks];
(void)self.menuViewController.view;
[self simulateTapOnMenuItemWithTitle:#"Some button"];
XCTAssertEqual(self.navigationController.viewControllers[0],
self.viewControllerMocks[MenuViewControllerSomeKey]);
This is how simulateTapOnMenuItemWithTitle: is defined:
- (void)simulateTapOnMenuItemWithTitle:(NSString *)title {
UIButton *button = [self.menuViewController.view testsFindButtonWithTitle:title];
[button testsSimulateTap];
}
// Helper methods defined in a UIView category
- (UIView *)testsFindSubviewUsingBlock:(BOOL (^)(UIView *subview))block {
for (UIView *subview in self.subviews) {
if (block(subview)) {
return subview;
}
UIView *foundSubview = [subview testsFindSubviewUsingBlock:block];
if (foundSubview != nil) {
return foundSubview;
}
}
return nil;
}
- (UIButton *)testsFindButtonWithTitle:(NSString *)title {
return (UIButton *)[self testsFindSubviewUsingBlock:^BOOL(UIView *subview) {
return [subview isKindOfClass:[UIButton class]] && [((UIButton *)subview).titleLabel.text isEqualToString:title];
}];
}
I am getting this crash log (getting it from users, cannot reproduce it):
Threads
_________________________________
Thread: Unknown Name (Crashed)
0 libsystem_kernel.dylib 0x382dd1fc __pthread_kill + 8
1 libsystem_c.dylib 0x3828dffd abort + 77
2 libc++abi.dylib 0x375bccd7 abort_message + 75
3 libc++abi.dylib 0x375d320d _ZSt11__terminatePFvvE + 149
4 libc++abi.dylib 0x375d2d2d __cxa_increment_exception_refcount + 1
5 libobjc.A.dylib 0x37d1e7f7 objc_exception_rethrow + 43
6 CoreFoundation 0x2d811c9d CFRunLoopRunSpecific + 641
7 CoreFoundation 0x2d811a0b CFRunLoopRunInMode + 107
8 GraphicsServices 0x32538283 GSEventRunModal + 139
9 UIKit 0x300b5049 UIApplicationMain + 1137
10 Paok FC 0x000c6723 main (main.m:12)
Thread: Unknown Name
0 libsystem_kernel.dylib 0x382ca83c kevent64 + 24
1 libdispatch.dylib 0x3820af9b _dispatch_mgr_thread$VARIANT$mp + 39
Thread: Unknown Name
0 libsystem_kernel.dylib 0x382ddc7c __workq_kernreturn + 8
Thread: Unknown Name
0 libsystem_kernel.dylib 0x382caadc semaphore_wait_trap + 8
1 libdispatch.dylib 0x38207a17 _dispatch_barrier_sync_f_slow + 139
2 Paok FC 0x0010c369 __42-[SDImageCache queryDiskCacheForKey:done:]_block_invoke (SDImageCache.m:308)
3 libdispatch.dylib 0x38201d1b _dispatch_call_block_and_release + 11
4 libdispatch.dylib 0x38208273 _dispatch_queue_drain$VARIANT$mp + 375
5 libdispatch.dylib 0x3820806b _dispatch_queue_invoke$VARIANT$mp + 43
6 libdispatch.dylib 0x38208ce1 _dispatch_root_queue_drain + 77
7 libdispatch.dylib 0x38208f59 _dispatch_worker_thread2 + 57
8 libsystem_pthread.dylib 0x38343dbf _pthread_wqthread + 299
Thread: Unknown Name
0 libsystem_kernel.dylib 0x382caa8c mach_msg_trap + 20
1 CoreFoundation 0x2d8a87c3 __CFRunLoopServiceMachPort + 155
2 CoreFoundation 0x2d8a6ee9 __CFRunLoopRun + 785
3 CoreFoundation 0x2d811c27 CFRunLoopRunSpecific + 523
4 CoreFoundation 0x2d811a0b CFRunLoopRunInMode + 107
5 Foundation 0x2e24c2f7 +[NSURLConnection(Loader) _resourceLoadLoop:] + 319
6 Foundation 0x2e2c1c87 __NSThread__main__ + 1063
7 libsystem_pthread.dylib 0x38345c1d _pthread_body + 141
8 libsystem_pthread.dylib 0x38345b8f _pthread_start + 103
Thread: Unknown Name
0 libsystem_kernel.dylib 0x382dd440 __select + 20
1 libsystem_pthread.dylib 0x38345c1d _pthread_body + 141
2 libsystem_pthread.dylib 0x38345b8f _pthread_start + 103
Thread: Unknown Name
0 libsystem_kernel.dylib 0x382ddc7c __workq_kernreturn + 8
Thread: Unknown Name
0 libsystem_kernel.dylib 0x382ddc7c __workq_kernreturn + 8
Crashed Registers
_________________________________
r12 0x148
r10 0x190
r11 0x1559ca80
cpsr 0x10
r4 0x6
r5 0x3a15318c
r6 0x0
r7 0x27d45a60
r0 0x0
r1 0x0
r2 0x0
r3 0x2060
sp 0x27d45a54
r8 0x1558f8e0
r9 0x1
pc 0x382dd1fc
lr 0x38346a33
The method crashing in SDWebImageCache.m is this:
- (NSOperation *)queryDiskCacheForKey:(NSString *)key done:(void (^)(UIImage *image, SDImageCacheType cacheType))doneBlock
{
NSOperation *operation = NSOperation.new;
if (!doneBlock) return nil;
if (!key)
{
doneBlock(nil, SDImageCacheTypeNone);
return nil;
}
// First check the in-memory cache...
UIImage *image = [self imageFromMemoryCacheForKey:key];
if (image)
{
doneBlock(image, SDImageCacheTypeMemory);
return nil;
}
dispatch_async(self.ioQueue, ^
{
if (operation.isCancelled)
{
return;
}
#autoreleasepool
{
UIImage *diskImage = [self diskImageForKey:key];
if (diskImage)
{
CGFloat cost = diskImage.size.height * diskImage.size.width * diskImage.scale;
[self.memCache setObject:diskImage forKey:key cost:cost];
}
dispatch_main_sync_safe(^
{
doneBlock(diskImage, SDImageCacheTypeDisk);
});
}
});
return operation;
}
Has anyone experience this crash? If yes, is there a way to fix this?
Line 308 where the crash occurs is this:
dispatch_main_sync_safe(^
{
doneBlock(diskImage, SDImageCacheTypeDisk);
});
This method is called in another class from this method:
- (id<SDWebImageOperation>)downloadWithURL:(NSURL *)url options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletedWithFinishedBlock)completedBlock
{
// Invoking this method without a completedBlock is pointless
NSParameterAssert(completedBlock);
// Very common mistake is to send the URL using NSString object instead of NSURL. For some strange reason, XCode won't
// throw any warning for this type mismatch. Here we failsafe this error by allowing URLs to be passed as NSString.
if ([url isKindOfClass:NSString.class])
{
url = [NSURL URLWithString:(NSString *)url];
}
// Prevents app crashing on argument type error like sending NSNull instead of NSURL
if (![url isKindOfClass:NSURL.class])
{
url = nil;
}
__block SDWebImageCombinedOperation *operation = SDWebImageCombinedOperation.new;
__weak SDWebImageCombinedOperation *weakOperation = operation;
BOOL isFailedUrl = NO;
#synchronized(self.failedURLs)
{
isFailedUrl = [self.failedURLs containsObject:url];
}
if (!url || (!(options & SDWebImageRetryFailed) && isFailedUrl))
{
dispatch_main_sync_safe(^
{
NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorFileDoesNotExist userInfo:nil];
completedBlock(nil, error, SDImageCacheTypeNone, YES);
});
return operation;
}
#synchronized(self.runningOperations)
{
[self.runningOperations addObject:operation];
}
NSString *key = [self cacheKeyForURL:url];
operation.cacheOperation = [self.imageCache queryDiskCacheForKey:key done:^(UIImage *image, SDImageCacheType cacheType)
{
if (operation.isCancelled)
{
#synchronized(self.runningOperations)
{
[self.runningOperations removeObject:operation];
}
return;
}
if ((!image || options & SDWebImageRefreshCached) && (![self.delegate respondsToSelector:#selector(imageManager:shouldDownloadImageForURL:)] || [self.delegate imageManager:self shouldDownloadImageForURL:url]))
{
if (image && options & SDWebImageRefreshCached)
{
dispatch_main_sync_safe(^
{
// If image was found in the cache bug SDWebImageRefreshCached is provided, notify about the cached image
// AND try to re-download it in order to let a chance to NSURLCache to refresh it from server.
completedBlock(image, nil, cacheType, YES);
});
}
// download if no image or requested to refresh anyway, and download allowed by delegate
SDWebImageDownloaderOptions downloaderOptions = 0;
if (options & SDWebImageLowPriority) downloaderOptions |= SDWebImageDownloaderLowPriority;
if (options & SDWebImageProgressiveDownload) downloaderOptions |= SDWebImageDownloaderProgressiveDownload;
if (options & SDWebImageRefreshCached) downloaderOptions |= SDWebImageDownloaderUseNSURLCache;
if (options & SDWebImageContinueInBackground) downloaderOptions |= SDWebImageDownloaderContinueInBackground;
if (options & SDWebImageHandleCookies) downloaderOptions |= SDWebImageDownloaderHandleCookies;
if (image && options & SDWebImageRefreshCached)
{
// force progressive off if image already cached but forced refreshing
downloaderOptions &= ~SDWebImageDownloaderProgressiveDownload;
// ignore image read from NSURLCache if image if cached but force refreshing
downloaderOptions |= SDWebImageDownloaderIgnoreCachedResponse;
}
id<SDWebImageOperation> subOperation = [self.imageDownloader downloadImageWithURL:url options:downloaderOptions progress:progressBlock completed:^(UIImage *downloadedImage, NSData *data, NSError *error, BOOL finished)
{
if (weakOperation.isCancelled)
{
dispatch_main_sync_safe(^
{
completedBlock(nil, nil, SDImageCacheTypeNone, finished);
});
}
else if (error)
{
dispatch_main_sync_safe(^
{
completedBlock(nil, error, SDImageCacheTypeNone, finished);
});
if (error.code != NSURLErrorNotConnectedToInternet)
{
#synchronized(self.failedURLs)
{
[self.failedURLs addObject:url];
}
}
}
else
{
BOOL cacheOnDisk = !(options & SDWebImageCacheMemoryOnly);
if (options & SDWebImageRefreshCached && image && !downloadedImage)
{
// Image refresh hit the NSURLCache cache, do not call the completion block
}
// NOTE: We don't call transformDownloadedImage delegate method on animated images as most transformation code would mangle it
else if (downloadedImage && !downloadedImage.images && [self.delegate respondsToSelector:#selector(imageManager:transformDownloadedImage:withURL:)])
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^
{
UIImage *transformedImage = [self.delegate imageManager:self transformDownloadedImage:downloadedImage withURL:url];
dispatch_main_sync_safe(^
{
completedBlock(transformedImage, nil, SDImageCacheTypeNone, finished);
});
if (transformedImage && finished)
{
NSData *dataToStore = [transformedImage isEqual:downloadedImage] ? data : nil;
[self.imageCache storeImage:transformedImage imageData:dataToStore forKey:key toDisk:cacheOnDisk];
}
});
}
else
{
dispatch_main_sync_safe(^
{
completedBlock(downloadedImage, nil, SDImageCacheTypeNone, finished);
});
if (downloadedImage && finished)
{
[self.imageCache storeImage:downloadedImage imageData:data forKey:key toDisk:cacheOnDisk];
}
}
}
if (finished)
{
#synchronized(self.runningOperations)
{
[self.runningOperations removeObject:operation];
}
}
}];
operation.cancelBlock = ^{[subOperation cancel];};
}
else if (image)
{
dispatch_main_sync_safe(^
{
completedBlock(image, nil, cacheType, YES);
});
#synchronized(self.runningOperations)
{
[self.runningOperations removeObject:operation];
}
}
else
{
// Image not in cache and download disallowed by delegate
dispatch_main_sync_safe(^
{
completedBlock(nil, nil, SDImageCacheTypeNone, YES);
});
#synchronized(self.runningOperations)
{
[self.runningOperations removeObject:operation];
}
}
}];
return operation;
}
As the report says, this is related to semaphores. I found the line in question you commented
enterdispatch_main_sync_safe(^ { doneBlock(diskImage, SDImageCacheTypeDisk); });
to be exactly the one that is reported causing deadlock on SDWebImage GitHub error report [1]. If I understand correctly, this issue is already fixed, newest patch commit is 2 hours ago.
Maybe you can get that in some future release, or if you can use git, there it is..
My source:
[1] https://github.com/rs/SDWebImage/issues/507
when i run my game with the following code, my game crashes, when the player intersects with the enemy2 and i get the following error in the debug consel.
error:
*** -[CCSprite position]: message sent to deallocated instance 0xa8cabd0
code:
// Check if enemy2 is a child of the layer
if (enemy2) {
CGRect enemy2Rect = CGRectMake(
enemy2.position.x - (enemy2.contentSize.width/2),
enemy2.position.y - (enemy2.contentSize.height/2),
80,
// ERROR HAPPENS HERE Stopped at thread 1
41);
// check if player intersects the enemy
if (CGRectIntersectsRect(playerRect, enemy2Rect)) {
// check if the power up is true
if (bustEmUp == TRUE) {
enemy2Hit = TRUE;
[self unschedule:#selector(collisionDetection)];
[self removeChild:enemy2 cleanup:YES];
id delay = [CCDelayTime actionWithDuration:15];
id addEnemy = [CCCallFunc actionWithTarget:self selector:#selector(addEnemy2)];
[self runAction:[CCSequence actions:delay,addEnemy, nil]];
[self schedule:#selector(collisionDetection) interval:0.01];
} else {
// if not then collide
[self schedule:#selector(collisionAlert)];
}
}
}
heres my backtrace if it helps:
#0 0x01a83e1e in ___forwarding___ ()
#1 0x01a83ce2 in __forwarding_prep_0___ ()
#2 0x000e4fab in -[Survival collisionDetection] (self=0x12b975c0, _cmd=0x14a5e0) at Survival.m:521
#3 0x0005babb in -[CCTimer update:] (self=0x1281af50, _cmd=0x13347c, dt=0.0494979993) at CCScheduler.m:141
#4 0x00064a20 in -[CCScheduler tick:] (self=0xa8c9b70, _cmd=0x13c8fa, dt=0.0494979993) at CCScheduler.m:606
#5 0x0008d9ef in -[CCDirectorIOS drawScene] (self=0x9466d20, _cmd=0x136bdf) at CCDirectorIOS.m:152
#6 0x0008ffda in -[CCDirectorDisplayLink mainLoop:] (self=0x9466d20, _cmd=0x142bcd, sender=0x1208c2b0) at CCDirectorIOS.m:721
#7 0x005e22db in CA::Display::DisplayLink::dispatch ()
#8 0x005e21af in CA::Display::TimerDisplayLink::callback ()
#9 0x01af1966 in __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ ()
#10 0x01af1407 in __CFRunLoopDoTimer ()
#11 0x01a547c0 in __CFRunLoopRun ()
#12 0x01a53db4 in CFRunLoopRunSpecific ()
#13 0x01a53ccb in CFRunLoopRunInMode ()
#14 0x021c8879 in GSEventRunModal ()
#15 0x021c893e in GSEventRun ()
#16 0x00b63a9b in UIApplicationMain ()
#17 0x000c083f in main (argc=1, argv=0xbffff5a0) at main.m:14
heres where i initialized the enemy2:
enemy2 = [CCSprite spriteWithFile:#"SpaceShip2.png"];
enemy2.position = ccp(500,700);
[self addChild:enemy2];
enemy2 has probably been released. It would pass your if(enemy2) check because enemy2 is an address and not nil, but the object at that address has been deallocated.
I find my self out of ideas trying to get this app to work. My app uses a split view to show to lists. the "Master" list should hold a list of the user's Facebook friends. Since the app does not force you to login, if you're not logged in yet it shows "You have no friends" in the list till you've logged in. My problem is that once I've loaded all the friends and call [self.tableView reloadData] my program crashes some in there, and despite my best attempts at debugging it I can't find it. The method is
- (void)request:(FBRequest *)request didLoad:(id)result
{
if ([result isKindOfClass:[NSArray class]] && ([result count] > 0)) {
result = [result objectAtIndex:0];
}
switch (((Facebook *)[Facebook shared]).currentCall) {
case graphUserFriends:
{
_friends = [NSMutableArray array];
NSArray *resultData = [result objectForKey:#"data"];
if ([resultData count] > 0)
{
for (NSUInteger i=0; i<[resultData count] && i < 25; i++)
{
NSDictionary *friendDictionary = [resultData objectAtIndex:i];
FbFriend * f = [[[FbFriend alloc] initWithName:[friendDictionary objectForKey:#"name"] Id:[friendDictionary objectForKey:#"id"]] autorelease];
[_friends addObject:f];
}
}
[self.tableView reloadData];
break;
}
default:
break;
}
}
The whole source code (and Xcode 4 project) can be downloaded from https://skydrive.live.com/redir.aspx?cid=04b38cdd7b38bb7f&resid=4B38CDD7B38BB7F!798&parid=4B38CDD7B38BB7F!470&authkey=!API4iVva95nZFL8
Console (At Crash):
GNU gdb 6.3.50-20050815 (Apple version gdb-1708) (Mon Aug 15 16:03:10 UTC 2011)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "x86_64-apple-darwin".sharedlibrary apply-load-rules all
Attaching to process 48870.
Catchpoint 3 (throw)Pending breakpoint 1 - "objc_exception_throw" resolved
Current language: auto; currently objective-c
(gdb) bt
#0 0x0156ecf0 in objc_exception_throw ()
#1 0x013c9674 in -[__NSArrayI objectAtIndex:] ()
#2 0x00454805 in -[UITableViewDataSource tableView:heightForRowAtIndexPath:] ()
#3 0x0026427a in -[UITableViewController tableView:heightForRowAtIndexPath:] ()
#4 0x0020f548 in -[UISectionRowData refreshWithSection:tableView:tableViewRowData:] ()
#5 0x00211722 in -[UITableViewRowData numberOfRows] ()
#6 0x000c17c7 in -[UITableView noteNumberOfRowsChanged] ()
#7 0x000c12c1 in -[UITableView reloadData] ()
#8 0x0000247e in -[MasterViewController request:didLoad:] (self=0x6a491e0, _cmd=0x12e65, request=0x681e930, result=0x6824250) at /Users/CheckM8/Documents/Xcode 4/Projects/iPeople4/iPeople4/MasterViewController.m:46
#9 0x00009d36 in -[FBRequest handleResponseData:] (self=0x681e930, _cmd=0x1397a, data=0x6a76c60) at /Users/CheckM8/Documents/Xcode 4/facebook-facebook-ios-sdk-74358cd/src/FBRequest.m:261
#10 0x0000a357 in -[FBRequest connectionDidFinishLoading:] (self=0x681e930, _cmd=0xade62e, connection=0x681ec40) at /Users/CheckM8/Documents/Xcode 4/facebook-facebook-ios-sdk-74358cd/src/FBRequest.m:346
#11 0x00a29a59 in ___NSURLConnectionDidFinishLoading_block_invoke_0 ()
#12 0x00a27e94 in __65-[NSURLConnectionInternal _withConnectionAndDelegate:onlyActive:]_block_invoke_0 ()
#13 0x00a28eb7 in -[NSURLConnectionInternalConnection invokeForDelegate:] ()
#14 0x00a27e4f in -[NSURLConnectionInternal _withConnectionAndDelegate:onlyActive:] ()
#15 0x00a27fd5 in -[NSURLConnectionInternal _withActiveConnectionAndDelegate:] ()
#16 0x0096cf6a in _NSURLConnectionDidFinishLoading ()
#17 0x0398fbbd in URLConnectionClient::_clientDidFinishLoading ()
#18 0x03a5c5ea in URLConnectionClient::ClientConnectionEventQueue::processAllEventsAndConsumePayload ()
#19 0x03986298 in URLConnectionClient::processEvents ()
#20 0x03a5c16b in non-virtual thunk to URLConnectionInstanceData::multiplexerClientPerform() ()
#21 0x03986137 in MultiplexerSource::perform ()
#22 0x013b197f in __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ ()
#23 0x01314b73 in __CFRunLoopDoSources0 ()
#24 0x01314454 in __CFRunLoopRun ()
#25 0x01313db4 in CFRunLoopRunSpecific ()
#26 0x01313ccb in CFRunLoopRunInMode ()
#27 0x012c6879 in GSEventRunModal ()
#28 0x012c693e in GSEventRun ()
#29 0x00034a9b in UIApplicationMain ()
#30 0x00001d82 in main (argc=1, argv=0xbfffed64) at /Users/CheckM8/Documents/Xcode 4/Projects/iPeople4/iPeople4/main.m:16
#31 0x00001cf5 in start ()
You've made the classic memory management mistake: You're directly accessing your ivars and it burned you.
_friends = [NSMutableArray array];
This is an under-retain (which will crash later), and also a possible leak if _friends had a prior value. You should always use accessors for your ivars except in dealloc and init:
self.friends = [NSMutableArray array];
...
[self.friends addObject:f];
EDIT: From your stacktrace, your bug is in your table view data source's tableView:heightForRowAtIndexPath:. It looks like you're reading off the end of your array.