AFNetworking CFData Leak? - ios

I am having a problem with AFNetworking.
I am requesting a lot of JSON data from my Server via GET using this:
[[SessionResponseClient sharedClient] getPath:kURIRateList parameters:#{...} success:^(AFHTTPRequestOperation *operation, id JSON) {
[_delegate receivedRateResponse:JSON];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
[_delegate receivedRateResponse:nil];
}];
When this is called around 10-20 times, CFData seems to take most of the used memory of my app.
Memory Usage
When I investigate both CFData and CFData (store), I get the following:
CFData (store)
CFData
Side note: My app is using ARC and everything else seems to perform fine.
My question is now, as I didn't see any pending issues on AFNetworking's GitHub Page and almost no other complaints about that on the internet, what the heck am I doing wrong? Is anybody else facing this issue or am I the only one? Could you please post your code, as I don't think my Code looks that wrongs...
Update 1
The code for interface:
#protocol RateRequestsDelegate;
#interface RateRequests : NSObject {
id<RateRequestsDelegate> _delegate;
}
#property (nonatomic, strong) id<RateRequestsDelegate> delegate;
- (void)fetchRateList;
#end
#protocol RateRequestsDelegate <NSObject>
- (void)receivedRateResponse:(NSDictionary *)response;
#end
SessionResponseClient is just an extended AFHtttpClient instance, as all the AFNetworking examples demonstrate, see: Interact with an API
The code for receivedRateResponse:
- (void)receivedRateResponse:(NSDictionary *)json {
if (!json) {
return;
}
self.moviesToInsert = [NSMutableArray arrayWithArray:[json objectForKey:#"rated"]];
[self.tableView reloadData];
}
Update 2
I changed the callback now to a block-based function instead of using delegates and it improved a little, but its barely mentionable and could also be caused by just a side effect of something else. How do you guys implement this? Try fetching data, display it in a table- or scrollview and then pull these data many times from the server and refresh the views
Many thanks! Paul

Thanks dude - I had the exact same problem - your solution worked.
However, I thought I'd comment that in your solution, you're essentially turning the NSURLCache off once you receive a memory warning. I'm not sure exactly how AFNetworking uses the NSURLCache, but I'm assuming their implementation won't work as effectively if you turn it off (i.e. by setting its capacity to 0). This may slow down the request speed after your first memory warning onwards. As an extreme edge case, you might even experience unexpected behaviour after a few days of using your app, as it might not manifest until the first memory warning.
I instead suggest implementing something that removes the cached responses, but keeps the cache active:
-(void)didReceiveMemoryWarning
{
[[NSURLCache sharedURLCache] removeAllCachedResponses];
}
The only issue is that AFNetworking may need to build up its cache again, but I'm assuming this won't affect the framework quite as much.
Lastly, just in case it's useful to you or anyone - in order to register your own method to a memory warning notification, you can do this:
[[NSNotificationCenter defaultCenter] addObserver:self (or pointer to your singleton)
selector:#selector(myMethod)
name:UIApplicationDidReceiveMemoryWarningNotification
object:nil];
I hope that helps!

Okay, the solution was that CFData (store) seems to be responsible for holding the url cache in memory when using NSURLConnection's.
So all I had to do was call...
NSURLCache *sharedCache = [[NSURLCache alloc] initWithMemoryCapacity:0 diskCapacity:0 diskPath:nil];
[NSURLCache setSharedURLCache:sharedCache];
...to clear the cache, once I received a memory warning...
Or you can just call it whenever you want(didn't time profile that function though)...
Hope this helps someone who encounters a similar problem.

Maybe you could give #autoreleasepool a try.
For example:
#autoreleasepool {
// your codes below
[[SessionResponseClient sharedClient] getPath:kURIRateList parameters:#{...} success:^(AFHTTPRequestOperation *operation, id JSON) {
[_delegate receivedRateResponse:JSON];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
[_delegate receivedRateResponse:nil];
}];
// your codes above
}

Related

Managing a bunch of NSOperation with dependencies

I'm working on an application that create contents and send it to an existing backend. Content is a title, a picture and location. Nothing fancy.
The backend is a bit complicated so here is what I have to do :
Let the user take a picture, enter a title and authorize the map to use its location
Generate a unique identifier for the post
Create the post on the backend
Upload the picture
Refresh the UI
I've used a couple of NSOperation subclasses to make this work but I'm not proud of my code, here is a sample.
NSOperation *process = [NSBlockOperation blockOperationWithBlock:^{
// Process image before upload
}];
NSOperation *filename = [[NSInvocationOperation alloc] initWithTarget: self selector: #selector(generateFilename) object: nil];
NSOperation *generateEntry = [[NSInvocationOperation alloc] initWithTarget: self selector: #selector(createEntry) object: nil];
NSOperation *uploadImage = [[NSInvocationOperation alloc] initWithTarget: self selector: #selector(uploadImageToCreatedEntry) object: nil];
NSOperation *refresh = [NSBlockOperation blockOperationWithBlock:^{
// Update UI
[SVProgressHUD showSuccessWithStatus: NSLocalizedString(#"Success!", #"Success HUD message")];
}];
[refresh addDependency: uploadImage];
[uploadImage addDependency: generateEntry];
[generateEntry addDependency: filename];
[generateEntry addDependency: process];
[[NSOperationQueue mainQueue] addOperation: refresh];
[_queue addOperations: #[uploadImage, generateEntry, filename, process] waitUntilFinished: NO];
Here are the things I don't like :
in my createEntry: for example, I'm storing the generated filename in a property, which mees with the global scope of my class
in the uploadImageToCreatedEntry: method, I'm using dispatch_async + dispatch_get_main_queue() to update the message in my HUD
etc.
How would you manage such workflow ? I'd like to avoid embedding multiple completion blocks and I feel like NSOperation really is the way to go but I also feel there is a better implementation somewhere.
Thanks!
You can use ReactiveCocoa to
accomplish this pretty easily. One of its big goals is to make this kind of
composition trivial.
If you haven't heard of ReactiveCocoa before, or are unfamiliar with it, check
out the Introduction
for a quick explanation.
I'll avoid duplicating an entire framework overview here, but suffice it to say that
RAC actually offers a superset of promises/futures. It allows you to compose and
transform events of completely different origins (UI, network, database, KVO,
notifications, etc.), which is incredibly powerful.
To get started RACifying this code, the first and easiest thing we can do is put
these separate operations into methods, and ensure that each one returns
a RACSignal. This isn't strictly necessary (they could all be defined within
one scope), but it makes the code more modular and readable.
For example, let's create a couple signals corresponding to process and
generateFilename:
- (RACSignal *)processImage:(UIImage *)image {
return [RACSignal startEagerlyWithScheduler:[RACScheduler scheduler] block:^(id<RACSubscriber> subscriber) {
// Process image before upload
UIImage *processedImage = …;
[subscriber sendNext:processedImage];
[subscriber sendCompleted];
}];
}
- (RACSignal *)generateFilename {
return [RACSignal startEagerlyWithScheduler:[RACScheduler scheduler] block:^(id<RACSubscriber> subscriber) {
NSString *filename = [self generateFilename];
[subscriber sendNext:filename];
[subscriber sendCompleted];
}];
}
The other operations (createEntry and uploadImageToCreatedEntry) would be very similar.
Once we have these in place, it's very easy to compose them and express their
dependencies (though the comments make it look a bit dense):
[[[[[[self
generateFilename]
flattenMap:^(NSString *filename) {
// Returns a signal representing the entry creation.
// We assume that this will eventually send an `Entry` object.
return [self createEntryWithFilename:filename];
}]
// Combine the value with that returned by `-processImage:`.
zipWith:[self processImage:startingImage]]
flattenMap:^(RACTuple *entryAndImage) {
// Here, we unpack the zipped values then return a single object,
// which is just a signal representing the upload.
return [self uploadImage:entryAndImage[1] toCreatedEntry:entryAndImage[0]];
}]
// Make sure that the next code runs on the main thread.
deliverOn:RACScheduler.mainThreadScheduler]
subscribeError:^(NSError *error) {
// Any errors will trickle down into this block, where we can
// display them.
[self presentError:error];
} completed:^{
// Update UI
[SVProgressHUD showSuccessWithStatus: NSLocalizedString(#"Success!", #"Success HUD message")];
}];
Note that I renamed some of your methods so that they can accept inputs from
their dependencies, giving us a more natural way to feed values from one
operation to the next.
There are huge advantages here:
You can read it top-down, so it's very easy to understand the order that
things happen in, and where the dependencies lie.
It's extremely easy to move work between different threads, as evidenced by
the use of -deliverOn:.
Any errors sent by any of those methods will automatically cancel all the
rest of the work, and eventually reach the subscribeError: block for easy
handling.
You can also compose this with other streams of events (i.e., not just
operations). For example, you could set this up to trigger only when a UI
signal (like a button click) fires.
ReactiveCocoa is a huge framework, and it's unfortunately hard to distill the
advantages down into a small code sample. I'd highly recommend checking out the
examples for when to use
ReactiveCocoa
to learn more about how it can help.
A couple of thoughts:
I would be inclined to avail myself of completion blocks because you probably only want to initiate the next operation if the previous one succeeded. You want to make sure that you properly handle errors and can easily break out of your chain of operations if one fails.
If I wanted to pass data from operation to another and didn't want to use some property of the caller's class, I would probably define my own completion block as a property of my custom operation that had a parameter which included the field that I wanted to pass from one operation to another. This assumes, though, that you're doing NSOperation subclassing.
For example, I might have a FilenameOperation.h that defines an interface for my operation subclass:
#import <Foundation/Foundation.h>
typedef void (^FilenameOperationSuccessFailureBlock)(NSString *filename, NSError *error);
#interface FilenameOperation : NSOperation
#property (nonatomic, copy) FilenameOperationSuccessFailureBlock successFailureBlock;
#end
and if it wasn't a concurrent operation, the implementation might look like:
#import "FilenameOperation.h"
#implementation FilenameOperation
- (void)main
{
if (self.isCancelled)
return;
NSString *filename = ...;
BOOL failure = ...
if (failure)
{
NSError *error = [NSError errorWithDomain:... code:... userInfo:...];
if (self.successFailureBlock)
self.successFailureBlock(nil, error);
}
else
{
if (self.successFailureBlock)
self.successFailureBlock(filename, nil);
}
}
#end
Clearly, if you have a concurrent operation, you'll implement all of the standard isConcurrent, isFinished and isExecuting logic, but the idea is the same. As an aside, sometimes people will dispatch those success or failures back to the main queue, so you can do that if you want, too.
Regardless, this illustrates the idea of a custom property with my own completion block that passes the appropriate data. You can repeat this process for each of the relevant types of operations, you can then chain them all together, with something like:
FilenameOperation *filenameOperation = [[FilenameOperation alloc] init];
GenerateOperation *generateOperation = [[GenerateOperation alloc] init];
UploadOperation *uploadOperation = [[UploadOperation alloc] init];
filenameOperation.successFailureBlock = ^(NSString *filename, NSError *error) {
if (error)
{
// handle error
NSLog(#"%s: error: %#", __FUNCTION__, error);
}
else
{
generateOperation.filename = filename;
[queue addOperation:generateOperation];
}
};
generateOperation.successFailureBlock = ^(NSString *filename, NSData *data, NSError *error) {
if (error)
{
// handle error
NSLog(#"%s: error: %#", __FUNCTION__, error);
}
else
{
uploadOperation.filename = filename;
uploadOperation.data = data;
[queue addOperation:uploadOperation];
}
};
uploadOperation.successFailureBlock = ^(NSString *result, NSError *error) {
if (error)
{
// handle error
NSLog(#"%s: error: %#", __FUNCTION__, error);
}
else
{
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
// update UI here
NSLog(#"%#", result);
}];
}
};
[queue addOperation:filenameOperation];
Another approach in more complicated scenarios is to have your NSOperation subclass employ a technique analogous to how the standard addDependency method works, in which NSOperation sets the isReady state based upon KVO on isFinished on the other operation. This not only allows you to not only establish more complicated dependencies between operations, but also to pass database between them. This is probably beyond the scope of this question (and I'm already suffering from tl:dr), but let me know if you need more here.
I wouldn't be too concerned that uploadImageToCreatedEntry is dispatching back to the main thread. In complicated designs, you might have all sorts of different queues dedicated for particular types of operations, and the fact that UI updates are added to the main queue is perfectly consistent with this mode. But instead of dispatch_async, I might be inclined to use the NSOperationQueue equivalent:
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
// do my UI update here
}];
I wonder if you need all of these operations. For example, I have a hard time imagining that filename is sufficiently complicated to justify its own operation (but if you're getting the filename from some remote source, then a separate operation makes perfect sense). I'll assume that you're doing something sufficiently complicated that justifies it, but the names of those operations make me wonder, though.
If you want, you might want to take a look at couchdeveloper's RXPromise class which uses promises to (a) control the logical relationship between separate operations; and (b) simplify the passing of data from one to the next. Mike Ash has a old MAFuture class which does the same thing.
I'm not sure either of those are mature enough that I'd contemplate using them in my own code, but it's an interesting idea.
I'm probably totally, biased - but for a particular reason - I like #Rob's approach #6 ;)
Assuming you created appropriate wrappers for your asynchronous methods and operations which return a Promise instead of signaling the completion with a completion block, the solution looks like this:
RXPromise* finalResult = [RXPromise all:#[[self filename], [self process]]]
.then(^id(id filenameAndProcessResult){
return [self generateEntry];
}, nil)
.then(^id(id generateEntryResult){
return [self uploadImage];
}, nil)
.thenOn(dispatch_get_main_queue() , ^id(id uploadImageResult){
[self refreshWithResult:uploadImageResult];
return nil;
}, nil)
.then(nil, ^id(NSError*error){
// Something went wrong in any of the operations. Log the error:
NSLog(#"Error: %#", error);
});
And, if you want to cancel the whole asynchronous sequence at any tine, anywhere and no matter how far it has been proceeded:
[finalResult.root cancel];
(A small note: property root is not yet available in the current version of RXPromise, but its basically very simple to implement).
If you still want to use NSOperation, you can rely on ProcedureKit and use the injection properties of the Procedure class.
For each operation, specify which type it produces and inject it to the next dependent operation. You can also at the end wrap the whole process inside a GroupProcedure class.

iOS [ARC] app not releasing memory

My application, during a process I've written, is rising in memory and seems to not be releasing it.
The first thing I'd like to mention is that the basic outline of what I've written is this:
- Request a url (fetching data using NSData -initWithContentsOfURL)
- Parse NSData into NSArray of NSDictionarys using NSJSONSerialization +JSONObjectWithStream
- Loop through decoded NSArray inserting/updating/deleting records in a sqlite database using the FMDB framework with the data decoded
The application does the above, however it does it in a loop for an undetermined period of time, in which the application displays a "Loading" HUD. I thought it may be worth mentioning this, although I find it insignificant how many times it does this process, as that shouldn't affect the memory usage if it were releasing properly. If I am wrong here, please advise me.
My code works fine, well, it does what it's intended to do. However, when I profile the application code, the memory seems to just keep rising. It does drop in segments throughout, but overall it keeps rising (IE doesn't release in full what it previously used).
I have, as previously stated, profiled the application with Allocations, Leaks, VM Tracker, and used Trace Highlights.
Trace Highlights: Shows that the memory usage is gradually going up, but dropping some memory (not all) meaning if the process is running for long enough the memory will reach high usage and terminate.
Allocations: Seems OK. The allocations has spikes but always comes back down to where it started. I took heapshots and they always drop down leaving maximum 500-700kb per segment (left for about 10 minutes)
VM Tracker: Proves to show that memory consistently rises, and is not releasing full memory (as discovered in trace highlights). Resident seems to get really high
Leaks: No leaks found in application
Here's some screenshots of Allocations/VM Tracker running:
It's worth noting that I have in fact tried:
- Adding autoreleasepools
- "force releasing" by assigning each properties; such as NSURLs, NSRequests, etc; to nil
My questions:
- Should I be doing something special to release the memory?
- How could I further debug this issue?
- How best can I find out what's wrong from the data Instruments gives me?
---- EDIT: ----
Here's the code that sends the url request to fetch the data.:
- (void) requestAndParse : (NSString *)url
{
NSURL *theURL;
ASIHTTPRequest *request;
NSData *collectedData;
NSError *error;
#try {
// File cache the NSData
theURL = [[NSURL alloc] initWithString: url];
request = [ASIHTTPRequest requestWithURL: theURL];
[request setDownloadDestinationPath: [[NSHomeDirectory() stringByAppendingPathComponent:#"Documents"] stringByAppendingString:#"/cachefile.txt"]];
[request startSynchronous];
[request waitUntilFinished];
collectedData = [[NSData alloc] initWithContentsOfFile:[[NSHomeDirectory() stringByAppendingPathComponent:#"Documents"] stringByAppendingString:#"/cachefile.txt"]];
if ([collectedData length] > 0) {
records = [NSJSONSerialization JSONObjectWithData:collectedData options:NSJSONReadingMutableContainers error:&error];
}
}
#catch (NSException *exception) {
// Failed
NSLog(#"Parse error: %#", error);
}
#finally {
// DB updates with the records here
...
// remove file
[[NSFileManager defaultManager] removeItemAtPath:[[NSHomeDirectory() stringByAppendingPathComponent:#"Documents"] stringByAppendingString:#"/cachefile.txt"] error:nil];
// release properties used
collectedData = nil;
request = nil;
theURL = nil;
}
}
This above method is called from within a while loop in the Application Delegate. The while loop is an undetermined length, as previously mentioned.
--- EDIT 2: ---
The following is what happens within the #finally statement (updating the SQLite database using FMDB). There are a lot of these methods in my class, one for each table. They all follow the same pattern though, as they are all duplicated from the first one:
-(BOOL) insertBatchOfRecords:(NSArray *)records {
__block BOOL queueReturned = YES;
#autoreleasepool {
FMDatabaseQueue *dbQueue = [self instantiateDatabaseQueue];
[dbQueue inTransaction:^(FMDatabase *tdb, BOOL *rollback) {
if (![tdb open]) {
NSLog(#"Couldn't open DB inside Transaction");
queueReturned = NO;
*rollback = YES;
return;
}
for (NSDictionary *record in records) {
[tdb executeUpdate:#"INSERT OR REPLACE INTO table (attr1, attr2) VALUES (?,?)", [record valueForKey:#"attr1"], [record valueForKey:#"attr2"]];
if ([tdb hadError]) {
queueReturned = NO;
*rollback = YES;
NSLog(#"Failed to insert records because %#", [tdb lastErrorMessage]);
return;
}
}
}];
[dbQueue close];
dbQueue = nil;
}
return queueReturned;
}
And follows is the -instantiateDatabaseQueue method:
-(FMDatabaseQueue *) instantiateDatabaseQueue {
#autoreleasepool {
return [FMDatabaseQueue databaseQueueWithPath: [self.getDocumentsDirectory stringByAppendingPathComponent:#"localdb.db"]];
}
}
The autoreleasepools may make it messy, but the code originally did not have these. I implemented them in various locations to see if there was any improvement (there was not).
--- EDIT 3 ---
I have been profiling the application the past few days, and still have no luck in finding an answer. I have separated the part of the app in question to a separate project of it's own, to make sure that it is indeed this causing the memory usage. This proved to be correct, as the app is still acting the same.
I have taken further profiling pictures, and am still having a hard time identifying what is actually wrong. See below that the allocations looks OK (the VM also doesn't look too bad to me?), and there's still no leaks (no picture of this, because there's none!!)
However, when I profiled on Trace Highlights, the memory usage just keeps going up, until reaching too much usage (around 70+MB on a 3GS) and then crashes due to using so much memory.
I reduced the problem by using ASIHTTPRequest for grabbing the NSData (stores to file instead). Please see revised code above. However, problem still persists, just takes longer to happen!
As per originally, question:
- Is there something wrong with the second part of this app process?
Using try / catch in iOS with ARC can cause memory leaks, and is best avoided.
an alternative approach is to use an async NSURLConnection, or an NSOperation with a synch NSURLConnection.

ARC: returning allocated object from a method called by performSelector, is it OK?

I'm not sure if i cause a leak here, is it ok to return allocated NSError back to
the calling method by perform selector?
Is it OK to create the NSMutableArray and store it in the same object i got for the callback? and later pass it to the delegate?
The code works fine, but because i'm new to arc i have the fear of doing something wrong.
(i'm using perform selector because my selector is dynamic. just for the example i wrote it statically).
AFHTTPRequestOperation *operation = [self.client HTTPRequestOperationWithRequest:request
success:^(AFHTTPRequestOperation *operation, id responseObject) {
//-----------------Callback--------------------
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
SEL callback = #selector(getOperationCallback:);
NSError *error = [self performSelector:callback withObject:operation];
//------------------Delegate Call---------------
if(operation.delegate)
[operation.delegate onFinish:operation.requestIdentifier error:error
data:operation.parsedObject];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
//------------------Delegate Call---------------
if(operation.delegate)
[operation.delegate onFinish:operation.requestIdentifier error:error data:nil];
}];
- (NSError *)getOperationCallback:(AFHTTPRequestOperation *)operation{
NSArray *rawJson = (NSArray *)operation.jsonObject;
NSError *error;
NSMutableArray *array = [[NSMutableArray alloc] init];
for(id json in rawJson){
MyObject *object = [[MyObject alloc] initWithJson:json];
if(object){
[array addObject:object];
}else{
error = [NSError errorWithDomain:#"myErrors" code:1000 userInfo:nil];
break;
}
}
operation.parsedObject = array;
return error;
}
Generally, performSelector: in ARC could only cause a leak, if the selector you pass to it starts with alloc, new, retain, copy, or mutableCopy.
is it ok to return allocated NSError back to the calling method by perform selector?
Is it OK to create the NSMutableArray and store it in the same object
i got for the callback?
and later pass it to the delegate?
Answer to all questions are OK, nothing wrong with anything. All objects are created in autorelease way.
As long as the return value of the method your are invoking via performSelector:withObject: is an object, it's perfectly ok to do that.
It won't leak since ARC will take care of releasing array and error is autoreleased.
In general, steer clear of performSelector:. The reason being that ARC cannot help you. Even if you think your app works and you've tested that it does, it might break later down the line when you change something.
Sure, if the selector you're calling does not start with alloc, new, copy, mutableCopy, etc then it won't be a problem. But there's cases, such as using __attribute__((ns_returns_retained)) that make it non-obvious that a method might return something retained. In any case, having code that ARC cannot help you out with, is a bad thing.
There's always a way to make it such that you don't have to use performSelector:. Why not make use of a callback block for example?

RestKit/RestEASY -- ClientAbortException when enqueuing request operations

I am working on an iOS application that will use RestKit 0.20 to make REST-based calls to a service that is running on JBoss AS 7.1.1 and using restEASY as its REST-based web service framework.
The REST service that the client app will be calling is used to retrieve objects based on their unique identifier. Since these objects can be small or large (> 1MB in size) and great in number (20? 50? 100 or more at a time) I don't want to make one large call to retrieve them all at once. Rather, I was planning on using RestKit's queued operation support to create a GET request for each object based on the object identifier, and execute the calls asynchronously. Once the GET has completed, each object will be processed through the use of Objective-C blocks so as to avoid any unnecessary blocking.
My RestKit client code looks like this...
NSArray *identifiers = ...
RKObjectManager *objectManager = [RKObjectManager sharedManager];
RKResponseDescriptor *getObjResp = [RKResponseDescriptor responseDescriptorWithMapping:[MyObject mapping] pathPattern:[WebServiceHelper pathForServiceOperation:#"/objects/:uniqueIdentifier"] keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
for (int i=0; i < identifiers.count; i++) {
NSString *identifier = [identifiers objectAtIndex:i];
NSURL *serviceURL = [WebServiceHelper urlForServiceOperation:[NSString stringWithFormat:#"/objects/%#", identifier]];
NSURLRequest *request = [NSURLRequest requestWithURL:serviceURL];
RKObjectRequestOperation *requestOp = [[RKObjectRequestOperation alloc] initWithRequest:request responseDescriptors:#[getObjResp]];
[requestOp setCompletionBlockWithSuccess:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
MyObject *obj = [mappingResult firstObject];
if (self.delegate != nil) {
[self.delegate didLoadObjectWithIdentifier:identifier myObj:obj];
}
} failure:^(RKObjectRequestOperation *operation, NSError *error){
if (self.delegate != nil) {
[self.delegate didFinishWithError:error];
}
}];
[objectManager enqueueObjectRequestOperation:requestOp];
}
From there, the delegate method that gets called when an object has been retrieved looks like this:
-(void)didLoadObjectWithIdentifier:(NSString *)identifier myObj:(MyObject *)myObj {
if(secureMessage != nil) {
NSLog(#"Message %# retrieved successfully : %#:%#", identifier, myObj);
} else {
NSLog(#"NO OBJ");
}
}
The calls appear to be functioning as expected, as I am able to print out information about the retrieve objects. However, I am seeing some weird/unexepcted behavior on the service side.
First, I see a number of Exceptions being thrown by restEASY:
13:22:02,903 WARN [org.jboss.resteasy.core.SynchronousDispatcher] (http--0.0.0.0-8080-10) Failed executing GET /objects/BBFE39EA126F610C: org.jboss.resteasy.spi.WriterException: ClientAbortException: java.net.SocketException: Broken pipe
at org.jboss.resteasy.core.ServerResponse.writeTo(ServerResponse.java:262) [resteasy-jaxrs-2.3.2.Final.jar:]
at org.jboss.resteasy.core.SynchronousDispatcher.writeJaxrsResponse(SynchronousDispatcher.java:585) [resteasy-jaxrs-2.3.2.Final.jar:]
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:506) [resteasy-jaxrs-2.3.2.Final.jar:]
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:119) [resteasy-jaxrs-2.3.2.Final.jar:]
at org.jboss.seam.resteasy.ResteasyResourceAdapter$1.process(ResteasyResourceAdapter.java:145) [jboss-seam-resteasy.jar:2.3.0.Final]
at org.jboss.seam.servlet.ContextualHttpServletRequest.run(ContextualHttpServletRequest.java:65) [jboss-seam.jar:2.3.0.Final]
at org.jboss.seam.resteasy.ResteasyResourceAdapter.getResource(ResteasyResourceAdapter.java:120) [jboss-seam-resteasy.jar:2.3.0.Final]
...
It would appear as though RestKit is closing the socket somehow (or some other error is preventing the object from being read from the server). I am unable to find anything in the documentation that could explain what is going on here.
Secondly, though, I also see another call for the very same object when a request fails with this error. Why is the GET being called more than once? Is RestKit redoing the failed GET request?
I'm mostly concerned about why the Exception is occurring within restEASY, as it will make it difficult to diagnose calls that really do fail. Has anyone seen this behavior before? Any tips as to how I can correct these issues? Thanks for any help you can give!!
Those exception are resulted from disconnected Clients i.e. some of the users might quit the app while waiting for the process to complete OR has a network failure (at the client end).
Hence, Broken Pipe.

ipad: Crash out of application is not generating an exception?

I am having this horrible crash out of my application that I have been trying to resolve for several days now. The code is an NSURLRequest to send a request to a web-service. I already use the web-service in production and I simply added this new service request. I finally added #try ... #catch around the offending code and it still crashes the application and does not "catch" anything.
How do I debug this?
I have used code inspection, including a peer review.
The code is like this ... where "httpClient" is an NSObject with:
id _delegateConnection;
id _delegateReceiver;
NSURLConnection *connection;
NSMutableURLRequest *urlServiceRequest;
NSMutableString *bodyRequest;
NSHTTPURLResponse *httpResponse;
NSMutableData *responseData;
NSError *error;
#try {
[httpClient setDelegateReceiver: self];
[httpClient buildRequest: dictParameters];
[httpClient executeRequest];
}
#catch (NSException *exception) {
NSLog(#"%s: %#", __FUNCTION__, exception);
}
#finally {
// Add code here ...
}
I found the problem and it was through good-fortune and code inspection in a different part of the code ("where the light was better" :)
As it turns out, I have a dictionary of parameters that get written to a JSON string, added to the HTTP body of the urlServiceRequest object listed in my sample code. What I finally stumbled upon was that the parameter container (NSObject, not NSDictionary) was not "retained", therefore it was probably "autoreleased", while still referenced within my buildRequest method, by the posting of the urlServiceRequest.
Poor memory management on my part led me astray in my troubleshooting.

Resources