iOS Crash Log NSObject doesNotRecognizeSelector: - at which line? - ios

I have recorded a crash of my app, but the last line in my app (5 Control) points just to the method begin. How do I know in which line the problem is?
0 CoreFoundation 0x185f0af50 __exceptionPreprocess + 132
1 libobjc.A.dylib 0x1924141fc objc_exception_throw + 60
2 CoreFoundation 0x185f0fc04 -[NSObject(NSObject) doesNotRecognizeSelector:] + 220
3 CoreFoundation 0x185f0d930 ___forwarding___ + 912
4 CoreFoundation 0x185e2d5dc _CF_forwarding_prep_0 + 92
5 Control 0x10005acb4 -[PaymillPaymentService handleTransactionListRequest:] (PaymillPaymentService.m:211)
6 Foundation 0x186a7416c __103+[__NSOperationInternal _observeValueForKeyPath:ofObject:changeKind:oldValue:newValue:indexes:context:]_block_invoke96 + 28
7 libdispatch.dylib 0x1929ec014 _dispatch_call_block_and_release + 24
8 libdispatch.dylib 0x1929ebfd4 _dispatch_client_callout + 16
9 libdispatch.dylib 0x1929f32b8 _dispatch_root_queue_drain + 556
10 libdispatch.dylib 0x1929f34fc _dispatch_worker_thread2 + 76
11 libsystem_pthread.dylib 0x192b816bc _pthread_wqthread + 356
12 libsystem_pthread.dylib 0x192b8154c start_wqthread + 4
Here the [lengthy] method code. I see a couple of places where I can add the check but how to I know it for sure that I fixed the issue? The problem is sporadical and I cannot reproduce it easily.
- (void)handleTransactionListRequest:(ServiceRequest *)serviceRequest
{
LRURLRequestOperation* operation = serviceRequest.operation;
NSHTTPURLResponse *response = (NSHTTPURLResponse *)operation.URLResponse;
if (response.statusCode == 200)
{
if (operation.responseData)
{
NSError *parserError = nil;
NSDictionary *data = [NSJSONSerialization JSONObjectWithData:operation.responseData options:0 error:&parserError];
//NSLog(#"%#", data);
if (!parserError)
{
NSArray* transactions = [data objectForKey:#"data"];
if (0 == serviceRequest.currentOffset)
{
NSNumber* totalCountObj = [data objectForKey:#"data_count"];
serviceRequest.totalCount = [totalCountObj intValue];
}
int loadedCount = 0;
if (transactions)
{
for (id object in transactions)
{
TransactionInfo* info = [self createTransactionFrom:object];
[serviceRequest.transactionList addTransaction:info];
[info release];
loadedCount++;
}
}
if (loadedCount + serviceRequest.currentOffset >= serviceRequest.totalCount)
{
if ([serviceRequest.delegate respondsToSelector:#selector(transactionListLoadingComplete:)])
[serviceRequest.delegate transactionListLoadingComplete:serviceRequest];
serviceRequest.transactionList.timeStamp = [[NSDate date] timeIntervalSince1970];
NSLog(#"COMPLETE: %d transaction loaded ", serviceRequest.totalCount);
}
else
{
serviceRequest.currentOffset += loadedCount;
bool needToContinue = YES;
if ([serviceRequest.delegate respondsToSelector:#selector(transactionListLoadingContinue:)])
needToContinue = [serviceRequest.delegate transactionListLoadingContinue];
if (needToContinue)
{
[self continueRetrievingTransactionListFor:serviceRequest];
NSLog(#"CONTINUE: %d of %d loaded ", serviceRequest.currentOffset, serviceRequest.totalCount);
}
}
return; // all OK cases
}
}
}
if ([serviceRequest.delegate respondsToSelector:#selector(transactionListLoadingFailed:with:)])
[serviceRequest.delegate transactionListLoadingFailed:serviceRequest with:response.statusCode];
NSLog(#"ERROR: Loading Transactions Response Code: %ld", (long)response.statusCode);
}

Short Answer:
You are sending a message to an object that cannot validly respond to it. The stack trace is telling you that when you make the call [PaymillPaymentService handleTransactionListRequest:] that PaymillPaymentService cannot accept handleTransactionListRequest.
Long answer:
Look at the stack trace here:
5 Control 0x10005acb4 -[PaymillPaymentService handleTransactionListRequest:] (PaymillPaymentService.m:211)
This is telling you that in the file PaymillPaymentService.m on line 211 you are sending PaymillPaymentService the message handleTransactionListRequest to which it cannot validly respond. In your discussion with rmaddy, Hot Licks, and Paulc11 you mentioned that line 211 is the function entry for handleTransactionListRequest (in whatever file it resides). If that's the case it is coincidental.
If you want further follow up you need to post PaymillPaymentService.m and ensure that you include all the line numbers.

Related

Getting IPV4 address as a String

Im using Bonjour to browse for available services from specific devices. I can successfully obtain and resolve the services returned from the browse, however I would like to take the service and retrieve it's IPV4 address in String form. To do this I am using the arpa/inet library to translate the NSdata object received by the NSNetService.addresses into a String. The code below works most of the time however occasionally the line below results in the crashing of the app.
NSString *ipString = [NSString stringWithFormat: #"%s",
inet_ntoa(socketAddress->sin_addr)];
The error: EXC_BAD_ACCESS
I am sure it has to do with the way I have declared this code, any ideas?
+ (NSString *)getStringFromAddressData:(NSData *)dataIn {
struct sockaddr_in *socketAddress = nil;
socketAddress = (struct sockaddr_in *)[dataIn bytes];
NSString *ipString = [NSString stringWithFormat: #"%s", inet_ntoa(socketAddress->sin_addr)];
return ipString;
}
Stack trace:
2015-08-13 08:23:45.860 Semiphores[4664:2119558] Stack trace : (
0 Semiphores 0x0000000100001c0b +[BonjourAddressHelper getStringFromAddressData:] + 107
1 Semiphores 0x0000000100007c8a _TFFC10Semiphores17BonjourController15resolveServicesFS0_FPSs9AnyObject_T_U_FT_T_ + 2682
2 Semiphores 0x0000000100007207 _TTRXFo__dT__XFdCb__dT__ + 39
3 libdispatch.dylib 0x00000001006852bb _dispatch_call_block_and_release + 12
4 libdispatch.dylib 0x000000010067fd43 _dispatch_client_callout + 8
5 libdispatch.dylib 0x0000000100683283 _dispatch_root_queue_drain + 1471
6 libdispatch.dylib 0x0000000100694cd0 _dispatch_worker_thread3 + 106
7 libsystem_pthread.dylib 0x00007fff86770637 _pthread_wqthread + 729
8 libsystem_pthread.dylib 0x00007fff8676e40d start_wqthread + 13
)
What would happen if someone passed in nil data?
+ (NSString *)getStringFromAddressData:(NSData *)dataIn {
if (dataIn != nil) {
struct sockaddr_in *socketAddress = nil;
socketAddress = (struct sockaddr_in *)[dataIn bytes];
NSString *ipString = [NSString stringWithFormat: #"%s", inet_ntoa(socketAddress->sin_addr)];
return ipString;
}
return #"";
}

RestKit Paginator Crash: Cannot determine hasNextPage: paginator is not loaded

For some reason, I randomly sometimes get this crash.
Fatal Exception: NSInternalInconsistencyException
Cannot determine hasNextPage: paginator is not loaded.
Thread : Fatal Exception: NSInternalInconsistencyException
0 CoreFoundation 0x309a1f4b __exceptionPreprocess + 130
1 libobjc.A.dylib 0x3b1386af objc_exception_throw + 38
2 CoreFoundation 0x309a1e25 +[NSException raise:format:]
3 Foundation 0x31349fe3 -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 90
4 Poka 0x004f0f71 -[RKPaginator hasNextPage] (RKPaginator.m:151)
5 Poka 0x00289a41 __66-[PokaLocationContentManagerSingleton fetchLatestPlantsWithCount:]_block_invoke (PokaLocationContentManagerSingleton.m:345)
6 Poka 0x004f2495 __24-[RKPaginator loadPage:]_block_invoke157 (RKPaginator.m:231)
7 Poka 0x004e9355 __66-[RKObjectRequestOperation setCompletionBlockWithSuccess:failure:]_block_invoke244 (RKObjectRequestOperation.m:477)
8 libdispatch.dylib 0x3b61bd1b _dispatch_call_block_and_release + 10
9 libdispatch.dylib 0x3b61bd07 _dispatch_client_callout + 22
10 libdispatch.dylib 0x3b62278d _dispatch_main_queue_callback_4CF$VARIANT$mp + 268
11 CoreFoundation 0x3096c819 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 8
12 CoreFoundation 0x3096b0ed __CFRunLoopRun + 1300
13 CoreFoundation 0x308d5c27 CFRunLoopRunSpecific + 522
14 CoreFoundation 0x308d5a0b CFRunLoopRunInMode + 106
15 GraphicsServices 0x355c9283 GSEventRunModal + 138
16 UIKit 0x33179049 UIApplicationMain + 1136
17 Poka 0x0006df95 main (main.m:17)
18 libdyld.dylib 0x3b640ab7 start + 2
I am loading the Paginator like this:
- (void)fetchLatestPlantsWithCount:(NSNumber *)count
{
RKObjectManager *objectManager = [RKObjectManager sharedManager];
NSString *requestString = [NSString stringWithFormat:#"/api/rest/plants/?count=%#&limit=:perPage&offset=:offset", count];
NSDictionary *parameters = nil;
if(_dateFilterLastModifiedAppend)
parameters = [[NSDictionary alloc]initWithObjectsAndKeys:_dateFilterLastModifiedAppend, #"last_modified_date__gte", nil];
RKPaginator *paginator = [objectManager paginatorWithPathPattern:requestString parameters:parameters];
paginator.perPage = API_PER_PAGE_LIMIT;
[ZAActivityBar showWithStatus:[NSString stringWithFormat:NSLocalizedStringFromTable(#"Downloading latest plants: %# remaining", #"PokaLocalizable", nil), count]];
[paginator setCompletionBlockWithSuccess:^(RKPaginator *paginator, NSArray *objects, NSUInteger page) {
if([paginator hasNextPage])
{
[ZAActivityBar showWithStatus:[NSString stringWithFormat:NSLocalizedStringFromTable(#"Downloading latest plants: %# remaining", #"PokaLocalizable", nil), [NSNumber numberWithInt:([count integerValue] - paginator.offset)]]];
[paginator loadNextPage];
}
else
{
[self fetchLatestProductionLinesCount];
}
} failure:^(RKPaginator *paginator, NSError *error) {
[self fetchLatestProductionLinesCount];
}];
[paginator loadPage:1];
}
Finally, I added some code to RestKit in order to load the paginator. I don't think it is the problem though.
- (RKPaginator *)paginatorWithPathPattern:(NSString *)pathPattern parameters:(NSDictionary *)parameters
{
NSAssert(self.paginationMapping, #"Cannot instantiate a paginator when `paginationMapping` is nil.");
NSMutableURLRequest *request = [self requestWithMethod:#"GET" path:pathPattern parameters:parameters];
RKPaginator *paginator = [[RKPaginator alloc] initWithRequest:request paginationMapping:self.paginationMapping responseDescriptors:self.responseDescriptors];
#ifdef _COREDATADEFINES_H
paginator.managedObjectContext = self.managedObjectStore.mainQueueManagedObjectContext;
paginator.managedObjectCache = self.managedObjectStore.managedObjectCache;
paginator.fetchRequestBlocks = self.fetchRequestBlocks;
#endif
paginator.operationQueue = self.operationQueue;
Class HTTPOperationClass = [self requestOperationClassForRequest:request fromRegisteredClasses:self.registeredHTTPRequestOperationClasses];
if (HTTPOperationClass) [paginator setHTTPOperationClass:HTTPOperationClass];
return paginator;
}
The only difference is that I pass some parameters to it.
The thing I don't understand is that I load other objects, WITH that same code with the only difference being the type of objects I am downloading. I execute almost that same code right before executing this one, and it works perfectly fine. Hence, my question as to I am confused...
Some more information:
It says the object count is 1, that page is 1, but apparently it is not loaded?
Note that I call the paginator multiple times within the same page. I do the paginator for one type of objects... once it is done I do it for another one... and so on.
All pull requests that I mentioned before were merged already to master. So just use the newest version.
I found an issue and fixed it if you are interested. I posted Pull Request on RestKit github page
https://github.com/RestKit/RestKit/pull/2156
I would recommend to use my fork on branch inventorum where I also cherry picked malloc error fix:
https://github.com/bimusiek/RestKit/commits/inventorum

Getting CocoaLibSpotify error in SPPlaylist.m

When I try to build my project i get the following error on line 827
/PATH_TO_PROJECT/Libs/CocoaLibSpotify/Model/SPPlaylist.m:827:25: Implicit conversion of Objective-C pointer type 'AVAssetTrack *' to C pointer type 'sp_track *' (aka 'struct sp_track *') requires a bridged cast
Here is the code where the error occurs:
805 -(void)addItems:(NSArray *)newItems atIndex:(NSUInteger)index callback:(SPErrorableOperationCallback)block {
806
807 SPDispatchAsync(^{
808
809 if (newItems.count == 0) {
810 dispatch_async(dispatch_get_main_queue(), ^{
811 if (block) block([NSError spotifyErrorWithCode:SP_ERROR_INVALID_INDATA]);
812 });
813 return;
814 }
815
816 sp_track **tracks = malloc(sizeof(sp_track *) * newItems.count);
817
818 // libSpotify iterates through the array and inserts each track at the given index,
819 // which ends up reversing the expected order. Defeat this by constructing a backwards
820 // array.
821 for (int currentTrack = (int)newItems.count - 1; currentTrack >= 0; currentTrack--) {
822
823 sp_track *track;
824 id item = [newItems objectAtIndex:currentTrack];
825
826 if ([item isKindOfClass:[SPTrack class]])
827 track = [item track];
828 else
829 track = [(SPTrack *)((SPPlaylistItem *)item).item track];
830
831 tracks[currentTrack] = track;
832 }
833 sp_track *const *trackPointer = tracks;
834
835 if (block)
836 [self.addCallbackStack addObject:block];
837
838 sp_error errorCode = sp_playlist_add_tracks(self.playlist, trackPointer, (int)newItems.count, (int)index, self.session.session);
839 free(tracks);
840 tracks = NULL;
841
842 NSError *error = nil;
843 if (errorCode != SP_ERROR_OK)
844 error = [NSError spotifyErrorWithCode:errorCode];
845
846 if (error && block) {
847 [self.addCallbackStack removeObject:block];
848 dispatch_async(dispatch_get_main_queue(), ^{ block(error); });
849 }
850 });
851 }
Thanks for your help!
The error is pretty self-explanatory - you need to make a bridged cast.
track = (__bridge sp_track *)[item track];
or
track = [(SPPlaylistItem *)item track];

SIGABRT crash because of SDWebImageCache

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

Why my [UIScrollView removeFromSuperview] is crashing?

The crash log is below.
Do you know any particular reason why might [UIScrollView removeFromSuperview] can crash? The scrollview contains view hierarchy with different types of UIViews. I also finds that the ad hoc version crash often not the debug version. I could not find any reason for that.
Same viewcontroller is loaded in a different flow in iPhone that works fine. But in iPad it crashes.
In iPad, in a container view controller, only viewcontroler.view is loaded.
Incident Identifier: EE102239-34D1-4BE7-8B52-41F74AB26203
CrashReporter Key: 2b11ea2a01ac5618e199ffc5a1e1f321600bb6a9
Hardware Model: iPad3,4
Version: ??? (???)
Code Type: ARM (Native)
Parent Process: launchd [1]
Date/Time: 2013-06-18 15:19:16.132 +0200
OS Version: iOS 6.1.3 (10B329)
Report Version: 104
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x00000000
Crashed Thread: 0
Thread 0 name: Dispatch queue: com.apple.main-thread
Thread 0 Crashed:
0 libobjc.A.dylib 0x3bab7070 prepareForMethodLookup + 20
1 libobjc.A.dylib 0x3bab6fb2 lookUpMethod + 42
2 libobjc.A.dylib 0x3bab6f7e _class_lookupMethodAndLoadCache3 + 14
3 libobjc.A.dylib 0x3bab6638 objc_msgSend_uncached + 24
4 QuartzCore 0x357f2a72 CA::Layer::contents_visibility_changed(CA::Transaction*, bool) + 50
5 QuartzCore 0x357f29de CA::Layer::mark_visible(CA::Transaction*, bool) + 190
6 QuartzCore 0x357f29b2 CA::Layer::mark_visible(CA::Transaction*, bool) + 146
7 QuartzCore 0x357f29b2 CA::Layer::mark_visible(CA::Transaction*, bool) + 146
8 QuartzCore 0x357f29b2 CA::Layer::mark_visible(CA::Transaction*, bool) + 146
9 QuartzCore 0x357f29b2 CA::Layer::mark_visible(CA::Transaction*, bool) + 146
10 QuartzCore 0x357f28d2 CA::Layer::update_removed_sublayer(CA::Transaction*, unsigned int) + 18
11 QuartzCore 0x357f255a CA::Layer::remove_sublayer(CA::Transaction*, CALayer*) + 130
12 QuartzCore 0x357f246a CA::Layer::remove_from_superlayer() + 34
13 UIKit 0x35a6e92c -[UIView(Hierarchy) removeFromSuperview] + 144
14 UIKit 0x35b857bc -[UIScrollView removeFromSuperview] + 60
15 MyApp 0x000bde8a -[iPadNavigationController vcAnimationDone] (iPadNavigationController.m:400)
16 UIKit 0x35a55ab6 -[UIViewAnimationState sendDelegateAnimationDidStop:finished:] + 154
17 UIKit 0x35aca8f8 -[UIViewAnimationState animationDidStop:finished:] + 44
18 QuartzCore 0x35801304 CA::Layer::run_animation_callbacks(void*) + 204
19 libdispatch.dylib 0x3bed55d8 _dispatch_client_callout + 20
20 libdispatch.dylib 0x3bed8e40 _dispatch_main_queue_callback_4CF + 224
21 CoreFoundation 0x33c051ac __CFRunLoopRun + 1284
22 CoreFoundation 0x33b78238 CFRunLoopRunSpecific + 352
23 CoreFoundation 0x33b780c4 CFRunLoopRunInMode + 100
24 GraphicsServices 0x37733336 GSEventRunModal + 70
25 UIKit 0x35a942b4 UIApplicationMain + 1116
A few line from the code (as asked),
previous = showing;
showing = [ vc retain ];
showing.view.frame = startFrameIn;
[ container addSubview:showing.view ];
CGContextRef context = UIGraphicsGetCurrentContext();
[ UIView beginAnimations:nil context:context ];
[ UIView setAnimationDelegate:self ];
[ UIView setAnimationDidStopSelector:#selector(vcAnimationDone) ];
[ UIView setAnimationCurve:UIViewAnimationCurveEaseOut ];
[ UIView setAnimationDuration:0.4 ];
previous.view.frame = endFrameOut;
showing.view.frame = detailFrame;
[ UIView commitAnimations ];
}
- (void) vcAnimationDone {
if ( previous != nil ) {
if (previous.view.superview != nil) {
[previous.view removeFromSuperview];
}
[ previous release ];
previous = nil;
}
A very probable reason is that you are overreleasing your scrollview or one of the views inside it.
Calling removeFromSuperview then deallocates the view instead of simply decreasing the retain count.
Actually, if you are still stuck with non-ARC project, Static Code Analysis is very useful for this kind of bug. Retain/release balancing issues are hard to pin down, and nearly impossible with incomplete method so I suggest you post the full method body if possible.
Thanks everyone for your answers, tips and tricks. However one thing I want share with you is the cause of the crash. I found that the crash was at different thread in different times. I had several views loaded with button pressing/menu in my iPad app. Some of the button pressing fetch data from web service. So I was bit confused to get the cuase of crash, animation, or url connection etc... I tried with enabled NSZombie objects, but it did not show any information.
Then I tried with Guard Malloc. This only runs in Simulator. And magically I found the code point of crash. I have function to convert a hex string into data. There I have line of code to make a C string null terminated. where I assigned 0 at the last index. and that makes the crash!
tmpCh[count] = 0;
I do not why, but probably it takes some time in the memory management procedure in iOS so it crash at different thread at different times. But with Guard malloc in Simulator, it always point out here and when I rewrite the code, the crash is gone.
/* Converts a hex string to bytes.
Precondition:
. The hex string can be separated by space or not.
. the string length without space or 0x, must be even. 2 symbols for one byte/char
. sample input: 23 3A F1 OR 233AF1
*/
+ (NSData *) dataFromHexString:(NSString*)hexString
{
if (hexString.length < 1) {
return nil;
}
char * tmpCh = (char *) malloc([hexString length] * sizeof(char));
int count = 0;
for (int k=0; k<hexString.length;k++) {
char c = [hexString characterAtIndex:k];
if (c == (char)0x20) { //skip space
continue;
}
if (c == '0') { // skip 0x
if(k+1 < hexString.length){
if ([hexString characterAtIndex:k+1] == 'x'
|| [hexString characterAtIndex:k+1] == 'X' )
{
k = k + 1;
continue;
}
}
}
tmpCh[count] = c;
count++;
}
tmpCh[count] = 0; // make null terminated string
if (count % 2) {
return nil;
}
NSString *temp = [[NSString alloc] initWithUTF8String:tmpCh];
free(tmpCh);
if ([temp length] % 2 != 0) {
return nil;
}
NSMutableData *result = [[NSMutableData alloc] init];
unsigned char byte;
char hexChars[3] = {0};
for (int i=0; i < (temp.length/2); i++) {
hexChars[0] = [temp characterAtIndex:i*2];
hexChars[1] = [temp characterAtIndex:i*2+1];
if (![Util isValidChar:hexChars[0]] || ![Util isValidChar:hexChars[1]]) {
return nil;
}
byte = strtol(hexChars, NULL, 16);
[result appendBytes:&byte length:1];
}
NSData * data = [NSData dataWithData:result];
[result release];
return data;
}

Resources