issue with EXC_BAD_REQUEST in TWRequest - iphone

I have the following code and it always gives me a crash when performing the request, any idea?
NSString *responseBody = [[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding];
NSLog(#"Response body is %#", responseBody);
NSDictionary *accessTokenRequestParams = [[NSMutableDictionary alloc] init];
[accessTokenRequestParams setValue:CONSUMER_KEY forKey:#"x_reverse_auth_target"];
[accessTokenRequestParams setValue:responseBody forKey:#"x_reverse_auth_parameters"];
NSURL *url2 = [NSURL URLWithString:#"https://api.twitter.com/oauth/access_token"];
TWRequest * accessTokenRequest = [[TWRequest alloc] initWithURL:url2 parameters:accessTokenRequestParams requestMethod:TWRequestMethodPOST];
if (selectionIndex != -1)
[accessTokenRequest setAccount:[self.twitterACAccounts objectAtIndex:selectionIndex]];
// execute the request
[accessTokenRequest performRequestWithHandler:
^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) {
NSString *responseStr =
[[NSString alloc] initWithData:responseData
encoding:NSUTF8StringEncoding];
NSLog(#"The user's info for your server:\n%#", responseStr);
}];
UPDATE:
Turning on NSZombieEnabled gives me
*** -[ACAccountStore typeForAccount:]: message sent to deallocated instance 0x7199c70
this is no where to be found

Your error looks completely different than your question. You have error in ACAccountStore class. Check your retain count when you accessing, manipulating, and store accounts (ACAccountStore). I think you are deallocated memory first and you are using some where.

Somewhere you call ACAccountStore typeForAccount. But the ACAccountStore is gone. Looking at the AcAccount docs, there are no special initializers, so likely in your code you have something like:
static ACAccountStore* accountStore = [[[ACAccountStore alloc] init] autorelease];
then in the completion for the request, the object has been cleaned away by the OS, but your accountStore still points to the old, now dangling pointer. The pointer may be 'static' or 'global' or a member of some other static or global object.
Look for ACAccountStore in your code.

Related

handle NSError using ARC - leak

- (BOOL)parserJSONString:(NSString *)jsonString error:(NSError **)anError {
//some data getting
//error handle
NSString *description = #"phone number couldn't be using";
NSString *recoverySuggestion = #"Please provide an other phone number.";
NSInteger errorCode = -1;
NSArray *keys = [NSArray arrayWithObjects: NSLocalizedDescriptionKey, NSLocalizedRecoverySuggestionErrorKey, nil];
NSArray *values = [NSArray arrayWithObjects:description, recoverySuggestion, nil];
NSDictionary *userDict = [NSDictionary dictionaryWithObjects:values forKeys:keys];
*anError = [[NSError alloc] initWithDomain:#"my domain" code:errorCode userInfo:userDict];
return NO;
}
*anError = [[NSError alloc] initWithDomain:#"my domain" code:errorCode userInfo:userDict]; compiler give next leak warning
"Potential null dereference. According to coding standards in 'Creating and Returning NSError Objects' the parameter '' may be null"
How to fix this?
You need to first check whether anError is nil or NULL:
if (anError) {
*anError = [[NSError alloc] initWithDomain:#"my domain" code:errorCode userInfo:userDict];
}
This is not actually a leak warning, but a potential dereference of a null pointer. The compiler is complaining about the line
*anError = [[NSError alloc] initWithDomain:#"my domain" code:errorCode userInfo:userDict];
You assign to the location being pointed to by anError without checking, whether anError is actually the null pointer (which is allowed "according to the coding standard", and may happen, if the caller is not interested in detailed error information).

fetch JSON data asynchronously

I want to fetch JSON data asynchronously. The data is set up in a way that one request will bring only 8 records. I need to send the requests repeatedly until the response becomes empty or returns less than 8 records.
Currently, I have these methods in myviewcontroller.m class:
(void)myCallback:(id)sender {
MyDataRequest *objMyDataRequest = [[[MyDataRequest alloc] init] autorelease];
objMyDataRequest.myRequiredVariableToGetAuthTokenDataResponse = classOfMyCallBack.someVariable;
// Initiate getAuthToken request
[objWishListRequest initiateGetAuthTokenRequest:self requestSelector:#selector(getAuthTokenDataResponse:)];
}
Now here is the definition of getAuthTokenDataResponse:
(void) getAuthTokenDataResponse:(NSData *)data {
NSString *stringResponse = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
SBJsonParser *parser=[[SBJsonParser alloc]init];
NSDictionary *objDictionaryForStringResponse = [parser objectWithString:stringResponse];
[stringResponse release];
[parser release];
MyListRequest *objMyListRequest = [[[MyListRequest alloc] init] autorelease];
objMyListRequest.myRequiredValueToGetMyDataResponse = [objDictionaryForStringResponse objectForKey:#"Data"];
// Initiate GetMyDataResponse request
[objMyListRequest initiateGetMyDataRequest:self requestSelector:#selector(getMyDataResponse:)];
}
(void) getMyDataResponse:(NSData *)data {
NSString *stringResponse = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
SBJsonParser *parser=[[SBJsonParser alloc]init];
NSDictionary *objGetMyDataRootDictionary = [parser objectWithString:stringResponse];
[stringResponse release];
[parser release];
NSDictionary *dataElements=[objGetMyDataRootDictionary objectForKey:#"Data"];
Wish *objMyData;
for (NSDictionary* objGetMyDataRootDictionary in dataElements) {
objMyData = [[Wish alloc]init];
//add different elements from dataElements into member variables of object objWish
[self.myDataArray addObject:objMyData];
[objMyData release];
}
[self.myDataTableView reloadData];
}
This method lies in MyDataRequest class:
(void)initiateGetMyDataRequest:(id)requestDelegate requestSelector:(SEL)requestSelector{
// Set the delegate and selector
self.delegate = requestDelegate;
self.callback = requestSelector;
NSString* unescapedUrlString = [NSString stringWithFormat:#"http://test.mytesturl.com/core.svc/alldata/My/get/All/?token=%#&search=&page=1",myRequiredtokenparameter];
[self request:url];
}
I need to send multiple requests to the same url (with different parameter value i.e. value of page number) to fetch the results. How may I achieve it given the above scenario? The calls must be asynchronous.
How should I make the actual flow between all these calls? How may I get the data of "all the pages" asynchronously?
I think you are looking for a operation queue. I use ASIHTTPRequests in my apps and they work.
If you want to use this library, here's the link how to use it: Show UIActivityIndicatorView when loading NSString from Web

iPad background thread NSAutoReleasePool confusion about [object release]

I have an app where I import a bunch of data and I want to to happen on a background thread. This was working well for a small amount of data but now it seems I am running into this error midway through the parsing and importing of large amounts of my data into Core Data:
Program received signal: “EXC_BAD_ACCESS”.
Here is the call to the background thread:
[self performSelectorInBackground:#selector(importAllData) withObject:nil];
Here is an example of what I am doing in my code:
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
// load manufactuers from DB
NSFetchRequest *crequest = [[NSFetchRequest alloc] init];
NSEntityDescription *manufacturer = [NSEntityDescription entityForName:#"Manufacturer" inManagedObjectContext:managedObjectContext];
[crequest setEntity:manufacturer];
NSError *cerror=nil;;
NSArray *manufacturers = [[managedObjectContext executeFetchRequest:crequest error:&cerror]mutableCopy];
[crequest release];
for (int m=0; m < [manufacturers count]; m++) {
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:kClientListURL, [[manufacturers objectAtIndex:m]ManufacturerID]]];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setNumberOfTimesToRetryOnTimeout:2];
[request startSynchronous];
NSError *error = [request error];
if (!error) {
NSString *responseString = [request responseString];
NSArray *items = [responseString JSONValue];
NSNumberFormatter *f = [[NSNumberFormatter alloc] init];
NSNumberFormatter *dec = [[NSNumberFormatter alloc]init];
[dec setNumberStyle:NSNumberFormatterDecimalStyle];
for (int i = 0; i < [items count]; i++)
{
Client *entity = (Client*) [NSEntityDescription insertNewObjectForEntityForName:#"Client" inManagedObjectContext:managedObjectContext];
[entity setCompanyName:[[items objectAtIndex:i] objectForKey:#"CompanyName"]];
// set a bunch of other properties
[entity setManufacturer:[manufacturers objectAtIndex:m]];
statusMessage = [NSString stringWithFormat:#"importing client: %#", entity.CompanyName];
[self performSelectorOnMainThread:#selector(setStatus) withObject:nil waitUntilDone:YES];
}
[f release];
[dec release];
} else {
NSLog(#"%#",[NSString stringWithFormat:#"JSON parsing failed: %#", [error localizedDescription]]);
}
NSError *entityerror;
if (![managedObjectContext save:&entityerror]) {
// //Handle the error.
NSLog(#"\n\n\n Error saving clients: %# \n\n\n\n",entityerror);
}
}
//More data importing code
[pool release];
As I said this was working fine for a small amount of data but now in he simulator it throws bad access errors at random points.
Then I read this article which confused me:
http://www.cocoadev.com/index.pl?DebuggingAutorelease
Do I not need to release my objects if they are inside of the NSAutoReleasePool? Am I causing them to be released twice at some point?
If I remove the release statements I get potential leaks errors when building using Command-Shift-A?
The rules are:
If you are the owner, you need to either call [object release] or [object autorelease]. The later will delegate the release call to the NSAutoReleasePool, when the pool gets flushed or released.
You are an owner if you called [object retain] or if you got the object through a method that has either alloc or copy in its name.
If you got the object from a method that has neither alloc nor copy in its name and you haven't retained it you must not call release or autorelease on it (except in the very rare case that the documentations states that you are the owner).
So yes, if you got an autoreleased object and you call release on it you are over-releasing it. The effects are various but almost always lead to a crash, normally with EXC_BAD_ACCESS. You can debug this by setting the NSZombieEnabled environment variable. That way, whenever an object is deallocated it is replaced by a dummy that knows what object lived at that address before and can then tell you which object got over-released.
But reading through your code I didn't spot any immediately obvious problem, but I don't know Core Data (which you seem to be using) well enough. Another possibility is a threading/timing issue. Also, you said that's not the whole method ? Maybe the error is in the missing part.
I am assuming that importAllData is the method you are using. If so, you are missing the : at the end in your call.
[self performSelectorInBackground:#selector(importAllData) withObject:nil];
should be
[self performSelectorInBackground:#selector(importAllData:) withObject:nil];
Hope that helps!

Why is my NSURLResponse leaking memory when archived?

I found a leak in my code where archiving and unarchiving an NSURLResponse was causing a leak, and I can't figure out why.
- (void)doStuffWithResponse:(NSURLResponse *)response {
NSMutableData *saveData = [[NSMutableData alloc] init];
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:saveData];
[archiver encodeObject:response forKey:#"response"];
// Encode other objects
[archiver finishDecoding];
[archiver release];
// Write data to disk
// release, clean up objects
}
- (void)retrieveResponseFromPath:(NSString *)path {
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:[NSData dataWithContentsOfFile:path]];
NSURLResponse *response = [unarchiver decodeObjectForKey:#"response"];
// The above line leaks!!
// decode other objects
// clean up memory and do other operations
}
Instruments reports a leak when I unarchive the NSURLResponse. If I comment that out and do not use it, there is no leak. What was interesting was instead I saved the pieces of the NSURLResponse there is no leak:
// Encode:
[archiver encodeObject:[response URL] forKey:#"URL"];
[archiver encodeObject:[response MIMEType] forKey:#"MIMEType"];
[archiver encodeObject:[NSNumber numberWithLongLong:[response expectedContentLength]] forKey:#"expectedContentLength"];
[archiver encodeObject:[response textEncodingName] forKey:#"textEncodingName"];
// Decode:
NSURL *url = [unarchiver decodeObjectForKey:#"URL"];
NSString *mimeType = [unarchiver decodeObjectForIKey:#"MIMEType"];
NSNumber *expectedContentLength = [unarchiver decodeObjectForKey:#"expectedContentLength"];
NSString *textEncodingName = [unarchiver decodeObjectForKey:#"textEncodingName"];
NSURLResponse* response = [[NSHTTPURLResponse alloc] initWithURL:url MIMEType:mimeType expectedContentLength:[expectedContentLength longLongValue] textEncodingName:textEncodingName];
Anyone know why this is? Is there a bug with archiving NSURLResponse or am I doing something wrong?
Memory management in Objective-C is as simple as knowing that any time you call something that has "alloc", "new", or "copy" in the method name (or if you retain it), then you must release it at some point. See this for more info: http://developer.apple.com/mac/library/documentation/cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html
In your case, it appears that you call alloc to create an NSMutableData, but never release it (So [saveData release] at the end of doStuffWithResponse: may resolve at least one leak). From this code, this also appears to be the case with your alloc'ed NSKeyedUnarchiver and your alloc'ed NSURLResponse.
If you're not holding onto the value, like in an ivar, you can also just call autorelease right after alloc'ing, or use the class's autoreleased creators if available (e.g. [NSString stringWithFormat:] instead of [[NSString alloc] initWithFormat:]).
Selecting Build > Build and Analyze may also reveal such issues.

Calculating sum for decimal values via Core Data not working properly?

first time I post to this round, so please bear with me if I don't follow all the rules properly.
I am writing an app for the iPhone (OS 3.1) and am trying to write some code which lets me add decimals. I have a Core Data entity called SimpleItem with a amount attribute. Here is the test case I wrote:
// Create and configure objects
SimpleItem *si1 = [self createSimpleItem:#"si1"];
si1.amount = [NSDecimalNumber decimalNumberWithMantissa:1000 exponent:0 isNegative:NO];
SimpleItem *si2 = [self createSimpleItem:#"s12"];
si2.amount = [NSDecimalNumber decimalNumberWithMantissa:2000 exponent:0 isNegative:NO];
// Need to save prior to fetching results with NSDictionaryResultType (known limitation)
[self save];
// Describe fetch request
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:#"SimpleItem" inManagedObjectContext:self.context];
[request setEntity:entityDescription];
[request setResultType:NSDictionaryResultType];
NSExpression *keyPathExpression = [NSExpression expressionForKeyPath:#"amount"];
// For whatever reason, evaluating this expression here is absolutely not working. Probably decimals aren't handled properly.
NSExpression *sumAmountExpression = [NSExpression
expressionForFunction:#"max:"
arguments:[NSArray arrayWithObject:keyPathExpression]];
NSExpressionDescription *expressionDescription = [[NSExpressionDescription alloc] init];
[expressionDescription setName:#"amount"];
[expressionDescription setExpression:sumAmountExpression];
[expressionDescription setExpressionResultType:NSDecimalAttributeType];
[request setPropertiesToFetch:[NSArray arrayWithObject:expressionDescription]];
// Fetch the amounts
NSError *error = nil;
NSArray *array = [self.context executeFetchRequest:request error:&error];
If I execute this code through otest and debug it, I get an exception when the fetch request is executed: "-[NSDecimalNumber count]: unrecognized selector sent to instance."
Just evaluating the keyPathExpression without the aggregate function works fine, though.
The reference documentation shows exactly the same example so I'm wondering what I am doing wrong. Or could this be just a bug?
All the best,
Harald
Copying your given source to a new iPhone project and running that in the simulator worked fine here. I was compiling against the 3.1.2 SDK on Snow Leopard.
This is what I used for the data model:
model description http://homepage.mac.com/aclark78/.Public/Pictures/test%20model.png
There must be something else going on causing your issue. Can you describe your model or simplify it further?
I think I had this problem before. IIRC, the problem is that you've set your fetch result type to NSDictionaryResultType but you're receiving it in an NSArray. Try switching the fetch result type to NSManagedObjectResultType which does return an array. All the examples in the docs use the default NSManagedObjectResultType.
In any case, the error message clearly results from an NSDecimal object being sent an array's count message. You could confirm this by trapping the result in an id. eg:
id *genericObj = [self.context executeFetchRequest:request error:&error];
NSLog("returned object=%#",genericObj);
NSLog("returned object class=%#",[genericObj class]);
Thanks for letting me know. The thing is that I actually don't want to use managed objects. After all, I am interested in the amounts only and this is what I get with the dictionary.
Also, trying to investigate the issue as you described didn't work as executing the fetch request immediately fails and I don't get anything back.
Any other ideas? Is there any other possibility to get aggregate values? Any "best practices"? At the moment I do the following (continuation of the code above):
NSExpressionDescription *expressionDescription = [[NSExpressionDescription alloc] init];
[expressionDescription setName:#"amount"];
[expressionDescription setExpression:keyPathExpression];
[expressionDescription setExpressionResultType:NSDecimalAttributeType];
[request setPropertiesToFetch:[NSArray arrayWithObject:expressionDescription]];
// Fetch the amounts
NSError *error = nil;
NSArray *array = [self.context executeFetchRequest:request error:&error];
if (array == nil) {
STFail(#"Fetch request could not be completed: %#", [error localizedDescription]);
}
STAssertEquals([array count], (NSUInteger) 2, #"Number of fetched objects != 2");
// Manually calculate the sum
NSDecimalNumber *sum = nil;
for (NSDictionary * dictionary in array) {
NSDecimalNumber *amount = (NSDecimalNumber *) [dictionary valueForKey:#"amount"];
if (!sum) {
sum = amount;
} else {
sum = [sum decimalNumberByAdding:amount];
}
}
STAssertNotNil(sum, #"Sum is nil");
STAssertTrue([sum isEqualToNumber:[NSDecimalNumber decimalNumberWithMantissa:3000 exponent:0 isNegative:NO]],
#"Sum != 3000: %#", sum);
Regards,
Harald