How do I distinguish between NSURLConnections in delegate methods? - cocoa

I'm writing a RSS feeder and using the NSXMLParser to parse an XML page for me.
Everything works well.
This is the code that handles the asynchronously connection:
static NSString *feedURLString = #"http://www.example.com/data.xml";
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:feedURLString]];
feed = [[[NSURLConnection alloc] initWithRequest:request delegate:self] autorelease];
Now i'm trying to add another website to be parsed using the same code above, but i need to do different action, on a different URL
I'm implementing the delegate function:
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
The problem is i can't figure out which website was called, i only got the data.
How can i figure out which URL the connection is resolved to?
For example in the :
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
I can check the NSString in NSURL URL that comes from the NSURLResponse but in the above function I can't.

If you implement both delegate methods, shouldn't you receive the latter notification first? If so, you can associate the URL string with the NSURLConnection (which will assumedly be different for each site) in an instance variable and use it when you get the data afterward. I would generally suggest a dictionary, although you can't use the connection as a key in an NS(Mutable)Dictionary since it doesn't conform to NSCopying. You could use the URL string as the key, but that complicates lookup. Perhaps a pair of arrays?
More to the point though, why write an RSS reader from scratch? On 10.5+ you can use the PubSub.framework to do the work for you. This framework handles all sorts of weird formats and invalid XML, and can really save you a lot of time. Maybe it's a good fit for what you're trying to do?

Related

Fetching data from localhost

I'm using XAMPP and I'm trying to fetch some data out of a php file.
If I put the file on my webserver, it works, but locally it doesnt. Seems like Xcode doenst "find" my localhost.. any ideas?
NSString *stringURL = [NSString stringWithFormat:#"http://localhost/root/juraQuiz/test.php"];
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:stringURL]];
NSString *result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"%#", result);
Unfortunately I can't comment yet, so I've had to answer.
I would try seeing if the url is actually resolvable by using NURLs method and check the error.
-(BOOL)checkResourceIsReachableAndReturnError:(NSError **)error
Its possible your local server isn't using normal http ports and is using something random which you'll have to include in the url i.e. "localhost:3000/page.php"
Also, for remote fetching of data maybe NSURLConnection or something similar is more appropriate?
Hope that helps in some way.

Asynchronous NSURLConnection Scheme Tutorial

I am looking for a good tutorial on using the NSURLConnection Asynchronous request. I have been looking around in stackoverflow and Google but could not find one. This can be a duplicate of zillions of questions like this here. But please direct me to the correct tutorial, I have used ASIHTTPRequest before, but I have not used the Apple provided library before.
I would provide you with one written myself, however I would HIGHLY recommend using AFNetworking, it's a wrapper above the NSURLConnection / NSURLRequest system that has a much cleaner flow, you can also use basic NSURLRequests / Connections with this, along with regular NSOperationQueues. The library also uses cocoa pods, and to be honest you really can't get much cleaner then that.
NSOperationQueue *mainQueue = [[NSOperationQueue alloc] init];
[mainQueue setMaxConcurrentOperationCount:5];
NSURL *url = [NSURL URLWithString:#"http://192.168.0.63:7070/api/Misc/GetFuelTypes"];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
[request setHTTPMethod:#"GET"];
[request setAllHTTPHeaderFields:#{#"Accepts-Encoding": #"gzip", #"Accept": #"application/json"}];
[NSURLConnection sendAsynchronousRequest:request queue:mainQueue completionHandler:^(NSURLResponse *response, NSData *responseData, NSError *error) {
NSHTTPURLResponse *urlResponse = (NSHTTPURLResponse *)response;
if (!error) {
NSLog(#"Status Code: %li %#", (long)urlResponse.statusCode, [NSHTTPURLResponse localizedStringForStatusCode:urlResponse.statusCode]);
NSLog(#"Response Body: %#", [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding]);
}
else {
NSLog(#"An error occured, Status Code: %i", urlResponse.statusCode);
NSLog(#"Description: %#", [error localizedDescription]);
NSLog(#"Response Body: %#", [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding]);
}
}];
The mainQueue object is used for routing requests and managing how many can be sent at once. This can be used in many ways, I tend to use them for categorized request (Authentication, Main, Upload Queue)
once inside the block you build a local NSHTTPURLResponse using the returned response. This is needed if you want the status code returned. (doesn't exist in the standard NSURLResponse object)
responseData is the data that can usually be converted right to a string or run through a deserializer to obtain human readable data.
Pretty simple explanation, delegates get you in trouble if you have no idea how to manage multiple requests from the same object (probably why I prefer blocks) :-)
Like always delegates or blocks you want to trigger your UI to update after you receive the response, but not be held back waiting for the request to complete, if you were loading data into a table you would call the request on load and supply some form of progress hud telling them a request is being made, once the data is received you remove the hud and reload the table data. HUDs MUST be called on the main thread so you will definitely need to handle that, I usually just build extensions and use performSelectorOnMainThread, however a better way might be to wrap your function in dispatch_async and call you're hud show / hide code outside of that.

Connection Kit Basics

I need to implement file transfer in my application and it seems that in Cocoa ConnectionKit is unofficial standard. I was able to compile it but I have struggled finding any documentation or examples of it's use. The only example I found was outdated and even with modification I could not get it to work. Does anyone know the basic functions (creating connections, uploading...).
Thanks for any help
Its pretty simple once you figure out how its laid out.
Heres the code to create an ftp connection
CKConnectionRequest *request = [CKConnectionRequest requestWithURL:url];
CKFTPConnection *ftpConn = [[CKFTPConnection alloc] initWithRequest:request];
[ftpConn setDelegate:self];
[ftpConn connect];
self.connection = ftpConn;
[ftpConn release];
Then you would interact with the Connection Delegate methods found in CKConnectionProtocol.h
To authenticate to the server above you would use this delegate method where "cred" is an instance of NSURLCredential you have set up with the credentials you need.
- (void)connection:(id <CKConnection>)connection
didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
[[challenge sender] useCredential:cred forAuthenticationChallenge:challenge];
}
For an upload you would just call one of the upload methods specified in CKConnectionProtocol.h inside of a delegate method like below
- (void)connection:(id <CKConnection>)con
didOpenAtPath:(NSString *)dirPath error:(NSError *)error {
CKTransferRecord *tr = [con uploadLocalItem:localPath
toRemoteDirectory:remotePath
ignoreHiddenItems:YES];
}
Then you would receive callbacks as to the status of that upload via the Uploading Methods specified in CKConnectionProtocol.h
Hopefully that helps. Forgive any small errors in the code I typed it out not copy/paste

Need help with NSURLCredential initWithTrust:

I have been beating my head against the wall for the last few hours and cannot find even a glimmer of a solution anywhere.
I am working on an app to learn how to work with JSON so I am just building a simple app that at first just returns a list of all of my repos on GitHub.
I am able to extract the JSON response from the data returned by NSURLConnection with no problem, unfortunately when I try to access anything that requires authentication the response is always {
message = "Not Found";
}
If I send a request to just get public information about my username I get back the correct response with all the correct info so I know that I am successfully communicating with api.github.com.
First off to start the request I use:
-(IBAction)retriveRepos:(id)sender
{
responseData = [[NSMutableData data] retain];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:#"https://api.github.com/user/repos"]];
[request setHTTPMethod:#"GET"];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[[NSURLConnection alloc] initWithRequest:request delegate:self];
}
When - (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge gets called the authentication method comes back as NSURLAuthenticationMethodServerTrust (which I find strange since I feel like I should be supplying a username and password to login). According to Apple's docs I need to create my NSURLCredential with initWithTrust:. I Googled for answers and finally found a few places that said to just take the serverTrust from the protectionSpace of the NSURLAuthenticationChallenge that was passed in. Doing this shows no signs of having any effect at all, in fact it looks like my NSURLCredential has pretty much nothing in it.
if ([[challenge protectionSpace] authenticationMethod] == NSURLAuthenticationMethodServerTrust) {
NSLog(#"challenge.protectionSpace.serverTrust: %#", challenge.protectionSpace.serverTrust); // This logs "challenge.protectionSpace.serverTrust: <SecTrust 0x10340b2e0 [0x7fff7cc12ea0]>"
NSURLCredential *credential = [[NSURLCredential alloc] initWithTrust:challenge.protectionSpace.serverTrust];
NSLog(#"credential: %#", credential); // Always logs something like "credential: <NSURLCredential: 0x1002d2f20>: (null)"
NSURLCredential *otherCredential = [[NSURLCredential alloc] initWithUser:#"user" password:#"password" persistence:NSURLCredentialPersistencePermanent];
NSLog(#"otherCredential: %#", otherCredential); // This logs otherCredential: <NSURLCredential: 0x1018d0840>: user"
[[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
}
I used more extensive logging as well that showed that credential did in fact exist (at first I thought it hadn't been created at all) but that it had none of it's attributes set certificates: (null)
hasPassword: 0
identity: (null)
password: (null)
. I can only assume that the problem is in my authentication but I followed the examples I found to the letter. I am using the GM preview of Lion, so I guess it is possible I found a bug, or that there is some bug in the GitHub API, but given my skill level I find it much more likely that I am an idiot that is looking over the answer sitting right in front of me.
If anyone knows of a good guide that actually walks you through all the steps of authenticating (preferably in all the styles) rather than the severely lacking Apple URL loading guide that just says to use a method but doesn't say where the SecTrustRef comes from it would be greatly appreciated.
NSURLAuthenticationMethodServerTrust is what you will get back as it negotiates an SSL connection. It's giving you the opportunity to evaluate the trust of the server (or vice versa). Technote 2232 describes this in a bit of detail. Your delegate needs to handle it, the technote links to the source for the sample code Advanced URL Connections which should show you how to respond to that challenge.
Don't despair, if there is an HTTP authentication step coming from your server, you will see the delegate get that later.

How do I download contents into an NSData using a Secure URL?

I'm starting with the following snip to download an image
NSError *error = nil;
NSString *url = #"https://...";
[NSData dataWithContentsOfURL:[NSURL urlWithString:url] options:nil error:&error];
When this code runs, the error instance contains an error without a whole lot of information in the userInfo. It's just the secure url that was attempted.
Given the results, I'm pretty sure these methods don't handle secure URLs.
My question:
Is there an easy way (like these
methods, or some option) to set the
dataWithContentsOfURL: method to download over a secure url?
Try running your URL through this first

Resources