RestKit Core Data NSError dealloc Crash - ios

Trying to get to the bottom of an issue I've been seeing in production builds and FINALLY was able to reproduce it while testing. Using RestKit v0.23.1, when doing an RKManagedObjectRequestOperation using the following code (while plugged into instruments) I get "An Objective-C message was sent to a deallocated 'NSError' object (zombie)" and the app crashes every time there's objects in the response JSON - if the response is something like "objects = ();" there's no crash - so I'm guessing it's somewhere in the RestKit/Core Data mapping or storage?
RKManagedObjectRequestOperation *objectRequestOperation = [_objectManager managedObjectRequestOperationWithRequest:request managedObjectContext:_objectManager.managedObjectStore.mainQueueManagedObjectContext success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
DDLogInfo(#"INSIDE SUCCESS BLOCK");
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
DDLogInfo(#"INSIDE ERROR BLOCK");
}];
[objectRequestOperation setWillMapDeserializedResponseBlock:^id(id deserializedResponseBody) {
DDLogInfo(#"Response JSON: %#", deserializedResponseBody);
return deserializedResponseBody;
}];
objectRequestOperation.savesToPersistentStore = YES;
[objectRequestOperation start];
The raw JSON is properly logged inside the setWillMapDeserializedResponseBlock, but the logs inside the success and error block are never reached. Here is the stack trace I get back from crashlytics:
Thread : Crashed: NSOperationQueue Serial Queue
0 libobjc.A.dylib 0x37dd4626 objc_msgSend + 5
1 Foundation 0x2df5802d -[NSError dealloc] + 60
2 libobjc.A.dylib 0x37dd9b6b objc_object::sidetable_release(bool) + 174
3 libobjc.A.dylib 0x37dda0d3 (anonymous namespace)::AutoreleasePoolPage::pop(void*) + 358
4 CoreFoundation 0x2d569501 _CFAutoreleasePoolPop + 16
5 Foundation 0x2df69999 -[__NSOperationInternal _start:] + 1064
6 Foundation 0x2e00d745 __NSOQSchedule_f + 60
7 libdispatch.dylib 0x382b8cbd _dispatch_queue_drain + 488
8 libdispatch.dylib 0x382b5c6f _dispatch_queue_invoke + 42
9 libdispatch.dylib 0x382b95f1 _dispatch_root_queue_drain + 76
10 libdispatch.dylib 0x382b98dd _dispatch_worker_thread2 + 56
11 libsystem_pthread.dylib 0x383e4c17 _pthread_wqthread + 298

This isn't a problem with RestKit. I've seen this problem frequently and it actually looks like the over-release actually happens in Apple's code. The problem happens when you try to save to a Core Data store and it fails. Core Data reports an error as it should, but that error is mishandled.
I had a few scenarios causing the save failures and this is how I fixed them:
The data store is inaccessible because of the Data Protection API.
Either busy wait and let your app fail to launch like this:
while(![[UIApplication sharedApplication] isProtectedDataAvailable]) {
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.5f]];
}
Or disable protection if the data in your store isn't sensitive like this:
[_coordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:url
options:#{NSPersistentStoreFileProtectionKey:NSFileProtectionNone}
error:&error];
The important thing is that you don't try to save until you can access the file. If you can re-structure you code to prevent accessing the database when it is inaccessible that is good too. You can use the Data Protection API application delegate methods to trigger that mechanism.
The data store is corrupted - The best thing to do here is to delete the store and start over. Here is a good way to detect a corrupted store using the sqlite library directly.
#import <sqlite3.h>
sqlite3 *dbConnection;
if (sqlite3_open([[url absoluteString] UTF8String], &dbConnection) != SQLITE_OK) {
NSLog(#"[SQLITE] Unable to open database!");
}
sqlite3_stmt *statement = nil;
sqlite3_prepare_v2(dbConnection, "PRAGMA quick_check;", -1, &statement, NULL);
NSString *result = nil;
while (sqlite3_step(statement) == SQLITE_ROW) {
for (int i=0; i<sqlite3_column_count(statement); i++) {
int colType = sqlite3_column_type(statement, i);
if (colType == SQLITE_TEXT) {
const unsigned char *col = sqlite3_column_text(statement, i);
result = [NSString stringWithFormat:#"%s", col];
} else {
NSLog(#"[SQLITE] UNKNOWN DATATYPE");
}
}
}
sqlite3_close(dbConnection);
This runs a sqlite PRAGMA query to perform an integrity check. I use quick_check, but you could also use integrity_check if you are willing to wait the extra time. You can tell things are good using [result isEqualToString:#"ok"]

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.

iOS Core Data dispatch_async background queuing crash

I'm getting a non-reproduceable crash and I'm not sure why. I'm caching images on a background queue. The image names are properties on a Core Data NSManagedObject subclass, CCCard. At the same time, I have a collection view that is also accessing these CCCards.
Here is the relevant code and notes to follow.
//CCDeckViewController.m --------------------------------------
- (void)viewDidLoad {
// This will fetch the CCCard objects from Core Data.
self.cards = [[CCDataManager shared] cards];
[self cacheImages];
}
- (void)cacheCardImages {
// Because these are NSManagedObjects, I access them in the background
// via their object ID. So pull the IDs out here.
NSArray *cardIds = [self.cards valueForKey:#"objectID"];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
for (NSManagedObjectID *cardId in cardIds) {
// Fetch the actual CCCard object.
CCCard *card = (CCCard *)[[CCDataManager shared] objectWithId:cardId];
// Cache the card's image if it's not already there.
NSString *key = [card thumbnailCacheKey];
if ([self.cardImageCache objectForKey:key]) {
continue;
}
CCDiscardableImage *discardable = [CCHelper decompressedImageForPath:key size:[card thumbnailSize] tintable:[card tintable]];
[self.cardImageCache setObject:discardable forKey:key];
}
});
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
CCCard *card = self.cards[indexPath.item];
// This line calls the code that crashes.
UIColor *color = [card color];
// More code that returns the cell.
}
// CCCard.m --------------------------------------
- (UIColor *)color {
// Crash happens on this line.
if (self.colorId.integerValue == 0) {
// some code
}
}
Here are parts of the stack trace from the Crashlytics report I think are most relevant:
Thread #0: Crashed: com.apple.main-thread
EXC_BREAKPOINT 0x000000000000defe
0 CoreData 0x24c1b070 _sharedIMPL_pvfk_core + 247
1 CoreData 0x24c1b071 _sharedIMPL_pvfk_core + 248
2 myapp 0x4286f -[CCCard color] (CCCard.m:37)
3 myapp 0x40bbb -[CCDeckViewController collectionView:cellForItemAtIndexPath:] (CCDeckViewController.m:127)
Thread #4: com.apple.root.utility-qos
0 libsystem_pthread.dylib 0x2321920c RWLOCK_GETSEQ_ADDR
1 libsystem_pthread.dylib 0x23219295 pthread_rwlock_unlock + 60
2 libobjc.A.dylib 0x22cb8e01 rwlock_tt<false>::unlockRead() + 8
3 libobjc.A.dylib 0x22cb5af5 lookUpImpOrForward + 488
4 libobjc.A.dylib 0x22cb5903 _class_lookupMethodAndLoadCache3 + 34
5 libobjc.A.dylib 0x22cbbd7b _objc_msgSend_uncached + 26
6 CoreData 0x24c1d3ab _PFObjectIDFastEquals64 + 38
7 CoreFoundation 0x233eeed4 CFBasicHashFindBucket + 1820
8 CoreFoundation 0x233ee775 CFDictionaryGetValue + 116
9 CoreData 0x24c17037 _PFCMT_GetValue + 122
10 CoreData 0x24c16ec7 -[NSManagedObjectContext(_NSInternalAdditions) _retainedObjectWithID:optionalHandler:withInlineStorage:] + 58
11 CoreData 0x24c1b45d _PF_FulfillDeferredFault + 940
12 CoreData 0x24c1afcf _sharedIMPL_pvfk_core + 86
13 myapp 0x42991 -[CCCard imagePath] (CCCard.m:53)
14 myapp 0x41d5b __39-[CCDeckViewController cacheCardImages]_block_invoke (CCDeckViewController.m:295)
It's frustrating because it never happens during development, so can't test any theories. I'm trying to understand the code and crash report to figure out the problem now. My guess is that it has something to do with faulting because it accesses the CCCard object's instance method, but then crashes when trying to read the property from it. But why?
You are violating thread confinement.
Per the Core Data documentation, a NSManagedObjectContext and any NSManagedObject associated with it must only be accessed on the queue that it is assigned to.
Your dispatch_async violates that rule and needs to be corrected. There is no longer a design where you can use Core Data in a dispatch_async like that.
If you want the processing to be asynchronous then you should spawn a private NSManagedObjectContext that is a child of your main NSManagedObjectContext and then execute a -performBlock: against it. That will give you background processing that is configured properly.
Also, I highly recommend turning on -com.apple.CoreData.ConcurrencyDebug 1 as that will catch issues like this during development.

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.

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

I cannot catch the "No space left on device" exception when using NSFileHandle writedata function

I used NSFileHandle to writedata to a file.
NSFilehandle *handle = [NSFileHandle fileHandleForWritingAtPath:#"path/of/file"];
#try {
[handle writedata:data];
} #catch (NSException *e) {
// when exception occur, never got here
NSLog(#"%#", e);
}
As my device disk space is full, calling writedata will fail. But I can't catch the exception.
My program log info:
2014-05-23 16:17:24.435 mytest[12919:3203] An uncaught exception was raised
2014-05-23 16:17:24.435 mytest[12919:3203] *** -[NSConcreteFileHandle writeData:]:
No space left on device
2014-05-23 16:17:24.436 mytest[12919:3203] (
0 CoreFoundation 0x00007fff8fae725c __exceptionPreprocess + 172
1 libobjc.A.dylib 0x00007fff8cbb3e75 objc_exception_throw + 43
2 CoreFoundation 0x00007fff8fae710c +[NSException raise:format:] + 204
3 Foundation 0x00007fff93640f31 __34-[NSConcreteFileHandle writeData:]_block_invoke + 84
4 Foundation 0x00007fff93840020 __49-[_NSDispatchData enumerateByteRangesUsingBlock:]_block_invoke + 32
5 libdispatch.dylib 0x00007fff8bfc2fad _dispatch_client_callout3 + 9
6 libdispatch.dylib 0x00007fff8bfc2f28 _dispatch_data_apply + 113
7 libdispatch.dylib 0x00007fff8bfc9502 dispatch_data_apply + 31
8 Foundation 0x00007fff9383fff9 -[_NSDispatchData enumerateByteRangesUsingBlock:] + 83
9 Foundation 0x00007fff93640ed2 -[NSConcreteFileHandle writeData:] + 150
10 ZiSyncMac 0x000000010000b1eb -[TransferFile writePart:data:] + 475
I found out writedata calls a dispatch to do real write data to the file system. So I think writedata will throw a exception in GCD.
How can I handle the GCD exception in my code?
From a website that's been hijacked since (not providing the link for that reason, but the explanation is still useful):
seekToEndOfFile() and writeData() are not marked as throws (they don’t
throw an NSError object which can be caught in with a do-try-catch
block), which means in the current state of Swift, the NSExceptions
raised by them cannot be “caught”.
If you’re working on a Swift project, you could create an Objective-C
class which implements your NSFileHandle methods that catches the
NSExceptions (like in this question), but otherwise you’re out of
luck.
What #eric said is right.
But, what you can do is check before that you write for how much space is left in the disk and only after it write to the disk.

Resources