How to write an Objective-C REST API wrapper - objective-c

I’m working of writing an Objective-C wrapper for a REST API. A lot of what I’m reading says not to use synchronous NSUrlConnection requests to avoid blocking the main thread. This makes sense, but I am wondering, what is the best way to make an API wrapper in Objective-C?
For example, we have an API method that takes a session ID and returns whether or not the session is valid. Ideally the wrapper method prototype would look like the following:
- (BOOL) sessionIsValid:(NSString *)sessionId;
So, that method could be called and the return value could be used to decide what to do next. But how would this work if the API call is asynchronous? It seems like the caller would need to set itself as the wrapper's delegate, make a request, and then process the response from the delegate method. Seems pretty ugly for such a simple API call. Is there a good way to achieve this?

Whether a session is valid or expired, should be an implementation detail of the underlying network layer. Thus, you would rarely have this method in a Objective-C API. Rather you would have an API that looks more like this:
typedef void (^completion_t)(id result, NSError* error);
- (void) fetchAllPostsWithUser:(ID)userID completion:(completion_t)completionHandler;
This is an asynchronous method. The call-site will be notified about the completion through calling the completion handler, which passes the result of the operation and possibly an error object. What result is actually, is entirely up to you: it may be an NSArray of custom objects of class Post or it may be JSON (either serialized or as objects), or whatever. In any case it must be clearly defined in the documentation.
Your "session problem" is part of the authentication scheme. In many cases, NSURLSession, respectively NSURLConnection can already handle authentication completely transparent for you. If not, there are a few delegate methods which can be overridden where you can tailor the behavior. A client (a developer using this API as a library) of that Objective-C API should never be concerned with such "abstract" and "obscure" notions like "session". He/she, knows just passwords, users, posts, etc. ;)

If you wanted to return a BOOL you would need to have already setup the session and cached the validity (expiry date) - which isn't always going to be possible. A delegate pattern is a good option. Don't forget that you can implement the delegate pattern using blocks (which give you the option of having multiple different delegates all using the API at the same time).

Related

Unit testing NSURLConnection sendAsynchronousRequest with OCMockito

I'm struggling to write a unit test for an API wrapper with an interface like
- (void)publish:(id<MyCustomRequest>)aRequest completionHandler:(void (^)(id<MyCustomResponse>, NSError *)) completionBlock
which calls this method under the hood:
NSURLConnection sendAsynchronousRequest:queue:completionHandler
I don't want to use a delegate instead, as the exposed API fits much more comfortably with the sendAsynchronousRequest method (and doesn't require a separate accumulator object per-request). Further, I am using OCMockito for mocking throughout the rest of the code, which doesn't support partial mocks or mocking class methods.
Are there any other testing techniques that my be able to test this function? Is it necessary to use a delegate instead?
Use the delegate-based API. I realize it's more code, but the convenience API is clearly not adequate to meet your needs (i.e. mockable with OCMockito). Furthermore, don't worry about the "overhead" of allocating one ancillary per request. I feel quite confident that there will be dozens of objects allocated behind the scenes in the system frameworks by virtue of your calling +[NSURLConnection sendAsynchronousRequest:queue:completionHandler:]; you shouldn't be concerned. That said, a single object can be the delegate for more than one request, so you needn't necessarily have more than one.

iOS, Objective C - NSURLConnection and asynchronious examples, default behavior and best practices?

I have been working with a few applications that deal with NSURLConnections. While researching best practices I have noticed a lot of examples online showing how to use NSOperation and NSOperationQueue to deal with this.
I have also noticed on stackoverflow a few examples that show initializing the connection as synchronous and asynchronous using the class methods of NSURLConnection: sendAsynchronousRequest and sendSynchronousRequest.
Currently I am doing my initialization as follows:
[[NSURLConnection alloc] initWithRequest:request delegate:self];
While doing this I have monitored the main thread and the calls to the delegate methods:
connectionDidFinishLoading, connectionDidReceiveResponse, connectionDidReceiveData and connectionDidFailWithError
Everything I have read in Apples documentation and my tests prove to me that this is asynchronous by default behavior.
I would like to know from more experienced Objective C programmers when the other options would be used for either a best practice, or just be more correct than what I see as the most simplistic way to get async behavior?
This is my first question I have posted on here, if more information is needed please ask.
Synchronous is bad bad bad. Try to avoid it. That will block up your main thread if the data transfer is large, thus resulting in an unresponsive UI.
Yes, it is possible to dispatch a synchronous call onto a different thread, but then you have to access any UI elements back on the main thread and it is a mess.
Normally I just use the delegate methods you have described - it is straightforward, and NSURLConnection already handles the asynchronous call for you away from the main thread. All you need to do is implement the simple delegate methods! It's a little more code, but you always want to go asynchronous. Always. And when it is finished loading, use the information you get to update the UI from the finishedLoading delegate method.
You also have the option of using blocks now, but I can't speak for how well those work or even how to use them well. I'm sure there's a tutorial somewhere - the delegate methods are just so easy to implement.
The method you list are the traditional means of asynchronous transfer and an app that uses them will be efficient in processor (and hence power) use.
The sendAsynchronousRequest method is a relatively new addition, arriving in iOS 5. In terms of best practice there's little other than style to differentiate between it and the data delegate methods other than that a request created with the latter can be cancelled and a request created with the former can't. However the tidiness and hence the readability and greater improbability of bugs of the block-based sendAsynchronousRequest arguably give it an edge if you know you're not going to want to cancel your connections.
As a matter of best practice, sendSynchronousRequest should always be avoided. If you use it on the main thread then you'll block the user interface. If you use it on any other thread or queue that you've created for a more general purpose then you'll block that. If you create a special queue or thread for it, or post it to an NSOperationQueue then you'll get no real advantages over a normal asynchronous post and your app will be less power efficient per Apple's standard WWDC comments.
References to sendSynchronousRequest are probably remnants of pre-iOS 5 patterns. Anywhere you see a sendSynchronousRequest, a sendAsynchronousRequest could be implemented just as easily and so as to perform more efficiently. I'd guess it was included originally because sometimes you're adapting code that needs to flow in a straight line and because there were no blocks and hence no 'essentially a straight line' way to implement an asynchronous call. I really can't think of any good reason to use it now.

Delegate method/selector for NSURLConnection

I'm creating a service class in Objective-C that communicates with a HTTP server. I'm familiar with NSURLConnection and the associated classes to make an asynchronous request to a server. So far, I've used self as the delegate, responding to the four delegate methods (didReceiveResponse, didReceiveData etc.) required for the call.
The service class I'm building must be able to handle several requests at once, and respond differently to each. I'm looking for a way to achieve this, without an endless switch or if-elseif in the connectionDidFinishLoading method.
I have the idea to create a delegate class that implements the four methods described above, and give that to the NSURLConnection object to talk to. However, I want to notify the parent class when the connection finishes loading and then fire another method within the parent class. And of course, the delegate doesn't know which method this is - it could be anything.
How to proceed? Is there a way to set a selector for the delegate class, and fire that selector (which is a method) when the request is finished? How do I do such a thing?
(Creating a delegate for my delegate, and then calling a superclass method could do the trick, but I'm really looking into wildcard methods, such as a selector.)
Any help is greatly appreciated!
Regards,
Reinder
I would pass a block (^{ ... })to the delegate that it should call when the connection has finished.
You have three options:
Using a block callback
Using notifications
Using a delegate, as you already suggested.
All three are perfectly valid, but with various advantages/disadvantages. Learn them all, then decide which to use in each scenario. :-)
Often more than one solution will be chosen. For example many of Apple's classes implement a delegate method and send a notification for the same event.

Can I use blocks in asynchronous results with restkit?

--UPDATE: I've decided to give AFNetworking a try. Even though RestKit has a really nice object mapping functionality, the way the networking calls were designed have made some things difficult for us.
I'm hoping for some advice on how to organize my project that's using RestKit.
I have several REST calls from a repository class and its results get passed to controllers. For example I have a getProfile method in the repository class that is getting called from our browse view controller. The view controller is set as the delegate to the get profile calls while the repository class is set to the delegate for the restkit calls.
The problem is if the browse controller makes several get profile requests, it is difficult to distinguish which result should go to which delegate function since all the restkit calls share the same delegate method objectLoaderDidFinishLoading. I then have 4 delegates that I have to match the results of the 4 asynchronous restkit requests.
Is there any way I can use blocks so that I can pass a function to execute as the asnynrhounous result comes back so that I can assign a proper delegate? The block support that I saw allowed a block to be used before the request was sent out in rest kit but I am interested in using it for when the asynchronous result is returned.
The alternative of examining the results or setting user data and sleuthing what delegate goes with what asynchronous results seems unreliable and bulky.
You can solve your issues with disambiguating between your profile requests by using the userData opaque pointer on RKObjectLoader. That will allow you to hang any object you want on the request, which can then be used to help distinguish between multiple profile requests. Also, if those profile requests are going to different resourcePaths then you can just use the wasSentToResourcePath: method on RKObjectLoader to distinguish between them.
I just stumbled upon this question while trying to figure out this problem for my own REST interface. I'm glad I did, I'll probably use RestKit now.
I digress, back to your question. As you noted it doesn't seem like the block argument in the RKObjectManager is meant to be used this way. Instead, how about writing a class that implements RKObjectLoaderDelegate, takes in a block, and calls that block on any of the delegate calls.
Maybe something like this?
#interface MyObjectLoaderDelegate : NSObject <RKObjectLoaderDelegate>
#property (nonatomic, copy) void (^callback)(RKObjectLoader *loader, NSDictionary *objectDictionary, NSError *error)
- (id)initWithCallback:(void (^)(RKObjectLoader*, NSDictionary*, NSError*)aCallaback;
#end
And on any implemented delegate method you can execute the block. Since blocks retain scoped variables you can run code against the calling delegate.
Whatcha think?
I am not sure using blocks is the right way to solve your issue.
How about having a class GetProfile that implements RKObjectLoaderDelegate.
So you call the request from within here and set itself to be the delegate.
Then you have an objectLoader per request.
So in your view controller, each time you what GetProfile, you create an instance. And then when that instance messages your controller back (via delegates?) you know which it is.
I am just grappling with this issue as well, so am keen to hear feedback.
Switching over to AFNetworking seems to be the way to go... it was a much easier implementation for what I needed.

Do I have to create an instance of a class in order to assign it a delegate?

Sorry for noobness-level of the question.
I saw this answer, where it says
Add something like this to your NSURLConnection delegate
However, the method in question, sendSynchronousRequest:returningResponse:error:, is a class method. If I understand delegate methods correctly, they use a delegate which is specified when the NSURLConnection object is initiated.
So, if I have no instance of the class, a delegate can't be used. Did I understand correctly?
Yes, you are correct. In Cocoa, assigning a delegate requires an instance. In the case of NSURLConnection, its delegate is supposed to be used when making an asynchronous request that is initiated with -initWithRequest:delegate: or +connectionWithRequest:delegate:
Since classes are also objects it could be conceived that they also could have delegates. However, since there is no concept of class variables in Objective-C, a class would have nowhere to store its delegate (it could use a standard C variable in its .m file, though). Anyway, this concept is not used in Cocoa.
Yes delegates are used for handling events when you send your request asynchronously.
While sending synchronous request using +sendSynchronousRequest:returningResponse:error: method delegates are not used - you only get the resulting data and (optionally) server response and error and not aware about intermediate loading events (and remember that calling thread is also blocked while connection is in progress).