Getting CocoaLibSpotify error in SPPlaylist.m - ios

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];

Related

UIDocument saveToUrl Delayed Crash

I have a Core Data app that's been running fine for over 4 years. Last week I updated XCode to version 8.2.1 (can't remember what I was running before this, but it had been months since I updated it).
After updating, I'm now getting a crash that I can't track down. There's a delay between doing something in the app, and getting the crash to occur. I have attempted to setup global breakpoints to gain more information, but nothing specific is shown that I can tell.
I don't explicitly spawn any threads myself.
When my app first launches, in the viewDidLoad of my initial viewController I do this:
- (void)viewDidLoad
{
[super viewDidLoad];
NSFileManager* fileManager = [NSFileManager defaultManager];
NSURL* ubiquitousURL = [fileManager URLForUbiquityContainerIdentifier:nil];
NSDictionary* localOptions = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES],
NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES],
NSInferMappingModelAutomaticallyOption,
nil];
NSURL* localURL = [fileManager URLForDirectory:NSDocumentDirectory
inDomain:NSUserDomainMask
appropriateForURL:nil
create:NO
error:nil];
NSURL* localCoreDataURL = [localURL URLByAppendingPathComponent:#"MyData"];
self.database = [[UIManagedDocument alloc] initWithFileURL:localCoreDataURL];
self.database.persistentStoreOptions = localOptions;
if( [fileManager fileExistsAtPath:[localCoreDataURL path]] )
{
[self.database openWithCompletionHandler: ^(BOOL success) {
//log statement
}];
}
else
{
NSFileCoordinator* coordinator = [[NSFileCoordinator alloc] initWithFilePresenter:nil];
[coordinator coordinateWritingItemAtURL:ubiquitousURL
options:NSFileCoordinatorWritingForDeleting
error:nil
byAccessor:^(NSURL *newURL) {
[[NSFileManager defaultManager] removeItemAtURL:newURL error:nil];
}];
[self.database saveToURL:localCoreDataURL
forSaveOperation:UIDocumentSaveForCreating
completionHandler:^(BOOL success) {
//log statement
}];
}
}
Later in the app, I allow the user to create some data and save it (create a new entity), like this:
NSManagedObjectContext* context = database.managedObjectContext;
NSError* error = nil;
if( ![context save:&error])
{
[AppUtility printNsError:error];
[NSException raise:NSInternalInconsistencyException format:#"An error occurred when saving context: %#",[error localizedDescription]];
}
else
{
if (![[context parentContext] save:&error])
{
NSLog(#"Error Saving Parent Data %#, %#", error, [error userInfo]);
}
}
The app will then run for 15 to 20 seconds, then suddenly crash. There is an error in the log that says
[NSError retain]: message sent to deallocated instance 0x608000443b10
And the output in the debug navigator looks like this:
Thread 1 Queue: com.apple.main-thread
0 __forwarding__
1 _forwarding_prep_0__
2 -[UIDocument saveToURL:forSaveOperation:completionHandler:
3 __55-[UIDocument _saveUnsavedChangesWithCompletionHandler:)_block_invoke_2
4 _dispatch_call_block_and_release
5 _dispatch_client_callout ()
6 _dispatch_main_queue_callback_4CF
7 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__
8 __CFRunLoopRun
9 CFRunLoopRunSpecific
10 GSEventRunModal
11 UIApplicationMain
12 main
13 start
14 start
Enqueued from UIDocument File Access (Thread 5)
0 _dispatch_queue_push
1 __55-[UIDocument _saveUnsavedChangesWithCompletionHandler:]_block_invoke
2 _dispatch_call_block_and_release
...
Equeued from com.apple.main-thread (Thread 1)
0 _dispatch_queue_push
1 -[UIDocument _saveUnsavedChangesWithCompletionHandler:]
2 -[UIDocument _autosaveWithCompletionHandler:]
3 +[UIDocument _autosavingTimerDidFireSoContinue:]
4 __NSFireTimer ()
5 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__
...
In an attempt to get more information, I enabled Zombie settings, then ran this in XCode:
command script import lldb.macosx.heap
malloc_info --stack-history *memory address*
The output of that didn't seem to point to a specific line in my app:
(lldb) malloc_info --stack-history 0x60820f611fd0
0x000060820f611fd0: malloc( 48) -> 0x60820f611fd0
_NSZombie_NSError stack[0]: addr = 0x60820f611fd0, type=malloc, frames:
[0] 0x000000010ffcb130 libsystem_malloc.dylib`calloc + 30
[1] 0x000000010ea45458 libobjc.A.dylib`class_createInstance + 85
[2] 0x000000010ea4fd55 libobjc.A.dylib`_objc_rootAlloc + 42
[3] 0x000000010de1f19b Foundation`+[NSError errorWithDomain:code:userInfo:] + 37
[4] 0x000000010c1a4a3c CoreData`-[NSPropertyDescription(_NSInternalMethods) _nonPredicateValidateValue:forKey:inObject:error:] + 124
[5] 0x000000010c1a4bc0 CoreData`-[NSRelationshipDescription(_NSInternalMethods) _nonPredicateValidateValue:forKey:inObject:error:] + 80
[6] 0x000000010c1a3b40 CoreData`-[NSManagedObject(_NSInternalMethods) _validateValue:forProperty:andKey:withIndex:error:] + 384
[7] 0x000000010c1a3896 CoreData`-[NSManagedObject(_NSInternalMethods) _validatePropertiesWithError:] + 358
[8] 0x000000010c1a36f7 CoreData`-[NSManagedObject(_NSInternalMethods) _validateForSave:] + 119
[9] 0x000000010c1b3d4c CoreData`-[NSManagedObject validateForInsert:] + 76
[10] 0x000000010c1a2a77 CoreData`-[NSManagedObjectContext(_NSInternalAdditions) _validateObjects:forOperation:error:exhaustive:forSave:] + 1783
[11] 0x000000010c1a2202 CoreData`-[NSManagedObjectContext(_NSInternalAdditions) _validateChangesForSave:] + 146
[12] 0x000000010c1a1f56 CoreData`-[NSManagedObjectContext(_NSInternalChangeProcessing) _prepareForPushChanges:] + 214
[13] 0x000000010c19e972 CoreData`-[NSManagedObjectContext save:] + 562
[14] 0x000000010ce26a9d UIKit`__43-[UIManagedDocument contentsForType:error:]_block_invoke + 30
[15] 0x000000010c1b89a7 CoreData`developerSubmittedBlockToNSManagedObjectContextPerform + 199
[16] 0x000000010c1b885f CoreData`-[NSManagedObjectContext performBlockAndWait:] + 255
[17] 0x000000010ce269f0 UIKit`-[UIManagedDocument contentsForType:error:] + 258
[18] 0x000000010cd9477c UIKit`-[UIDocument saveToURL:forSaveOperation:completionHandler:] + 486
[19] 0x000000010cd962b2 UIKit`__55-[UIDocument _saveUnsavedChangesWithCompletionHandler:]_block_invoke_2 + 156
[20] 0x000000010fd77978 libdispatch.dylib`_dispatch_call_block_and_release + 12
[21] 0x000000010fda10cd libdispatch.dylib`_dispatch_client_callout + 8
[22] 0x000000010fd818a4 libdispatch.dylib`_dispatch_main_queue_callback_4CF + 406
[23] 0x000000010ef9de49 CoreFoundation`__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 9
[24] 0x000000010ef6337d CoreFoundation`__CFRunLoopRun + 2205
[25] 0x000000010ef62884 CoreFoundation`CFRunLoopRunSpecific + 420
[26] 0x00000001115dfa6f GraphicsServices`GSEventRunModal + 161
[27] 0x000000010c5a1c68 UIKit`UIApplicationMain + 159
[28] 0x000000010bac23bf MyApp`main + 111 at main.m:16:9
[29] 0x000000010fded68d libdyld.dylib`start + 1
[30] 0x0000000110153001 libsystem_pthread.dylib`_thread + 1
Can someone help me diagnose this?

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 #"";
}

iOS Crash Log NSObject doesNotRecognizeSelector: - at which line?

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.

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