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

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

Related

Crashlytics Crash with NSOperationQueue (QOS: UNSPECIFIED)

I'm getting a crash, reported in Crashlytics, and I have no idea how to reproduce the error, It happens randomly so it's hard to debug it with Xcode. Any ideas?
Crashed: NSOperationQueue 0x280419200 (QOS: UNSPECIFIED)
0 libobjc.A.dylib 0x22c471430 objc_retain + 16
1 CoreFoundation 0x22d2b5888 __CFBasicHashAddValue + 1480
2 CoreFoundation 0x22d1e64ac CFDictionarySetValue + 260
3 Foundation 0x22dd04888 _encodeObject + 732
4 myAPI 0x1062b44b0 -[DataCore encodeWithCoder:] (DataCore.m:236)
5 myAPI 0x1062909c4 -[DataHandle encodeWithCoder:] (DataHandle.m:53)
6 Foundation 0x22dd04aa8 _encodeObject + 1276
7 Foundation 0x22dc69c6c +[NSKeyedArchiver archivedDataWithRootObject:] + 168
8 myAPI 0x106288a34 __77+[CachableObject addObjectToCache:withCacheName:withTTL:withCompletionBlock:]_block_invoke (CachableObject.m:162)
9 Foundation 0x22dd198bc NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK + 16
10 Foundation 0x22dc21ab8 -[NSBlockOperation main] + 72
11 Foundation 0x22dc20f8c -[__NSOperationInternal _start:] + 740
12 Foundation 0x22dd1b790 __NSOQSchedule_f + 272
13 libdispatch.dylib 0x22ccc16c8 _dispatch_call_block_and_release + 24
14 libdispatch.dylib 0x22ccc2484 _dispatch_client_callout + 16
15 libdispatch.dylib 0x22cc6582c _dispatch_continuation_pop$VARIANT$mp + 412
16 libdispatch.dylib 0x22cc64ef4 _dispatch_async_redirect_invoke + 600
17 libdispatch.dylib 0x22cc71a18 _dispatch_root_queue_drain + 376
18 libdispatch.dylib 0x22cc722c0 _dispatch_worker_thread2 + 128
19 libsystem_pthread.dylib 0x22cea517c _pthread_wqthread + 472
20 libsystem_pthread.dylib 0x22cea7cec start_wqthread + 4
Here is what the code in DataCore.m looks like
- (void)encodeWithCoder:(NSCoder *)coder {
[super encodeWithCoder:coder];
[coder encodeObject:programFormatPlayInfo forKey:#"ProgramFormatPlayInfo"];
[coder encodeObject:bigScreenPlayInfo forKey:#"BigScreenPlayInfo"];
[coder encodeObject:pivotHandle forKey:#"PivotHandle"];
[coder encodeInteger:pivotDataLinkId forKey:#"PivotDataLinkId"];
[coder encodeInteger:viewContextId forKey:#"ViewContextId"];
[coder encodeBool:suppressImagePivot forKey:#"SuppressImagePivot"];
[coder encodeObject:attributeIds forKey:#"AttributeIds"];
[coder encodeObject:self.overflow forKey:#"Overflow"];
[coder encodeObject:self.cacheNameWithUser forKey:#"CacheNameWithUser"];
[coder encodeObject:self.metaData forKey:#"Metadata"];
}
and here is where I try to add an object to the cache,
not sure if it's failing to decode or something related to the background queue.
+ (void)addObjectToCache:(CachableObject*)object withCacheName:(NSString*)cacheName withTTL:(CacheTime)cacheTimeSeconds withCompletionBlock:(void(^)()) block {
CachableObject* theObject = object;
[_backgroundQueue addOperationWithBlock:^{
#autoreleasepool {
#try {
NSString * path = [CachableObject pathForCachedObject:cacheName];
NSDate * date = [NSDate date];
[object setCacheDate:date];
[object setTtlSeconds:[NSNumber numberWithInteger:cacheTimeSeconds]];
[object setApiVersion:APIVERSION];
// Add to NSCache
[[CachableObject objectCache] setObject:theObject forKey:cacheName];
// Add to file system
NSError* err = nil;
NSData * data = [NSKeyedArchiver archivedDataWithRootObject:theObject];
if (data) {
[data writeToFile:path options:NSDataWritingAtomic error:&err];
}
// Add to dynamic cache
unwrapObjectAndComplyWithClass(object, [DataHandle class], ^(id unwrappedObject) {
DataHandle *objectUnwrapped = unwrappedObject;
DataFrame *objectFrame = objectUnwrapped.frame;
for (NSString *eachDependencyName in objectFrame.dependencies) {
[[VVIDynamicCacheManager sharedManager]addDependencyToStore:eachDependencyName withCacheName:cacheName];
}
}, ^{
/*Not a data handle*/
});
} #catch (NSException* ex) {
NSLog(#"CachableObject: got an exception %#", ex);
} #finally {
if (block) {
block();
}
}
}
}];
}
Some thoughts here.
First, you're using #try/#catch. I believe that NSKeyedArchiver throws exceptions when it should actually return NSError objects. So, perhaps that's why you are doing it. But, you have to keep in mind that none of Apple's frameworks are guaranteed to be exception-safe. This means that catching exceptions can leave Apple's code (and, of course, your own) in inconsistent states that will prevent it from working correctly in the future.
I would strongly recommend either removing the #catch, or scoping it extremely tightly around the NSKeyedArchiver code, if that's why you are using it. This could be unintentionally introducing a variety of other bugs into your app.
Now, on to the specific crash. It's occurring in the runtime's memory management code. This points very strongly at heap corruption. This means you've got a pointer that doesn't point to a valid Objective-C object in memory. This can happen for many reasons, and is extremely common. The most common cause is known as a dangling pointer. However, it could also be caused by an over-release. And, I wouldn't be at all surprised if it is possible to use an #catch to trigger an over-release. (I know, I'm harping, but I've seen so many issues caused by this pattern)
What I generally recommend in these situations:
Look for other crashes that look heap-corruption-related
Try out Zombies in Instruments
Try malloc scribble, or guardmalloc, two other good memory debugging tools
It's hard, and often even impossible, to reason about heap corruption. Replicating the bug can also be impossible, as memory corruption is typically not deterministic.
So, just try to find and fix as many issues as you can. It's totally possible that one of them is responsible for a variety of crashes, one of which could be this one.

I don't understand this iOS stack trace from BugSense/Mint... where is my code actually crashing at?

My app here is named Movies. I am using Splunk Mint (formerly BugSense) to capture crash reports. I recently updated to their new 4.0 SDK. Here is a crash report today that I don't understand. At what line exactly is the crash happening in my code?
Crash is: NSInvalidArgumentException *** -[NSPlaceholderString initWithString:]: nil argument
You would think line #4? But I have no idea what the heck URLBlackListManager is. Or is it line #0, a crash inside of MKSKProduct (the code I've been using for years to make in-app purchases easy), but then why would it say it's coming from CoreFoundation? Or is it line #10, the last line that Movies actually gets called with my code?
And I have NO clue what SplunkNSURLConnectionSendSynchronousRequestReturningResponseError is and their website doesn't have any info on it.
I have been unable to report the crash, but it's happened at least 10 times on different devices for different people.
I'm a bit confused... anyone have any ideas?
0 CoreFoundation -[MKSKProduct verifyReceiptOnComplete:onError:] (in Movies) (MKSKProduct.m:196) + 868307
1 libobjc.A.dylib _mh_execute_header (in Movies) + 15567
2 CoreFoundation -[MKSKProduct verifyReceiptOnComplete:onError:] (in Movies) (MKSKProduct.m:190) + 868117
3 Foundation -[CollectionViewController collectionView:didSelectItemAtIndexPath:] (in Movies) (CollectionViewController.m:227) + 154361
4 Movies -[URLBlackListManager containsURL:] (in Movies) + 129
5 Movies SplunkNSURLConnectionSendSynchronousRequestReturningResponseError (in Movies) + 453
6 Foundation -[SettingsViewController tableView:didSelectRowAtIndexPath:] (in Movies) (SettingsViewController.m:278) + 292459
7 Foundation -[SettingsViewController tableView:didSelectRowAtIndexPath:] (in Movies) (SettingsViewController.m:270) + 292251
8 Foundation +[MKSKProduct connection:didFailWithError:] (in Movies) (MKSKProduct.m:299)
9 Movies -[iPhoneRSS initWithURL:andItemName:] (in Movies) (iPhoneRSS.m:39) + 871897
10 Movies -[CreateUsernameViewController submit:] (in Movies) (CreateUsernameViewController.m:123) + 572531
11 UIKit -[ImportViewController setUrlTextField:] (in Movies) (ImportViewController.m:34) + 262231
12 UIKit -[ImportViewController setInstructionsLabel:] (in Movies) (ImportViewController.m:32) + 262135
13 UIKit -[ImportViewController instructionsLabel] (in Movies) (ImportViewController.m:32) + 262097
14 UIKit __43-[CollectorsAdViewController openAppStore:]_block_invoke (in Movies) (CollectorsAdViewController.m:279) + 177975
15 UIKit -[ImportViewController ebaySearchWithCountry:andBarcode:] (in Movies) (ImportViewController.m:2464) + 260687
16 UIKit -[ImportViewController ebaySearchWithCountry:andBarcode:] (in Movies) (ImportViewController.m:2427) + 259873
17 UIKit -[ImportViewController importCollectorzData:] (in Movies) (ImportViewController.m:1488) + 239339
18 UIKit -[WishlistViewController tableView:commitEditingStyle:forRowAtIndexPath:] (in Movies) (WishlistViewController.m:1187) + 63725
19 UIKit -[WishlistViewController tableView:cellForRowAtIndexPath:] (in Movies) (WishlistViewController.m:929) + 57239
20 CoreFoundation -[MainViewController optionsTouched:] (in Movies) (MainViewController.m:687) + 651867
21 CoreFoundation -[MainViewController startActivityIndicator] (in Movies) (CGGeometry.h:294) + 649003
22 CoreFoundation -[MainViewController loadUp] (in Movies) (MainViewController.m:405) + 642847
23 CoreFoundation -[WishlistViewController themeSetup] (in Movies) (WishlistViewController.m:224) + 32527
24 CoreFoundation -[WishlistViewController loadDataOffline] (in Movies) (WishlistViewController.m:214) + 31987
25 GraphicsServices -[WishlistViewController loadUp] (in Movies) (WishlistViewController.m:412) + 38499
26 UIKit -[EditImageViewController viewWillAppear:] (in Movies) (EditImageViewController.m:102) + 450925
27 Movies main (in Movies) (main.m:16) + 891191
28 libdyld.dylib _mh_execute_header (in Movies) + 6839
Here's the verifyReceiptOnComplete code by the way from line #0 in the stack trace... let me know if you see any possible way to get a nil NSString crash anywhere here:
- (void) verifyReceiptOnComplete:(void (^)(void)) completionBlock
onError:(void (^)(NSError*)) errorBlock
{
self.onReceiptVerificationSucceeded = completionBlock;
self.onReceiptVerificationFailed = errorBlock;
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"%#/%#", OWN_SERVER, #"verifyProduct.php"]];
NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:url
cachePolicy:NSURLRequestReloadIgnoringCacheData
timeoutInterval:60];
[theRequest setHTTPMethod:#"POST"];
[theRequest setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
NSString *receiptDataString = [self.receipt base64EncodedString];
NSString *postData = [NSString stringWithFormat:#"receiptdata=%#", receiptDataString];
NSString *length = [NSString stringWithFormat:#"%d", [postData length]];
[theRequest setValue:length forHTTPHeaderField:#"Content-Length"];
[theRequest setHTTPBody:[postData dataUsingEncoding:NSASCIIStringEncoding]];
self.theConnection = [NSURLConnection connectionWithRequest:theRequest delegate:self];
[self.theConnection start];
}
Just stumbled upon this bug myself and here is what I found:
If you use Cocoapods to install Splunk Mint Express, you get two different Pods:
$> pod search Splunk
-> SplunkMint (4.0.4)
Usage, performance and crash monitoring for your iOS apps
pod 'SplunkMint', '~> 4.0.4'
- Homepage: https://mint.splunk.com/
- Source: download.splunk.com/misc/mint/SplunkMint-iOS.framework.zip
- Versions: 4.0.4, 4.0.3, 4.0.2, 4.0.1 [master repo]
-> SplunkMint-iOS (4.0.21)
Usage, performance and crash monitoring for your iOS apps
pod 'SplunkMint-iOS', '~> 4.0.21'
- Homepage: https://mint.splunk.com/
- Source: download.splunk.com/misc/mint/SplunkMint-iOS.framework.4.0.21.zip
- Versions: 4.0.21, 4.0.17, 4.0.1 [master repo]
When I was using SplunkMint I had the same crash but switching to SplunkMint-iOS fixed it. I don't know what the differences are between the two Pods (I didn't even have to change my code initializing Mint) but I filed a bug to Splunk to let them know about it.
I will edit my post if I find something else,
Hope this will help,
Update: Splunk Mint (formerly BugSense) is investigating. They said there may be a bug and that is why you can see SplunkNSURLConnectionSendSynchronousRequestReturningResponseError and URLBlackListManager in there. I'll edit in what they ultimately have to say.

Deleting orphaned objects from relationship

I am attempting to use the addFetchRequestBlock method to remove orphaned objects from an API call I'm making. However, the objects I'd like it to remove are the objects from various relationships to the main object.
The outermost object is the Day object which has many FoodEntry objects.
API call to /nutrition/days/2014-07-14
RKManagedObjectRequestOperation *operation = [[RKObjectManager sharedManager] appropriateObjectRequestOperationWithObject:nil method:RKRequestMethodGET path:[NSString stringWithFormat:#"nutrition/days/%#", dateFormatted] parameters:nil];
[operation setDeletesOrphanedObjects:YES];
[operation setCompletionBlockWithSuccess:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
self.day = (Day *)mappingResult.firstObject;
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
failure([operation decodeErrors]);
}];
[RKObjectManager.sharedManager enqueueObjectRequestOperation:operation];
results in:
{
"day": {
"date": "2014-07-24",
"food_entries": [
{
"id": "53d14b973861330009de0300",
"consumed_on": "2014-07-24",
"food_id": 36394,
"serving_id": 34187,
"quantity": 1,
"name": "Waffle",
"brand": null,
"description": "1 cup slices",
"meal_type": "breakfast",
"calories": 25,
"carbohydrate": 6.68,
"protein": 0.48,
"fat": 0.04,
"saturated_fat": null,
"polyunsaturated_fat": null,
"monounsaturated_fat": null,
"trans_fat": null,
"cholesterol": 0,
"sodium": 9,
"potassium": 43,
"fiber": null,
"sugar": null
},
{
"id": "53d151c138313800099c0100",
"consumed_on": "2014-07-24",
"food_id": 38720,
"serving_id": 48329,
"quantity": 0.5,
"name": "Australian Lamb Leg (Sirloin Chops, Boneless, Trimmed to 1/8\" Fat)",
"brand": null,
"description": "1 lb",
"meal_type": "breakfast",
"calories": 471.5,
"carbohydrate": 0,
"protein": 41.57,
"fat": 32.615,
"saturated_fat": 15.6445,
"polyunsaturated_fat": 1.472,
"monounsaturated_fat": 13.3315,
"trans_fat": null,
"cholesterol": 149.5,
"sodium": 134,
"potassium": 698.5,
"fiber": null,
"sugar": null
}]
}
}
The fetch request block I'm using is as follows:
[[RKObjectManager sharedManager] addFetchRequestBlock:^NSFetchRequest *(NSURL *URL) {
RKPathMatcher *pathMatcher = [RKPathMatcher pathMatcherWithPattern:#"nutrition/days/:date"];
NSDictionary *argsDict = nil;
BOOL match = [pathMatcher matchesPath:[URL relativePath] tokenizeQueryStrings:NO parsedArguments:&argsDict];
NSDate *date;
if (match) {
date = [[[RDFormatters sharedManager] dashFormatUTC] dateFromString:[argsDict objectForKey:#"date"]];
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:#"FoodEntry"];
fetchRequest.predicate = [NSPredicate predicateWithFormat:#"day.date = %#", date];
return fetchRequest;
}
return nil;
}];
This FetchRequest returns all the FoodEntries associated with the day call, however, I do not think I'm performing the call correctly. I realize this because
It crashes (duh!)
The response of the API call is usually a Day object, but after performing the FetchRequest it becomes a FoodEntry object – the very same FoodEntry object I'm attempting to delete.
Is there a way to delete orphaned objects in relationships via Restkit? What's the proper method for this?
================================
Here is the crash log
2014-07-25 08:38:18.158 Euco[6918:60b] I restkit.network:RKObjectRequestOperation.m:180 GET 'https://example.com/api/v1/nutrition/days/2014-07-24'
2014-07-25 08:38:18.831 Euco[6918:f03] I restkit.network:RKObjectRequestOperation.m:250 GET 'https://example.com/api/v1/nutrition/days/2014-07-24' (200 OK / 4 objects) [request=0.6671s mapping=0.0053s total=0.6881s]
2014-07-25 08:38:18.831 Euco[6918:60b] -[FoodEntry nutrition_plan]: unrecognized selector sent to instance 0x10ab5ff20
(lldb) po self.day
<FoodEntry: 0x10ab5ff20> (entity: FoodEntry; id: 0xd000000000040012 <x-coredata://1CAD1FBC-F8EE-4A9C-A1B4-7DCDF2A5F1D7/FoodEntry/p1> ; data: <fault>)
2014-07-25 08:38:58.103 Euco[6918:60b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[FoodEntry nutrition_plan]: unrecognized selector sent to instance 0x10ab5ff20'
*** First throw call stack:
(
0 CoreFoundation 0x00000001038a1495 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x00000001032c299e objc_exception_throw + 43
2 CoreFoundation 0x000000010393265d -[NSObject(NSObject) doesNotRecognizeSelector:] + 205
3 CoreFoundation 0x0000000103892d8d ___forwarding___ + 973
4 CoreFoundation 0x0000000103892938 _CF_forwarding_prep_0 + 120
5 Euco 0x0000000100036ff8 -[JournalNutritionViewController numberOfSectionsInTableView:] + 88
6 UIKit 0x00000001024ec8e2 -[UITableViewRowData(UITableViewRowDataPrivate) _updateNumSections] + 86
7 UIKit 0x00000001024ed5b5 -[UITableViewRowData invalidateAllSections] + 66
8 UIKit 0x000000010238b0cc -[UITableView _updateRowData] + 191
9 UIKit 0x000000010239c225 -[UITableView noteNumberOfRowsChanged] + 91
10 UIKit 0x000000010239bd27 -[UITableView reloadData] + 717
11 Euco 0x00000001000368c8 __42-[JournalNutritionViewController setDate:]_block_invoke + 184
12 Euco 0x0000000100067f7e __57+[Day(ModelFunctions) read:withType:withSuccess:failure:]_block_invoke + 142
13 Euco 0x0000000100200b3b __66-[RKObjectRequestOperation setCompletionBlockWithSuccess:failure:]_block_invoke242 + 91
14 libdispatch.dylib 0x0000000103e50851 _dispatch_call_block_and_release + 12
15 libdispatch.dylib 0x0000000103e6372d _dispatch_client_callout + 8
16 libdispatch.dylib 0x0000000103e533fc _dispatch_main_queue_callback_4CF + 354
17 CoreFoundation 0x00000001038ff289 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 9
18 CoreFoundation 0x000000010384c854 __CFRunLoopRun + 1764
19 CoreFoundation 0x000000010384bd83 CFRunLoopRunSpecific + 467
20 GraphicsServices 0x0000000104af0f04 GSEventRunModal + 161
21 UIKit 0x00000001022d7e33 UIApplicationMain + 1010
22 Euco 0x0000000100063113 main + 115
23 libdyld.dylib 0x00000001040b45fd start + 1
24 ??? 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
When I add an exception breakpoint, it stops here before crashing:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return self.day.nutrition_plan.meal_goals.count
}
When it breaks there, if I run po self.day in the console, it returns <FoodEntry: 0x10ab5ff20> so it is somehow thinking the Day object is a FoodEntry object.
From your description your orphan block looks fine. It verifies the URL that is being processed so should be auctioned at the appropriate times.
This code:
self.day = (Day *)mappingResult.firstObject;
is a risk in a number of cases because you can't always be sure what the first object in the mapping result will be. If:
You have multiple mapped objects (nested)
You have multiple response descriptors (which leads to 1.)
then the mapping result should be queried as a dictionary and you should check the contents before casting them to what you hope they are. Basically never access the mapping result as an array.

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.

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