How to use Faroo search API in cocoa - objective-c

I never use web API and don't know what i may read about this. I read FAROO Return Values doc, but i don't understand how i may get result-array (or dictionary) in cocoa.
Please anybody give me example or tutorial how to use Faroo API (or other web API) in objective-c.
Thank you.

To use web API and FAROO API in particular i use NSURLConnection class and NSURLConnectionDelegate protocol:
- (IBAction)search:(id)sender {
NSString* requestString = [NSString stringWithFormat:#"http://www.faroo.com/api?q=%#&start=1&length=10&l=ru&src=news&f=xml&YOUR_API_KEY",[searchField stringValue]];
// NSLog(#"str %#",requestString);
NSURL* requestUrl = [NSURL URLWithString:requestString];
NSURLRequest* searchRequest = [NSURLRequest requestWithURL:requestUrl cachePolicy:NSURLRequestReloadRevalidatingCacheData timeoutInterval:60];
[self performSelectorOnMainThread:#selector(startConnectionWithRequest:) withObject:searchRequest waitUntilDone:NO];
}
- (void)startConnectionWithRequest:(NSURLRequest*)request {
NSURLConnection* connection = [[NSURLConnection alloc]initWithRequest:request delegate:self startImmediately:YES];
if (connection) {
//update GUI and do something...
theData = [NSMutableData data];
}
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
NSLog(#"Receive data");
[theData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
NSLog(#"Http status code %ld",(long)[httpResponse statusCode]);
}
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSLog(#"Finish");
//do something with data and update GUI
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
NSAlert* searchFailedAlert = [NSAlert alertWithError:error];
[searchFailedAlert runModal];
}

One other way of doing things is to declare the missing method yourself as a category of the class in question. This will get the compiler to stop complaining about not finding the method, though of course you'll still need the runtime check you're already doing to avoid actually calling the method. You might also want to wrap such a declaration using availability macros, so that it will be ignored once you do move up to using the 10.5/10.6 SDK and you won't get a different compiler complaint down the line. That would look something like this:
#if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_4 //ignore when compiling with the 10.5 SDK or higher
#interface NSPropertyListSerialization(MissingMethods)
+ (NSData *)dataWithPropertyList:(id)plist format:(NSPropertyListFormat)format options:(NSPropertyListWriteOptions)opt error:(NSError **)error;
#end
#endif

Related

NSURLConnection Delegate Returns Null

I have followed a handful of examples on NSURLConnection, see latest below, but yet I keep getting null on the returned FinishLoading. I checked didReceiveResponse and its getting the data. What am I not doing right here?
EDITED: Now works as expected.
#pragma mark NSURLConnection Delegate Methods
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
_dataDictionary = [NSMutableDictionary new];
_theReceivedData = [NSMutableData new];
[_theReceivedData setLength:0];
// add object
[_dataDictionary setObject:_theReceivedData forKey:[connection description]];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
NSMutableData *imageData = _dataDictionary[ [connection description] ];
[imageData appendData:data];
if([connection description]!=nil && imageData!=nil)
{
[_dataDictionary setObject:imageData forKey:[connection description]];
}
}
- (NSCachedURLResponse *)connection:(NSURLConnection *)connection
willCacheResponse:(NSCachedURLResponse*)cachedResponse {
// Return nil to indicate not necessary to store a cached response for this connection
return nil;
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
// The request is complete and data has been received
// You can parse the stuff in your instance variable now
NSData *imageData = _dataDictionary[ [connection description] ];
if(imageData!=nil)
{
NSLog(#"%#",imageData);
Take NSMutableData *theReceivedData out. Make it a class variable. Your problem is theReceivedData is being deallocated in every method. You are creating a new object in every method. Retain the old one.
NSMutableData *_theReceivedData;
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
_theReceivedData = [NSMutableData new];
[_theReceivedData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[_theReceivedData appendData:data];
}
- (NSCachedURLResponse *)connection:(NSURLConnection *)connection
willCacheResponse:(NSCachedURLResponse*)cachedResponse {
// Return nil to indicate not necessary to store a cached response for this connection
return nil;
}
// LOOK AT THIS http://stackoverflow.com/questions/1064920/iphone-corrupt-jpeg-data-for-image-received-over-http
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSLog(#"%#",_theReceivedData);

When NSURLConnection delegate is self how to return didReceiveData and didReceiveResponse to my method

I am relatively new to objective-c but struggling with delegates when it comes to NSURLConnection. Below I have an implementation file api.m
Elsewhere in my viewcontrollers I call this api object with the method getGroups and the purpose here is to return the number of groups found when the API request is made. I can see the data in the didReceiveData but how can I get this data back into my getGroups so that I can access it in my viewController?
In my view controller I have something like:
NSInteger *numGroups = [apiRequest getGroups];
and in my api.m implementation file I have the following. Again everything works I am just not sure how to return the data from didReceiveData back so I can access it in getGroups method.
#import "API.h"
#import "Constants.h"
#import "JSONParser.h"
#implementation API
#synthesize user, url, receivedData
-(NSInteger)getGroups {
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:10];
[request setValue:APIKEY forHTTPHeaderField:#"apikey"];
[request setHTTPMethod:#"GET"];
[request setURL:url];
NSURLConnection *myConnection;
myConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
//How do I access what was append'd in receivedData below
return 2;
}
/* ----------------------------------------------------------------------------------------
NSURLConnection Delegates
------------------------------------------------------------------------------------------- */
// Check the response code that was returned
- (NSInteger)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
return [httpResponse statusCode];
}
// Take a peak at the data returned.
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
NSLog(#"DATA: %#", [data description]);
//How to get this information back up into the getGroups method
[receivedData appendData: data];
}
// Close the connection
- (void)connectionDidFinishLoading:(NSURLConnection*)connection {
NSLog(#"Connection Closed.");
}
#end
What you want to do is in your ViewController that is calling the API set the API's delegate to self. Then you need to add those delegate methods inside your ViewController, not use them out of the API. That way when the NSURLConnection tries to call one of the delegate methods it will be accessible within youre ViewController. You also want to make sure you add the delegate protocol inside your ViewController's .h file as well.
As a quick example your VC.h file will contain the following:
#interface ViewController : UIViewController <NSURLConnectionDataDelegate>
Then in your VC.m file you'd have the following methods:
/* ----------------------------------------------------------------------------------------
NSURLConnection Delegates
------------------------------------------------------------------------------------------- */
// Check the response code that was returned
- (NSInteger)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
return [httpResponse statusCode];
}
// Take a peak at the data returned.
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
NSLog(#"DATA: %#", [data description]);
//How to get this information back up into the getGroups method
[receivedData appendData: data];
}
// Close the connection
- (void)connectionDidFinishLoading:(NSURLConnection*)connection {
NSLog(#"Connection Closed.");
}
Now when your NSURLConnection tries to call didReceiveData it will be called inside your ViewController, not in the API.
As a side note I whole heartedly recommend taking #SK9's advice and make this an Async call to abstract it from the main thread.
NSURLConnection's sendSynchronousRequest:returningResponse:error:, see here, will return a data object. Do be sure you're happy to block the current thread like this. I'd prefer for this to be an asynchronous request, with a completion block to handle the return. More details on the page I referred to, but do make reading up on blocks a priority if this is new. The Short Practical Guid to Blocks might help.

How to refresh a connection with NSURLConnection

I'm working on a project for school, and I was wondering if there was a way to actually update the connection with NSURLConnection if a user submits something. For example, I'm having twitter search based on username, and I have a default username set up when the view loads. What would I have to do to refresh that connection when a user enters a different username on that page? I have my button handlers all set up, and I'm using the same code as in my viewDidLoad function. Is there a method call or something that will actually reset the connection?
Thanks,
David
I attached example codes
// member variable 'conn'
// NSURLConnection *conn;
// #property(strong, nonatomic) NSURLConnection *conn;
-(void)viewDidLoad {
[super viewDidLoad];
[self sendRequest];
}
- (IBAction)sendButtonClicked {
[self sendRequest];
}
- (void)sendRequest {
if (self.conn) {
[self.conn cancel];
self.conn = nil;
}
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.google.com"]];
NSURLConnection *conn = [NSURLConnection connectionWithRequest:request delegate:self];
self.conn = conn;
[conn start];
}
// NSURLConnection Delegates
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
// append received data
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
// error handling
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
// using data
}
I don't think you can "reset" the connection. You will have to make a new request. In your button clicked method simply make a new request call with the new user name.
It works like a request in a browser, when you change some parameter in the url the browser sends of a new request to the web-server.
have a look at this example by apple (if you dont need the caching part just focus on URLCacheConnection.h/.m) http://developer.apple.com/library/ios/#samplecode/URLCache/Listings/Classes_URLCacheController_m.html#//apple_ref/doc/uid/DTS40008061-Classes_URLCacheController_m-DontLinkElementID_10
i

Parsing JSON data in iOS [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
iPhone/iOS JSON parsing tutorial
I have been reading many tutorials on how to parse JSON data in Objective C but still I am unable to figure it out. I want to parse data from the JSON file and show it up on screen.
For example,
I want to parse data from here and get all the values of different retailers in different variables, so that I can use them later.
How can I do it?
Assuming that you have your data in a NSData object you can use NSJSONSerialization class available in iOS 5 and up.
+ (id)JSONObjectWithData:(NSData *)data options:(NSJSONReadingOptions)opt error:(NSError **)error
This is a class method that will convert your data into objects like NSArray, NSDictionary, NSNumber etc. depending on the contents of your data object.
Here is how you would download and parse the data from a web server. Note that all these methods are part of the same class and there are instance variables named _downloadData of type NSMutableData* and _downloadConnection of type NSURLConnection*. Also note this code assumes ARC is not being used. If it is, just remove the object releases and retains and make sure the instance variables are strong references.
-(void)startDownload {
NSURL* jsonURL = [NSURL URLWithString:#"http://isbn.net.in/9781449394707.json"];
NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:jsonURL cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:60];
_downloadData = [[NSMutableData dataWithCapacity:512] retain];
_downloadConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[_downloadData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[_downloadData appendData:data];
}
- (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
[_downloadConnection release];
_downloadConnection = nil;
[_downloadData release];
_downloadData = nil;
}
- (void) connectionDidFinishLoading:(NSURLConnection *)connection
{
NSError* jsonError = nil;
NSDictionary* jsonDict = nil; // your data will come out as a NSDictionry from the parser
jsonDict = [NSJSONSerialization JSONObjectWithData:_downloadData options:NSJSONReadingMutableLeaves error:&jsonError];
if ( nil != jsonError ) {
// do something about the error
return;
}
[_downloadConnection release];
_downloadConnection = nil;
[_downloadData release];
_downloadData = nil;
// now do whatever you want with your data in the 'jsonDict'
}

NSURLConnection always connects to the same URL

Whenever I create an NSURLConnection in a class I have, it always connects to the first URL connected to by that class. It has an ivar conn that the NSURLConnection is stored in, and here is the method that connects:
-(void)getMoreProblems
{
problemsPage++;
NSURL *url=[NSURL URLWithString:[NSString stringWithFormat:#"http://projecteuler.net/problems;page=%d",problemsPage]];
NSURLRequest *req=[NSURLRequest requestWithURL:url];
NSLog(#"%p",conn);
conn=[[NSURLConnection alloc] initWithRequest:req delegate:self];
NSLog(#"%p",conn);
}
I have checked by NSLoging the URL's description and the Connection's pointer that they are different, as well as telling the UIApplication to load the URL in safari. As far as I can tell, It tries to load the right page. I also tried both POST and GET, but it didn't make a difference. What might be causing this?
EDIT FOR ANYONE LOOKING AT THIS WITH A SIMILAR PROBLEM:
My problem ended up being that I did not reinitialize the NSMutableData I stored the connection data in after each page loaded.
This isn't really an answer, but it's too long for a comment. I can't see anything wrong with the code that you posted. I pasted your code for getMoreProblems into a new project and added the delegate methods necessary to look at the results -- as far as I can tell it worked fine. I can see in the resulting string, the problem numbers starting with 1 on the first page I receive (from the first call to getMoreProblems) and starting with problem 51 on the second call to getMoreProblems. The only thing I added to your getMoreProblems method was the if-else clause at the end. HEre is the code I used:
#synthesize window = _window,receivedData;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
problemsPage = 0;
[self getMoreProblems];
}
-(void)getMoreProblems {
problemsPage++;
NSURL *url=[NSURL URLWithString:[NSString stringWithFormat:#"http://projecteuler.net/problems;page=%d",problemsPage]];
NSURLRequest *req=[NSURLRequest requestWithURL:url];
NSLog(#"%p",conn);
conn=[[NSURLConnection alloc] initWithRequest:req delegate:self];
NSLog(#"%p",conn);
if (conn) {
self.receivedData = [NSMutableData data];
} else {
NSLog(#"The Connection Failed");
}
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
NSLog(#"%#",response.URL);
[self.receivedData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
NSLog(#"In connection:didReceiveData:");
[self.receivedData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSLog(#"Succeeded! Received %lu bytes of data",[receivedData length]);
NSString *page = [[NSString alloc] initWithData:self.receivedData encoding:NSUTF8StringEncoding];
NSLog(#"%#",page);
[self performSelector:#selector(getMoreProblems) withObject:nil afterDelay:5];
}
So, I can't reproduce your problem -- I'm guessing it lies elsewhere in some code that you didn't post.