As a novice iOS developer, I am trying to understand some concepts related to the callback mechanisms in iOS.
My model makes HTTP requests through NSURLRequest to a backend rest service. The model has several methods which corresponds to the methods in the service. NSURLRequest is based on the delegate pattern, which means that I receive a common callback for all of the service calls. Then, my model has to find out which service call the callback is related to, so that I can send an appropriate update event to the controller. This is awkward since I have to maintain som state in the model to remember which call I made the last time (which is very impractical in the case of concurrency), or interpret the payload in the HTTP response.
I would wish that NSURLRequest would support the target-action pattern, so that each of the requests could decide which callback method to use. Is that possible? Am I missing something here?
If target-action is not available in the framework, what are the best practices to solve this?
The way to do this is to use NSURLRequest with NSURLConnection. If you check out the docs for NSURLConnection, they will tell you that you need to implement the callback methods in the NSURLConnectionDelegate protocol, and will give you details.
That page also points to several examples, with sample code.
You can also check out the URL Loading System Programming Guide at developer.apple.com, which will give you additional information on how these classes are intended to be used.
Related
I am using AFNetworking for my client and server communication. I want to make a wrapper on top of AFNetworking so that I can set common header and extra information for all the HTTP requests. Basically all my HTTP request will go through one layer to AFNetworking. It will make my client server communication easier and I will be able to include any kind of data with all the http request at any point of time. What will be the best way to do it?
As example I want to send token, network status, user info etc.
More specifically:
I want to include some common info with all the request like network info, user info, token. Now its really difficult to change in each and every request. So I want to design in such a way that all the http call will go through one path and I can send anything with AFNetworking HTTP Request without touching all the file.
You should create one separate class that manage all the network related calls. You should subclass NSObject and make a class with different required methods that you need. Import your AFNetwotking in this class and use this class in whole project when needed to make network call!
I am using NSURLSession for networking and making POST requests to a server. I want to be able to cache these requests, however the URL is always the same.
Is it possible to cache with NSURLCache and change the cache key to something unique such as the request body?
By default, IIRC, POST requests are not cached at all. But yes, you can certainly do it. IIRC, on the NSURLSession side, the only thing you can control is whether the request gets cached or not. To actually control the name under which it is cached, you'll need to implement a custom URL protocol. I've never done what you're trying to do, but I'm pretty sure you'd do it roughly as follows:
Create an NSURLProtocol subclass, and provide it via the protocolClasses property on your session configuration. From that point on, your class gets called first whenever any that session makes a URL request.
In that subclass, in your startLoading method, use setProperty:forKey:inRequest: to tag the request as having been processed by your protocol.
In your canInitWithRequest method, call propertyForKey:inRequest: to see if the request is already tagged, and if so, return NO. That way, you'll see each request exactly once.
In your startLoading method, start a new data task with the tagged request.
In stopLoading, cancel the task.
In canonicalRequestForRequest:, do your conversion. You might have to use setProperty:forKey:inRequest: to store the original, unmodified URL, just in case you get back the modified URL. (I'm not sure.)
I don't think you'll need to implement requestIsCacheEquivalent:toRequest:, but keep it in mind, just in case I'm wrong. You might be able to implement that instead of the canonicalization method, also.
I’d like some input on whether there is a better design pattern to use for my iOS app, which uses a REST model to communicate asynchronously with a Django back end.
The server can presently return three types of responses to requests:
a JSON object
a server status code integer
a long Django error message
When an action is performed in the iOS app that requires data from the server, my design pattern looks like this:
An observer is added to notification center, specifying a method that can process the server response
The method puts together and sends a NSURLConnection
A NSURLConnection delegate method receives the response, does some interpretation to check what kind of server response it is, and then posts the appropriate notification to the notification center
This triggers the response method to run, processing the response
My issue with this pattern is that there are a large number of methods written to send and receive individual request and response types. For instance, if I am requesting an item list, I need to add several observers to the notification center, one to process a user list, one to process a blank user list, and one to process errors. Then I need to write custom methods for each one of those three to perform the appropriate actions and remove the observers, based on what kind of response the server sends.
Furthermore, the NSURLConnection delegate ends up being fairly complex, because I’m trying to interpret what type of a response was received (what types of items were in the list received?) without much context of what was requested, to make sure I don’t call the wrong response method when a server message comes back.
I am fairly new to both iOS programming and to REST programming, so I may be missing something obvious. Any advice or links to resources is appreciated.
I'd initially look at using RestKit to abstract your code away from the network comms so you can worry more about the data model and high level requests. Secondly, I wouldn't use notifications for this as it will likely get messy and be very hard to manage multiple simultaneous requests - delegation or block callbacks will be much better for this.
Your REST implementation is mostly server side, and emprirically you'd be passing and receiving binary. There are factors to consider, including whether you are utilizing HTTP.
Working with JSON with NSJSONSerialization class, and NSURLConnection keeps your program more lean and mean.
I have an IOS6 app, that connects to a REST API to fetch some data.
I use NSURLConnection sendSynchronousRequest in my data fetcher class, and I call its methods by GCD async pattern with blocks from my controller classes. So far so good.
My problem, that I change the API endpoint to https, its certificate is self-signed (I know its secure problems etc, but it is out of question for now).
By using sendSynchronousRequest I can't bypass this problem, because to bypass it, I need to set delegate for NSURLConnection, but in case of sendSynchronousRequest I cant' set delegate, delegate methods just called in case of async calls.
I don't like async request calling, I adore this GCD/sync call pattern very much, it works like a charm, it simple and clear.
So how can I make calls to a https api endpoint by GCD and , NSURLConnection sendSynchronousRequest that bypasses untrusted certificate problem?
Thanks to all!
You answered your question already yourself:
By using sendSynchronousRequest I can't bypass this problem, because to bypass it, I need to set delegate for NSURLConnection, but in case of sendSynchronousRequest I cant' set delegate, delegate methods just called in case of async calls.
You should really get used to the asynchronous style. The approach with a synchronous call within a dispatch_async call is suboptimal to say the least.
The method sendSynchronousRequest is for beginners and toy apps. IMHO, Apple should really deprecate this method and remove it in the next iOSs.
The method sendAsynchronousRequest:queue:completionHandler: is for demonstration purposes, sample apps, prove of concept, and very simple requests not using authentication and https.
Finally, using the asynchronous style with implementing the delegates is for "serious" and release apps. Any serious app should use https when talking to a dedicated server, unless the server is public and does not support https.
Once your have switched to asynchronous style, there might be an answer to your actual question. However, there is no need to bypass a certificate - rather you will use the certificate as it is used in the release app.
While testing my application, i connected to a wifi network which needed an authentication to access the internet.
I would have like [NSString stringWithContentOfUrl:encoding:error:] to fail or return the content of this authentication page even if it is not the page I asked. But it keeps on trying to download, and never returns.
Do you have any solution to detect this kind of issue ?
I would recommend using NSURLConnection. When a redirect happens it will call the delegate method as mentioned here. Also with NSURLConnection you will have greater control in the future when you add additional features and content. Or should the router not do a redirect and just force you to a page, you will be able to use the NSURLConnection to download the content and parse it to determine if it is indeed the page you were looking for.
In that case you'll have to do some coding. Download the contents of the url via NSURLRequest -> NSURLConnection. Then via the NSURLConnection's delegate methods you can respond to the authentication challenge.