NSDictionary selector error NSString with spaces - objective-c

-(void)messageSend:(NSString *)message;
{
NSLog(#"messageSend");
urlString = [[NSString alloc] initWithFormat:#"http://someaddress/message/send?from=%#&msg=%#&latitude=0&longitude=0",appDelegate.userName,message];
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] initWithDictionary:[self request:urlString]];
NSLog(#"Dictionary response");
if ([dictionary count] > 0)
{
if ([[dictionary objectForKey:#"send"] isEqualToString:#"OK"] )
{
NSLog(#"envio de mensagem de %# Ok: %#",appDelegate.userName,message);
}
}
[urlString release];
[dictionary release];
}
Gives an error of -[__NSArrayM getObjects:andKeys:]: unrecognized selector sent to instance. After some testing with NSLogs, the line
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] initWithDictionary:[self request:urlString]];
is the culprit, witch is calling this method:
-(NSDictionary *)request:(NSString *)requestString
{
url =[[NSURL alloc] initWithString:requestString];
request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:10];
error = [[NSError alloc] init];
responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
[responseData retain];
NSString *tempString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
NSMutableDictionary *tempDict= [[[NSMutableDictionary alloc] init] autorelease];
if (request)
{
Parser *parser = [[Parser alloc] init];
tempDict = [parser readXMLString:tempString];
for (id key in tempDict)
{
NSLog(#"%# is %#",key,[tempDict objectForKey:key]);
}
}
[url release];
[error release];
[responseData release];
[tempString release];
return tempDict;
}
And it happens when the string of the message has spaces.
But it was not happening before.

I see a few peculiarities:
error = [[NSError alloc] init];
responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
Usually, you simply do:
NSError *error = nil;
responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
The error variable will be filled with the address of an autoreleased error object if there is an error, otherwise it should remain nil. Do not allocate one yourself, since you could be releasing the wrong one (the one returned by the sendSynchronousRequest:etc. method). This could cause an over-release at the end of your method.
NSMutableDictionary *tempDict= [[[NSMutableDictionary alloc] init] autorelease];
if (request)
{
Parser *parser = [[Parser alloc] init];
tempDict = [parser readXMLString:tempString];
In the if-block, you are overwriting the pointer to the tempDict you just created. That is a memory leak (but not the cause of your problem). Update: the one you created is autoreleased. No leak.
You also don't release the Parser used in the if-block (and local to it).
You never check the value of error to see if actually an error occurred. As I said, you should set error to nil before the invocation of sendSynchronousRequest:etc. and then check if it is still nil, and if not, react accordingly:
if (error)
{
// error handling
}
What is the return type of [parser readXMLString: tempString];? Could it be an array and not a dictionary? E.g. an array of dictionaries?
Add an
NSLog(#"%#", tempDict);
in request:, before you return the tempDict. What does it show?
The getObjects:AndKeys: is probably called in -[NSMutableDictionary initWithDictionary:]. Apparently the real type of the dictionary returned by request: is not a dictionary, it is an array. See what I wrote above.

The culprit is the line tempDict = [parser readXMLString:tempString]. In fact, this means your previous creation of a [[[NSMutableDictionary alloc] init] autorelease] is pointless, as it will just be overwritten by the return value of [parser readXMLString:tempString]. In any case, it appears the -readXMLString: method is returning an NSArray instead of an NSDictionary.

Related

JSON to Objective-C Dictionary

I'm making URL Request to an API but I dont know how to render the JSON, It generates an array of multiple users like this [{"user": "value"}, {"user":"value"}] and I was trying to use a TableView so I need an NSDictionary but i think is better to render a JSON like {users: [{"user": "value"}, {"user":"value"}]}. I have this code to make the request
#import "JSONKit.h"
NSError *error = nil;
NSURLResponse *response = nil;
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL: [NSURL URLWithString: #"http://localhost:3000/getusers"]];
[request setHTTPMethod:#"GET"];
NSData *jsonData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
users = [[jsonData objectFromJSONData] objectForKey:#"users"];
usersKeys = [users allKeys];
but I'm getting this error
2012-09-16 18:51:11.360 tableview[2979:c07] -[JKArray allKeys]: unrecognized selector sent to instance 0x6d30180
2012-09-16 18:51:11.362 tableview[2979:c07] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[JKArray allKeys]: unrecognized selector sent to instance 0x6d30180'
I dont really know how to accomplish this so any help is useful, thanks
You are getting that error because whatever got parsed out of "jsonData" isn't necessarily what you expected (i.e. a dictionary).
Perhaps you need some error checking in that code of yours.
For example:
NSData *jsonData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if(jsonData)
{
id objectReturnedFromJSON = [jsonData objectFromJSONData];
if(objectReturnedFromJSON)
{
if([objectReturnedFromJSON isKindOfClass:[NSDictonary class]])
{
NSDictionary * dictionaryFromJSON = (NSDictionary *)objectReturnedFromJSON;
// assuming you declared "users" & "usersKeys" in your interface,
// or somewhere else in this method
users = [dictionaryFromJSON objectForKey:#"users"];
if(users)
{
usersKeys = [users allKeys];
} else {
NSLog( #"no users in the json data");
}
} else {
NSLog( #"no dictionary from the data returned by the server... check the data to see if it's valid JSON");
}
} else {
NSLog( #"nothing valid returned from the server...");
}
} else {
NSLog( #"no data back from the server");
}
I was thinking on something like this
NSError *error = nil;
NSURLResponse *response = nil;
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL: [NSURL URLWithString: #"http://localhost:3000/getusers"]];
[request setHTTPMethod:#"GET"];
NSData *jsonData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
JSONDecoder *decoder = [[JSONDecoder alloc]
initWithParseOptions:JKParseOptionNone];
NSArray *json = [decoder objectWithData:jsonData];
NSMutableArray *objects = [[NSMutableArray alloc] init];
NSMutableArray *keys = [[NSMutableArray alloc] init];
for (NSDictionary *user in json) {
[objects addObject:[user objectForKey:#"user" ]];
[keys addObject:[user objectForKey:#"value" ]];
}
users = [[NSDictionary alloc] initWithObjects:objects forKeys:keys];
NSLog(#"users: %#", users);
usersKeys = [users allKeys];
But it doesnt look efficient for many items or im wrong?

RaptureXML weird behaviour

I am getting an error (well it doesn't shows, just crashes out of app, no info on console)
that seems to happen whenever i call the method Iterate from RXML's rootXML:
-(void)valueSearch {
//FIRST CONNECTION
NSString *serverAddress = #"http://www.commix.com.br/clientes/grupoglobo/apple/valor.xml";
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:serverAddress]
cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData
timeoutInterval:10];
NSError *requestError;
NSURLResponse *urlResponse = nil;
response = [NSURLConnection sendSynchronousRequest:request returningResponse:&urlResponse error:&requestError];
//SECOND CONNECTION - Just an encapsulated form of the first, since i use it in other parts
// of the code
response = [self requestWithParameters:#"valor.xml"];
//i just uncommented both. but actually only one (connection) runs.
//Creation of the rooXML so i can grab the info i need
RXMLElement *rootXML = [RXMLElement elementFromXMLData:response];
//This array is where i'll keep the info from the files.
//it`s deallocated at the end in dealloc
searchResult = [[NSMutableArray alloc] init];
//This is the culprit. Atleast it seems so, since putting NSLog before and after
//revealed so.
[rootXML iterate:#"valor" usingBlock: ^(RXMLElement *valor) {
NSLog(#"valor: %#", [valor child:#"nome"].text);
[searchResult addObject:[valor child:#"nome"].text];
}];
}
The thing is, when i comment the requestWithParametersand use the normal non-encapsulated style (//FIRST CONNECTION) i don't get errors. But if i use the second, when the program reaches [rootXML iterate: [...]]it crashes there without warning.
using RaptureXML: https://github.com/ZaBlanc/RaptureXML
It also happens in another part of the code:
-(void)vehicleSearch {
NSString *path = [[NSBundle mainBundle] pathForResource:#"idArray" ofType:#"plist"];
NSMutableArray *idArray = [[NSMutableArray alloc] initWithContentsOfFile:path];
NSMutableString *serverAddress = (#"http://www.commix.com.br/clientes/grupoglobo/apple/modelo.php?marc=%#",[idArray objectAtIndex:0]);
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:serverAddress]
cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData
timeoutInterval:10];
NSError *requestError;
NSURLResponse *urlResponse = nil;
response = [NSURLConnection sendSynchronousRequest:request returningResponse:&urlResponse error:&requestError];
RXMLElement *rootXML = [RXMLElement elementFromXMLData:response];
searchResult = [[NSMutableArray alloc] init];
[rootXML iterate:#"modelo" usingBlock: ^(RXMLElement *modelo) {
NSLog(#"modelo: %#", [modelo child:#"nome"].text);
[searchResult addObject:[modelo child:#"nome"].text];
}];
[idArray release];
}
Happens at the same line [rootXML iterate:].
Sorry for leaks and stuff, i'm inexperienced (thats why i'm here), Thanks!
EDIT:
ACTUALLY the culprit is the line
NSMutableString *serverAddress = (#"http://www.commix.com.br/clientes/grupoglobo/apple/modelo.php?marc=%#",[idArray objectAtIndex:0]);
if i pass the parameter directly, without variables, it works:
NSMutableString *serverAddress = (#"http://www.commix.com.br/clientes/grupoglobo/apple/modelo.php?marc=4");
it shows correctly.
Are you sure that ,[idArray objectAtIndex:0] is an NSString?
Try to use
[NSString stringWithFormat:#"http://www.commix.com.br/clientes/grupoglobo/apple/modelo.php?marc=%#",[idArray objectAtIndex:0]];`
Or even
[NSString stringWithFormat:#"http://www.commix.com.br/clientes/grupoglobo/apple/modelo.php?marc=%#",[[idArray objectAtIndex:0]stringValue]];
response = [self requestWithParameters:#"valor.xml"];
if response is a property use self.response otherwise you will have memory leak issues.

Get web service response data

I have made this so far. It's code that will make a json String request with an http Header. When i run this code i get no errors. But i get a Expression result unused warning. I should get a response from the web service after sending this http header.
code:
- (void)viewDidLoad
{
[super viewDidLoad];
NSString *nid = #"";
NSString *vocab = #"";
NSString *inturl = #"testoverview";
NSString *mail = #"chh#fbr.dk";
NSString *md5pw = #"4d57e7ef1b7c3f431aca424764e9d786";
NSDictionary *jsonDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
nid, #"nid",
vocab, #"vocab",
inturl, #"inturl",
mail, #"mail",
md5pw, #"md5pw",nil];
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:jsonDictionary options:NSJSONWritingPrettyPrinted error:&error];
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
if (!jsonData) {
NSLog(#"Got an error; %#", error);
} else if(jsonData) {
NSString *url = #"http://www.taenk.dk/services/mobile";
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url] cachePolicy:NSURLCacheStorageAllowed timeoutInterval:30.0];
[request setValue:jsonString forHTTPHeaderField:#"X-FBR-App"];
[[NSURLConnection alloc] initWithRequest:request delegate:self]; <-- this line triggers the warning: "Expression result unused"
NSLog(#"jsonString %#", jsonString);
}
Can anybody clarify 2 things for me:
Does this trigger a response as soon as the request to the web service?
If yes, how do i print this result out?
You need to assign the result to a variable like
NSURLConnection *con = [[NSURLConnection alloc] initWithRequest:...
for later use (e.g. [con cancel];)
Then you should at least implement the delegate method connection:didFailWithError:. In the class reference I don't see the connection:didFinishLoading... anymore. Can you use the sendSynchronousRequest:returningResponse:error: instead, then you'll have the result, be it positive or negative.
This is how I retrieved the data (this version is without ARC):
- (void) connection :(NSURLConnection *)conn didReceiveData :(NSData *)data {
NSString *msg = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
[self checkAutoMailReply:msg];
[msg release];
}
msg contains the pure response data, no header or such.

Searching a custom tableviewCell

I want to do a search in a tableview. But in this table view I work with a custom tableview Cell. So for the data part. I select in a view a categorie. Then in the next view I get all the products within this categorie.
I followed a tutorial and implemented all the methods.
This is my function for getting the products.
-(void) fillArrayProducts:(NSString *)cat{
NSMutableString *postString = [NSMutableString stringWithString:kGETProducts];
[postString appendString:[NSString stringWithFormat:#"?%#=%#",#"Pro_cat",cat]];
[postString setString:[postString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSMutableURLRequest *request= [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:postString]];
[request setHTTPMethod:#"POST"];
postConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:postString]];
NSError *error;
json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
arrayProducts = [[NSMutableArray alloc] init];
copyArrayProducts = [[NSMutableArray alloc] init];
arrayProductNaam = [[NSMutableArray alloc] init];
for (int i=0; i<[json count]; i++) {
arrayProduct = [[NSMutableArray alloc] init];
[arrayProduct addObject:[json objectAtIndex:i]];
[arrayProducts addObject:arrayProduct];
[arrayProductNaam addObject:[[[arrayProducts valueForKey:#"Pro_naam"] objectAtIndex:i]objectAtIndex:0]];
[copyArrayProducts addObject:arrayProduct];
}
NSDictionary *productsDict = [NSDictionary dictionaryWithObject:arrayProductNaam forKey:#"Products"];
NSLog(#"%#",arrayProductNaam);
}
No what I'm doing. I have an array 'arrayProducts' in this array I put arrays from 'arrayProduct'. In arrayProduct you can find Pro_id,Pro_naam,Pro_prijs. But I only want to search on Pro_naam. So I fill also an array (arrayProductNaam) with only the products names.
So here is the part were I do my search.
- (void) searchTableView {
NSString *searchText = searchbar.text;
NSMutableArray *searchArray = [[NSMutableArray alloc] init];
for (NSDictionary *dictionary in arrayProductNaam)
{
NSArray *array = [dictionary objectForKey:#"Pro_naam"];
[searchArray addObjectsFromArray:array];
}
for (NSString *sTemp in searchArray)
{
NSRange titleResultsRange = [sTemp rangeOfString:searchText options:NSCaseInsensitiveSearch];
if (titleResultsRange.length > 0)
[copyArrayProducts addObject:sTemp];
}
}
I think that it's here were I getting this error.
2012-02-02 13:22:40.958 MamzelBestelling2[23727:f803] -[__NSCFString
objectForKey:]: unrecognized selector sent to instance 0x6c34780
2012-02-02 13:22:40.959 MamzelBestelling2[23727:f803] *** Terminating
app due to uncaught exception 'NSInvalidArgumentException', reason:
'-[__NSCFString objectForKey:]: unrecognized selector sent to instance
0x6c34780'
You are not filling arrayProductNaam with Dictionary. Its filled by NSString. Now, in the searchTableView function you are handling these string members as Dictionaries and hence the problem.
try to NSLog your String Array. so you can get the idea it exist or not
you are trying to get a keyValue from a string not from a dictionary.

Leaks in passing the request using URL at NSString, Objective-C

I getting the leak in this method even the allocated nsstring is released.
Now I am taken stringWithFormat, but still it is showing the leak at "NSData *returnData=...." line
-(BOOL)getTicket:(NSString*)userName passWord:(NSString*)aPassword isLogin:(BOOL)isLogin
{
NSString* str=#"";
if (isLogin == YES)
{
str =[NSString stringWithFormat:#"AGENT=true&LOGIN_ID=%#&PASSWORD=%#",[self _encodeString:userName],[self _encodeString:aPassword]];
}
else if (isLogin == NO)
{
str =[NSString stringWithFormat:#"AGENT=true&LOGIN_ID=%#&PASSWORD=%#",[self _encodeString:userName],[self _encodeString:aPassword]];
}
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:str]
cachePolicy:NSURLRequestReloadIgnoringCacheData
timeoutInterval:25.0];
[request setHTTPMethod: #"POST"];
NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSString *returnString = [[NSString alloc] initWithData:returnData encoding:NSUTF8StringEncoding];
printf("\n returnString in getticket:%s",[returnString UTF8String]);
NSRange textRange;
textRange =[returnString rangeOfString:#"TICKET"];
if(textRange.location != NSNotFound)
{
NSArray* splitValues = [returnString componentsSeparatedByString:#"TICKET="];
NSString* str1 = [splitValues objectAtIndex:1];
NSArray* splitValues1 = [str1 componentsSeparatedByString:#"RESULT"];
NSString* ticket1 = [splitValues1 objectAtIndex:0];
self.ticket = ticket1;
self.isCorrectLogin = YES;
[returnString release];
return YES;
}
else
{
self.isCorrectLogin = NO;
[returnString release];
return NO;
}
return NO;
}
Please help me out of this problem.
Macbirdie is correct in that composing a string using stringByAppendingString: is horribly inefficient. I would suggest using +stringWithFormat: instead.
As for the leak, if the leak is where you say it is, then it might be a leak in the underlying framework (and it might be a false positive). Post the backtrace of the leaked object (which can be had from the Allocations instrument).