I am making an iPhone app and I am loading information from a server. I send NSURLRequest to the server and get back a NSString value. This is working fine and the value I am getting back is the correct one. The problem is that when I try to add the value for the variable to a NSMutableDictionary I have made to store the values, it doesn't work. When I debug and look at the values of the NSMutableDictionary in Xcode it says 0 key/value pairs right after the line where I add the values. This is what my code looks like:
NSArray *varsToLoad = [fixedData objectForKey:#"varsToLoad"];
NSError *error;
for(NSString *var in varsToLoad){
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL: someURL]];
[request setHTTPMethod:#"POST"];
NSMutableString *file = [NSMutableString stringWithString:#"file="];
NSString *file1 = [file stringByAppendingString:var];
NSString *file2 = [file1 stringByAppendingString:#".txt"];
[request setHTTPBody:[file2 dataUsingEncoding:NSUTF8StringEncoding]];
NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:&error];
NSString *value = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];
[varsLoaded setObject:value forKey:var];
}
varsLoaded is declared at the #implementation and is a NSMutableDictionary.
The problem may be that you haven't initialized your varsLoaded by saying self.varsLoaded = [NSMutableDictionary dictionary];
So you're adding objects to a non-existing dictionary, but you're not getting an exception because this is normal in objective-c :)
You should really check the response before processing any further. Wrap it in something like this:
if (response == nil) {
// Check for problems
}
else {
NSString *value = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];
[varsLoaded setObject:value forKey:var];
}
Change the first line of your code from NSArray to NSMutableArray and see if you have better luck.
It doesn't matter that you declared your varsLoaded as a NSMutableDictionary somewhere else... in the local context of that code above, the compiler believes varsToLoad is a immutable array and probably isn't even compiling your setObject: forKey: line. You're not getting warnings in the build log or in the console while you're running??
Related
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.
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.
So far I've discovered in JSON that everything enclosed in { } are objects (objC : NSDictionary) and anything enclosed in [ ] is an array (objC : NSArray).
I've read and re-read this article about the subject>
How to parse JSON into Objective C - SBJSON
I have a .json file with the data modeled like this:
http://elbee101.com/dummySchedule.json
...and now for the code:
SBJSON *parser = [[SBJSON alloc] init];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://elbee101.com/dummySchedule.json"]];
NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSString *json_string = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];
NSDictionary *schedule = [parser objectWithString:json_string error:nil];
NSDictionary *day = [schedule objectForKey:#"day"];
NSArray *myList = [day objectForKey:#"name"];
NSLog(#"myList %#", myList);
NSArray *numLaps = [myList objectAtIndex:0];
NSLog(#"numlaps%# ", numLaps);
I'm getting "myList (null)" and "numlaps (null)" from the above code?!#
The question: Can somebody please set me straight on the ordering of objects and arrays with respect to my json data? I want to drill down the tree so that I can access the 'day name', 'session starttime/endtime/sessionname', 'numlaps' & 'class' but I can't seem to get past the 'day' object/array(?)
What you're referring to as schedule is the object enclosed in the outermost {}. Try this:
NSDictionary *json = [parser objectWithString:json_string error:nil];
NSDictionary *schedule = [json objectForKey:#"schedule"];
Then continue as before.
Also, if you're on iOS 5 you can use the NSJSONSerialization class -- using it is pretty much the same, you might get better performance, and you don't have to worry about the hassles of using a third-party library.
call this where ever u need to parse
NSMutableArray *arr=[[NSMutableArray alloc] init];
arr=[[Headparse getArrayFromUrl:#"http://elbee101.com/dummySchedule.json"] retain];
NSLog(#"%#",[arr description]);
[arr release];
write this method as custom class use when ever you need
+(NSMutableArray *) getArrayFromUrl: (NSString *)actionType
{
NSMutableData *responseData1= [NSMutableData data] ;
responseData1 = [NSMutableData dataWithContentsOfURL:[NSURL URLWithString:actionType]];
// NSLog(#"%#",responseData1);
NSString *responseString1 = [[NSString alloc] initWithData:responseData1 encoding:NSUTF8StringEncoding];
//NSLog(#"REs:-->%#",responseString1);
//[responseData1 release];
responseData1 = nil;
NSMutableArray *responseArray = [[NSMutableArray alloc]init];
responseArray = (NSMutableArray *)[responseString1 JSONValue];
// NSLog(#"ghfchfvghv%#",responseArray);
[responseString1 release];
return responseArray;
}
This is how i use NSJsonSerialization for parsing the json object.
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:#"http://elbee101.com/dummySchedule.json"]];
NSError *err;
NSDictionary* json = [NSJSONSerialization
JSONObjectWithData:data
options:kNilOptions
error:&err]; //
NSDictionary *schedule_dict = [json objectForKey:#"schedule"];
NSArray *days = [schedule_dict objectForKey:#"day"];//Days Array from day Object
NSDictionary *dayOne = [days objectAtIndex:0];
NSDictionary *dayTwo = [days objectAtIndex:1];
NSLog(#"THE DAY ONE : %#",dayOne);
NSLog(#"THE DAY TWO : %#",dayTwo);
Hope this may help you ....Note : If you don't want to go with NSJsonSerailization(consider reading of this) ,but still the parsing of json data like above will applicable in your case too.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Tutorials for using HTTP POST and GET on the iPhone in Objective-C
Is there away to create an NSArray with the correct information like id = 1, name = #"John", score = 100 then send it and receive a response from the server?
Maybe display it inside an NSLog();
Can anyone help answer this question by linking me to a good tutorial, I don't want to use ASIHTTPRequest either. I know it would be much simpler but if there is away to do something without using a load of prewritten code id rather learn how to make something using the functionality the the foundation framework offers before going off using someone elses classes.
What you're looking for is NSMutableURLRequest and the addValue:forHTTPHeaderField method.
Create the request with the URL you wish to communicate with. Load the values you wish to transmit into the header or into the HTTPBody, set your HTTPMethod and then use a NSURLConnection method to send and receive the response.
As for an array with the information you could simply enumerate through the array and add the values to the HTTPHeaderFields. It really depends on what the server is setup to receive.
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/URLLoadingSystem/URLLoadingSystem.html#//apple_ref/doc/uid/10000165i
Has more information.
NSString *urlString = #"http://yoururl.com";
NSURL *url = [NSUL URLWithString:urlString];
NSMutalbeURLRequest *request = [NSMutableURLRequest requestWithURL:url];
NSDictionary *headerInformation = [NSDictionary dictionaryWithObjectsAndKeys:#"1",#"id",#"John",#"name",#"100",#"score", nil];
for (NSString *key in [headerInformation allKeys])
{
[request addValue:[dict valueForKey:key] forHTTPHeaderField:key];
}
NSHTTPURLResponse *response = nil;
NSError *error = nil;
// this will perform a synchronous GET operation passing the values you specified in the header (typically you want asynchrounous, but for simplicity of answering the question it works)
NSData *responseData = [NSURLConnection sendSynchronousRequest:request reuturningResponse:&response error:&error];
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
NSLog(#"Response: %#", responseString);
[responseString release];
It might be easier to just use NSData to send a url request and store the response then to reinvent the wheel. Here is some code similar to something in my production project:
+ (NSData *)getProfiles {
NSString *token = [[NSUserDefaults standardUserDefaults] objectForKey:#"token"];
// Create string of the URL
NSString *serviceURL = [NSString stringWithFormat:#"http://www.myurlhere.com/getProfiles.php?token=%#", token];
NSLog(#"Service URL : %#", serviceURL);
// Create a NSURL out of the string created earlier. Use NSASCIIStringEncoding to make it properly URL encoded (replaces " " with "+", etc)
NSURL *URL = [NSURL URLWithString:[serviceURL stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding]];
// Request the url and store the response into NSData
NSData *data = [NSData dataWithContentsOfURL:URL];
if (!data) {
return nil;
}
// Since I know the response will be 100% strings, convert the NSData to NSString
NSString *response = [[[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding] autorelease];
// Test response and return a string that an XML Parser can parse
if (![response isEqualToString:#"UNAUTHORIZED"]) {
response = [response stringByReplacingOccurrencesOfString:#"&" withString:#"&"];
data = [response dataUsingEncoding:NSASCIIStringEncoding];
return data;
} else {
return nil;
}
}
NSLog output:
[Line: 476] +[WebSupport getProfiles]: Service URL : http://www.myurlhere.com/getProfiles.php?token=abcdef0123456789abcdef0123456789
Am a beginner in objective C, i am implementing a function that would query a web server and display the returning string in console. I am calling the function (getDatafromServer) repeatedly in a loop. The problem is that the first time am getting the value whereas the other times, it returns me a (null) in console... I've searched about memory management and check out on the forums but none have worked. Can you please guys tell me where am wrong in the codes below? Thanks in advance....
#implementation RequestThread
+(void)startthread:(id)param{
while (true) {
//NSLog(#"Test threads");
sleep(5);
NSLog(#"%#",[self getDatafromServer]);
}
}
+(NSString *) getDatafromServer{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *myRequestString = #"name=Hello%20&email=essssss#live.com";
NSData *myRequestData = [NSData dataWithBytes:[myRequestString UTF8String] length:[myRequestString length]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL: [NSURL URLWithString:#"http://192.168.1.32/gs/includes/widget/getcalls.php?user=asdasd&passw=asdasdasd"]];
[request setHTTPMethod:#"POST"];
[request setHTTPBody: myRequestData];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"content-type"];
NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSString *myString = [NSString stringWithUTF8String:[returnData bytes]];
[myRequestString release];
[request release];
[returnData release];
return myString;
[pool release];
}
#end
You have a problem with the autorelease pool. Firstly, as Nickolay has said, the release never happens because it is after the return. I'm amazed you aren't seeing compiler warnings. Make sure you have -Wall set in "other warning flags" and you have the "Run static analyzer" build option set.
Since you want to use the returned string outside of the function, the autorelease pool must also be outside the function, or the string may be deallocated before your log gets to it. Your code structure should look more like:
+(void)startthread:(id)param
{
while (true)
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
//NSLog(#"Test threads");
sleep(5);
NSLog(#"%#",[self getDatafromServer]);
[pool drain]; // use instead of release in case you move to GC
}
}
The other problem you have is that you are not doing any error checking. How can you be sure that:
the request to the server is working?
the response from the server is encoded as UTF-8.
You need to check if returnData is nil after you get it and you need to examine the NSError if it is. So you need something like this:
NSError* error = nil;
NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:&error];
if (returnData == nil)
{
the error object will be set and contain useful info.
}
You also need to check if myString is nil. If it is, it will be because the response was not encoded as UTF-8. With HTTP the default encoding is not UTF-8, it is ISO-8859-1. Also, the body of the response might not be character data at all. You need to examine the response to find out how to decode the data. So the code snippet I posted above should really look like:
NSError* error = nil;
NSURLResponse* response = nil;
NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if (returnData == nil)
{
// the error object will be set and contain useful info.
}
else
{
// You can get the content type and encoding from the response here.
}
Edit
Also, your code violates the Memory Management Rules. You did not obtain myRequestString or returnData through alloc, copy or new, neither have you retained them, so you must not release them.
That's bad idea to use autorelease pool in this function, and release it after 'return'.
Remove pool and everything should be ok.