Retrieving data from website to iphone - objective-c

I was recently looking at an example from apple about NSURLConnection and I tried implementing it into my code but I am not sure if am I doing it right.
Basically I want the connection to go to my website where I have it connected to a php script that runs the search within my database and then echo's it to the browser. I want the iphone to take the line that is echoed and hold it into a string variable. This is my code.
Is this correctly done?
Thank you in advance
NSString *stringToBeSent= [[NSString alloc] initWithFormat:
#"http:/xxxxx/siteSql.php? data=%#",theData];
NSURLRequest *theRequest=[NSURLRequest requestWithURL:
[NSURL URLWithString:stringToBeSent]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
// create the connection with the request
// and start loading the data
NSURLConnection *theConnection=[[NSURLConnection alloc]
initWithRequest:theRequest delegate:self];
if (theConnection) {
// Create the NSMutableData to hold the received data.
// receivedData is an instance variable declared elsewhere... in my .h file
// NSMutableData *receivedData;
receivedData = [[NSMutableData data] retain];
//convert NSMutableData to a string
NSString *stringData= [[NSString alloc]
initWithData:receivedData encoding:NSUTF8StringEncoding];
NSLog (#"result%#", receivedData);
} else {
// Inform the user that the connection failed.
NSLog(#"failed");
}

I think you might be missing a couple things:
In the method that you use to trigger retrieving the data make sure you release the old data before initializing:
[retrievedData release];
retrievedData=[[NSMutableData alloc] init];
I assume that space is a typo or something for the URL?
You don't need to call requestWithURL:cachePolicy:timeoutInterval: requestWithURL: uses the same defaults as you chose.
The data will come in blocks. You've got to handle that over time, outside this method, using the delegate method connection:didReceiveData:, like so:
- (void)connection:(NSURLConnection *)conn didReceiveData:(NSData *)data
{
[receivedData appendData:data];
}
Similarly, if you want something done with the data once it's all received, you do it in connectionDidFinishLoading: NOTE THAT THE CONNECTION IS RELEASED so it has to be defined in your header as an instance variable (eg. NSURLConnection *connection;
- (void)connectionDidFinishLoading:(NSURLConnection *)conn
{
NSString *stringData= [[NSString alloc]
initWithData:receivedData encoding:NSUTF8StringEncoding];
NSLog(#"Got data? %#", stringData);
[connection release];
connection = nil;
// Do unbelievably cool stuff here //
}
Also look into the other delegate methods like connection:didFailWithError: You probably want to release the connection and stringData there as well, in case of an error.
I hope that's of some help! Enjoy!

Related

Cannot call method in objective c

I'm having difficulty understanding how to call a method. Here's the code:
- (void)beachJSON
{
// Build the string to call Beach API
NSString *urlString = [NSString stringWithFormat:#"http://nrw-bwq-dev-api.azurewebsites.net/api/Pull"];
// Create NSURL string from formatted string
NSURL *url = [NSURL URLWithString:urlString];
// Setup and start async download
NSURLRequest *request = [[NSURLRequest alloc] initWithURL: url];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[connection release];
[request release];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
// Store incoming data into a string
NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
results = [jsonString JSONValue];
}
- (NSArray *)getBeachList {
[self beachJSON];
return results;
}
I call getBeachList from another class to populate 'results', beachJSON is called fine but I need to call
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
Within
- (NSArray *)getBeachList
i.e. right here
- (NSArray *)getBeachList {
[self beachJSON];
//This is where I want to call it to populate results before it is returned
return results;
}
Calling getBeachList will call beachJSON but the connection method will be skipped over leaving 'results' nil
If i try simply putting
[self connection:(NSURLConnection *)connection didReceiveData:(NSData *)data]
I get a expected expression error on that line.
I'm pretty new to objective c so any help would be great.
You don't need to call this method.
It's a delegate method of NSURLConnection.
What you need is to set a delegate for connection and method will be called by connection when it downloads any data.
You should not call connection:didReceiveData: by yourself. This is an event which is only supposed to be fired by the NSURLConnection instance. As far as I can see the only thing you are missing is the start call, which actually makes the NSURLConnection perform the request.
Try this:
NSURLRequest *request = [[NSURLRequest alloc] initWithURL: url];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[connection start];
Then you should see that your NSURLConnection instance will call your implementation of connection:didReceiveData:.
If you want to be sure that your data is fully loaded you should be using this event instead:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
The connection:didReceiveData: will be called multiple times if your data size is large enough. Every time the NSURLConnection receives data it will invoke connection:didReceiveData:. connectionDidFinishLoading: will only be called once when all your data is ready.

NSUrlRequest Not Working Objective C

I am trying to use the code below to 'trigger' the web address. The web server doesn't return any data. But the NSURLConnection is being established.
NSString *serverAddressTest = #"http://domain.com";
NSString *fullWebAddress = [NSString stringWithFormat:#"%#?CustomerName=%#&ContactNo=%#&Products=%#",serverAddressTest,customer,contactnumber,allProductsInString];
NSURL *url = [NSURL URLWithString:fullWebAddress];
NSURLRequest *theRequest=[NSURLRequest requestWithURL:url];
NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if (theConnection) {
NSMutableData *webData = [NSMutableData data];
NSLog(#"%#",webData);
}
else {
NSMutableData *webData = [NSMutableData data];
NSLog(#"%#",webData);
}
When you write:
NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:theRequest
delegate:self];
you are starting an asynchronous url connection.
Then immediately after that you are testing whether the connection was successful or not and creating an instance of NSMutableData with local scope. Your NSURLConnectionDelegate methods (which you haven't posted) will not have access to this locally-scoped NSMutableData variable.
Have you indeed implemented the methods of the NSURLConnectionDelegate protocol?
Try to send synchronous request to localise the problem:
NSError *error;
NSData *returnData = [NSURLConnection sendSynchronousRequest: theRequest
returningResponse: nil
error: &error];
NSLog(#"error = %#, \ndata = %#", error, returnData);
You also need to also implement the delegate Protocols. ( As NSBum says)
Using Apples example
shown here is the data is returned when the parts are put together.:
NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.apple.com/"]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
// Create the NSMutableData to hold the received data.
// receivedData is an instance variable declared elsewhere.
receivedData = [NSMutableData dataWithCapacity: 0];
// create the connection with the request
// and start loading the data
NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if (!theConnection) {
// Release the receivedData object.
receivedData = nil;
NSLog(#"FAIL " );
// Inform the user that the connection failed.
}
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
NSLog(#" response %#", response);
// This method is called when the server has determined that it
// has enough information to create the NSURLResponse object.
// It can be called multiple times, for example in the case of a
// redirect, so each time we reset the data.
// receivedData is an instance variable declared elsewhere.
[receivedData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
// Append the new data to receivedData.
// receivedData is an instance variable declared elsewhere.
[receivedData appendData:data];
NSLog(#" receivedData %#", receivedData);
}
receivedData is not local but declared elsewhere. (NSMutableData* receivedData;)
I do not use this much so cannot expand further without reading the docs fully myself; which is what you need to do. :-)

Downloading images and captions with JSON in xcode

I have googled this numerous times, with lots of different phrasing, but nothing seems to have exactly what I am after.
What I want to do is to download images and captions into a NSArray with JSON. I do not want to save these images, only display them in a UICollectionView. It would be much easier to be able to download multiple images using the same URL, not just 1 image per URL.
Since I am a fairly newbie programmer, I only know how to use NSURLRequest. This is some of my code:
NSString *getDataURL = [[NSString stringWithFormat:#"URL and a couple of perams", var, var2] stringByReplacingOccurencesOfString:#" " withString:#"%20"];
NSURLRequest *req = [NSURLRequest requestWithURL:[NSURL URLWithString:getDataURL]];
[[NSURLConnection alloc] initWithRequest:req delegate:self];
And then a bit later on in the connectionDidFinishLoading: method:
NSArray *dataArray = [NSJSONSerialization JSONObjectWithData:data options:nil error:nil]; // variable 'data' is an NSMutableData declared in .h
Please advise on what to do, or even if it's possible!
Thanks in advance!
You can do it this way:
-(void) loadImageAtURL:(NSString*)url {
NSURL *requestURL = [[NSURL alloc] initWithString:url];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:requestURL cachePolicy:nil timeoutInterval:45.0];
connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
imageData = [[[NSMutableData alloc] init] retain];
}
And handle response in NSURL delegate methods like:
- (void)connection:(NSURLConnection *)connection
didReceiveData:(NSData *)data {
[imageData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)aConnection {
// RELEASE THE CONNECTION
[connection release];
// CREATE NEW UIIMAGE FROM THE DATA
UIImage *image = [[[UIImage alloc] initWithData:imageData] retain];
[imageData release];
[yourImageView setImage:image];
[image release];
}
- (void)connection:(NSURLConnection *)connection
didFailWithError:(NSError *)error {
// Handle error
}
Hope these methods will give you direction how to carry out things. You make the JSON handling as per your API response in didReceiveData:(NSData *)data and use that data later in connectionDidFinishLoading:
I'm not sure I understand exactly what you are trying to ask but if your goal is to get a list of images/captions using JSON give AFNetworking a try
https://github.com/AFNetworking/AFNetworking

iOS App Wait for HTTP Response when calling a method?

I am trying to call a class method that takes a string and posts it to a site to receive a JSON response(among some other variables I have stored in the DataClass). I am stuck trying to return the data in the form of a response and can not at this point even NSLog the returned data. The question is, now that I have called my class method, how can the class method wait to return a response from an HTTP POST to return data? Once I return my JSON, I can expand it to a dictionary and process from there. Help is appreciated :)
Class Method:
//
// APISample.m
//
// Created by Sam on 1/6/13.
// Copyright (c) 2013 Sam. All rights reserved.
//
#import "APISample.h"
#import "DataClass.h"
#implementation APISample
#synthesize first_name = _first_name;
#synthesize last_name = _last_name;
#synthesize profile_pic_url = _profile_pic_url;
#synthesize responseData;
-(id)init
{
self = [super init];
return self;
NSLog(#"Loaded APISample and fetching");
}
+(id)getDataAboutUser:(NSString *)user_request_id;
{
DataClass *userdata=[DataClass getInstance];
NSLog(#"Loaded APISample and fetching %#", user_request_id);
NSMutableURLRequest *user_fetch_details = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:#"http://10.0.23.161/users/user_fetch_details.php"]];
[user_fetch_details setHTTPMethod:#"POST"];
NSMutableString *postString = [NSMutableString stringWithString:#"id=123"];
[postString appendString:#"&userrequest_id="];
[postString appendString:[userdata.str_userid copy]];
[postString appendString:#"&user_id="];
[postString appendString:[userdata.str_userid copy]];
[postString appendString:#"&identifier="];
[postString appendString:[userdata.str_identifier copy]];
[user_fetch_details setValue:[NSString stringWithFormat:#"%d", [postString length]] forHTTPHeaderField:#"Content-length"];
[user_fetch_details setHTTPBody:[postString dataUsingEncoding:NSUTF8StringEncoding]];
NSURLConnection *connection=[[NSURLConnection alloc] initWithRequest:user_fetch_details delegate:self];
NSMutableData *responseData=[NSMutableData data];
[responseData appendData:[NSURLConnection connection:didReceiveData];
if (connection) {
// Create the NSMutableData that will hold
// the received data
// receivedData is declared as a method instance elsewhere
NSMutableData *responseData=[NSMutableData data];
} else {
// inform the user that the download could not be made
}
NSLog(#"Received Data %#", [[NSString alloc] initWithData:responseData encoding:NSASCIIStringEncoding]);
return [[NSString alloc] initWithData:responseData encoding:NSASCIIStringEncoding];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[responseData appendData:data];
NSString *receivedDataString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
if ([receivedDataString isEqualToString: #"error"]) {
UIAlertView *errorAlert = [[UIAlertView alloc] initWithTitle:#"Error"
message:#"An error has occured. The application will now exit. Unexpected Response!"
delegate:nil
cancelButtonTitle:#"Close"
otherButtonTitles:nil];
[errorAlert show];
exit(0);
}else{
NSError* error;
NSDictionary* json = [NSJSONSerialization
JSONObjectWithData:responseData
options:kNilOptions
error:&error];
NSString *firstnameResponse = [json objectForKey:#"first_name"];
NSString *lastnameResponse = [json objectForKey:#"last_name"];
NSString *profile_pic_urlResponse = [json objectForKey:#"profile_pic_url"];
NSLog(#"didReceiveData %# analysed " , firstnameResponse);
}
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSLog(#"connectionDidFinishLoading");
NSLog(#"Succeeded! Received %d bytes of data",[self.responseData length]);
}
#end
I receive no data in the log after "Received Data" and do not see my error messages. Thanks you
The design pattern you are describing is called a CallBack. You need to be notified of an event occurring at some point in the future. In objective-c there are 4 main forms of callbacks.
Target Action Pairing (this is what is used with buttons, and things of the like. "When this button is pressed notify my target, and tell them to execute this action")
Delegation (you are using a form of delegation in the code above with NSURLConnection. When you see the word 'delegate' i want you to think 'helper object'. You are saying, "hey NSURLConnection, when important events happen, i would like you to tell this delegate (helper object) about these events)
Notifications (these are used a lot when dealing with model objects changing)
and finally... the one i would recommend for your purposes...
Blocks.
A block is a very cool variable. Most variables hold data. A block is a variable which holds code to be executed at some point in the future. So in your situation you could pass a completion block along with your method getDataAboutUser:(NSString *)user_request_id. So it would look like this.
getDataAboutUser:(NSString*)string withCompletion:(void(^)(NSData *finishedData))cBlock
Store that cBlock as an instanceVar. Then when your NSURLConnection finishes downloading all its data, you will execute the cBlock, passing in the finished data as an argument.
Blocks are a fairly complicated things if you have not used them before, so i would reccomend taking 20 minutes and reading this.
Since you need your method to wait for a response before returning, you can use NSURLConnection's convenience class method sendSynchronousRequest to carry out a synchronous request instead of creating and managing an NSURLConnection instance asynchronously.
So instead of your [[NSURLConnection alloc] init...] line you can do this:
NSURLResponse *response = nil;
NSError *error = nil;
NSData *responseData = [NSURLConnection sendSynchronousRequest:user_fetch_details returningResponse:&response error:&error];
Following which you can immediately parse the JSON from responseData instead of doing that in the connection:didReceiveData delegate.
Edit: Just saw user698846's suggestion to modify your method signature to take a completion block. That's also a good and possibly cleaner way to approach your problem if you are at liberty to change your method signature (i.e. nobody is requiring your function to return synchronously). Either way, sendSynchronousRequest is possibly the easiest way out and there's no shame in it especially if there's nothing your app nor your user can do while waiting for the request to complete.
This is some code:
NSURLResponse *response = nil;
NSError *error = nil;
NSData *responseData = [NSURLConnection sendSynchronousRequest:user_fetch_details returningResponse:&response error:&error];

Receiving EXC_BAD_ACCESS message with the following code

I am new to Objective C, so I'm not really even sure what this message means:
EXC_BAD_ACCESS
When executing the following code:
-(void)HelloWorld
{
NSURL *url = [NSURL URLWithString:#"http://example.com/service.asmx/HelloWorld"];
NSMutableURLRequest *request =[NSMutableURLRequest requestWithURL: url];
//do post request for parameter passing
[request setHTTPMethod:#"POST"];
//set the content type to JSON
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[connection release];
[request release];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
// Store incoming data into a string
NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}
I'm attempting to integrate with the Json Framework.
I call HelloWorld, which executes an async request to my service. What's strange, is that it worked one time, and now I get this EXC_BAD_ACCESS message every subsequent time. Any ideas what would be causing this?
You shouldn't be releasing the request. It's already autoreleased.
EXC_BAD_ACCESS means you have a bad pointer. In your case, it's because you are releasing the request when it's already autoreleased.
There's also another problem with your code (unrelated to the crash). You create an NSURLConnection and immediately release the connection after creation. When creating an asynchronous connection, you should release the connection in the delegate methods (if connection fails or if connection did finish loading).