I am using the below code below to perform my webservice calls with the service.I used AFNetworking version below 2.0 where AFHTTPClient .Now i migrated to latest version of AFNetworking .I donot find the AFHTTPClient class in the latest version . What should i replace with the curent code so that it works again .Any help please
#interface APIClient : AFHTTPClient
+ (APIClient*)client;
- (void)commandWithMethod:(NSString *)method params:(NSMutableDictionary*)params success:(APIClientSuccessCallback)successBlock failure:(APIClientFailureCallback)failureBlock;
#end
// Singleton method
+ (APIClient*)client {
static APIClient *client = nil;
static dispatch_once_t onceInst;
dispatch_once(&onceInst, ^{
client = [[self alloc] initWithBaseURL:[NSURL URLWithString:APIHost]];
[AFJSONRequestOperation addAcceptableContentTypes:[NSSet setWithObjects:
#"application/json",
#"text/json",
#"text/javascript",
#"text/plain",
#"text/html",
#"application/x-www-form-urlencoded", nil]];
});
return client;
}
#pragma mark - Init
// Intialize the API class with the destination host name
- (APIClient*)init {
self = [super init]; // call super init
if (self != nil) {
[self registerHTTPOperationClass:[AFJSONRequestOperation class]];
// Accept HTTP Header; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1
[self setDefaultHeader:#"Accept" value:#"application/json"];
}
return self;
}
#pragma mark - Core API Methods
// This function sends an API call to the server
- (void)commandWithMethod:(NSString *)method params:(NSMutableDictionary*)params success:(APIClientSuccessCallback)successBlock failure:(APIClientFailureCallback)failureBlock {
[MBMNetworkActivity pushNetworkActivity];
NSMutableURLRequest *apiRequest = [self requestWithMethod:#"POST" path:method parameters:params];
AFJSONRequestOperation *operation = [[AFJSONRequestOperation alloc] initWithRequest: apiRequest];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
// success! :)
[MBMNetworkActivity popNetworkActivity];
successBlock(responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
// failure! :(
[MBMNetworkActivity popNetworkActivity];
failureBlock(error);
}];
[operation start];
}
You can use NSURLSession for quite a bunch of the AFHTTPClient Stuff.
But to achieve all functionality just write a class like you now did but based on NSObject.
NSURLSession has a really nice API and great functionality combined with it.
AFHTTPRequestOperationManager is the replacement class to subclass instead of AFHTTPClient. It's not the same but it's probably what your looking for.
I would suggest you read Mattt Thompson's blog NSHipster. He is the author of AFNetworking and covered the changes a while back http://nshipster.com/afnetworking-2/. There is also an AFNetworking 2.0 migration guide https://github.com/AFNetworking/AFNetworking/wiki/AFNetworking-2.0-Migration-Guide that will be usefull to you.
Finally i was able to do with following changes replacing AFHttpClient with AFHTTPRequestOperationManager
typedef void (^APIClientSuccessCallback) (id response);
typedef void (^APIClientFailureCallback) (id error);
#interface APIClient : AFHTTPRequestOperationManager
+ (APIClient*)client;
- (void)commandWithMethod:(NSString *)method params:(NSMutableDictionary*)params success:(APIClientSuccessCallback)successBlock failure:(APIClientFailureCallback)failureBlock;
#end
#import "APIClient.h"
#implementation APIClient
+ (APIClient*)client {
static APIClient *client = nil;
static dispatch_once_t onceInst;
dispatch_once(&onceInst, ^{
client = [[self alloc] initWithBaseURL:[NSURL URLWithString:APIHost]];
client.responseSerializer = [AFJSONResponseSerializer serializer];
[client.responseSerializer setAcceptableContentTypes:[NSSet setWithObject:#"text/html"]];
});
return client;
}
#pragma mark - Core API Methods
// This function sends an API call to the server
- (void)commandWithMethod:(NSString *)method params:(NSMutableDictionary*)params success:(APIClientSuccessCallback)successBlock failure:(APIClientFailureCallback)failureBlock {
[self POST:method parameters:params success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"response --- %#",responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"error ----- %#",error);
}];
}
#end
Related
I'm new to iOS while I'm developing I am calling web services every where...I want like one single class for get,post,put methods...then call [self post];
[parameters:....]... that means I want to call single methods for all get services and post.. please help me...how it is..
NSURL *url = [NSURL URLWithString:#"https://example.com/"];
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url];
NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:
height, #"user[height]",
weight, #"user[weight]",
nil];
[httpClient postPath:#"/myobject" parameters:params success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSString *responseStr = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding];
NSLog(#"Request Successful, response '%#'", responseStr);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"[HTTPClient Error]: %#", error.localizedDescription);
}];
For AFNetworking 2.0 (and also using the new NSDictionary syntax):
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
NSDictionary *params = #{#"user[height]": height,
#"user[weight]": weight};
[manager POST:#"https://example.com/myobject" parameters:params success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"JSON: %#", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
From here you can create singleton class - How to create singleton class in objective C
Then you need to create your own method with completion handler and call where you want.
Example: Post Method:
+(void)postWebserviceWithURL:(NSString*)webServiceURL withParam:(NSDictionary*)urlParameters withCompletion:(void(^)(NSDictionary*response))completion {
//Your code goes here
}
here is the related answer.You should create nsobject classes something like webservices and create the singleton instance object like this.
+(WebServices *)sharedInstance{
/* Use this to make it a singleton class */
if (sharedObj==Nil) {
sharedObj=[[WebServices alloc]init];
}
return sharedObj;
/**/
}
using this singleton instance you can call the methods what ever you required.
Eg: [[webservices sharedInstance] post];
With in the method you can use the required web services hits such as post,get and put.
use the Nsnotifiers to consume the responses from the API hits.
+ (instancetype)sharedInstance
{
static CustomClass *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
//Override your constructor for custom initialization if you want
sharedInstance = [[CustomClass alloc] init];
});
return sharedInstance;
}
Then define your methods for CRUD actions.
simply access like
[[CustomClass sharedInstance] POST:...];
[[CustomClass sharedInstance] GET:...];
I am trying to implement AFNetworking code to communicate with a web API. I am getting the following errors in the code:
No visible #interface for APIClass declares the selector
registerHTTPOperationClass
No visible #interface for APIClass declares the selector
setDefaultHeader:Value
No visible #interface for APIClass declares the selector
multiPartFormRequestWithMethod:path:parameters:constructingBodyWithblock
Obviously something to do with the new AFNetworking 2.0 migration...however I have been looking at all the migration posts and documentation and connot find the replacements for these without throwing an error:
// add the location details of the web service we wrote
#define kAPIHost #"http://myurl"
#define kAPIPath #"mywebapi/"
#implementation APIClass
// this is the implementation of the singleton method
+(APIClass*)sharedInstance{
static APIClass *sharedInstance = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
sharedInstance = [[self alloc] initWithBaseURL:[NSURL URLWithString:kAPIHost]];
});
return sharedInstance;
}
-(APIClass*)init{
// call super init
self = [super init];
if (self != nil){
user = nil;
[self registerHTTPOperationClass:[AFHTTPRequestOperation class]];
// Accept HTTP header; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1
[self setDefaultHeader:#"Accept" value:#"application/json"];
}
return self;
}
// call to the server
-(void)commandWithParams:(NSMutableDictionary*)params onCompletion:
(JSONResponseBlock)completionBlock
{
// prepare e POST request by creating an NSMutableURLRequest instance using the
// parameters we want to send via POST
NSMutableURLRequest *apiRequest =
[self multipartFormRequestWithMethod:#"POST"
path:kAPIPath
parameters: params
constructingBodyWithBlock: ^(id <AFMultipartFormData>formData) {
// attach file if needed
}];
// create an operation to handle the network communication in the background
// and intialize it with the POST request we just prepared
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:
apiRequest];
// now set the 2 blocks needed for success and failure
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id
responseObject)
{
// success! - if the call is successful then we just pass in the JSON response
NSLog(#"responseObject: %#", responseObject);
completionBlock(responseObject);
}
// if there is a failure in the network call then we call the failure block
// and contrcut a new dictinary to hold the message of the network error
failure:^(AFHTTPRequestOperation *operation, NSError * error) {
//failure!
completionBlock([NSDictionary dictionaryWithObject:[error localizedDescription]forKey:#"error"]);
}];
// at this point we can call the start method so that AFNetworking can do its
// magic in the background
[operation start];
}
#end
You're getting these errors because the methods you're calling aren't methods of whatever class you're subclassing. I'll assume you're subclassing AFHTTPSessionManager, which is recommended for iOS 7 in AFNetworking 2.0. Based on that...
For your first two errors, I believe the updated lines below are the AFNetworking 2.0 way of doing it with AFHTTPSessionManager:
-(APIClass*)init{
// call super init
self = [super init];
if (self != nil){
user = nil;
self.requestSerializer = [AFJSONRequestSerializer serializer];
self.responseSerializer = [AFJSONResponseSerializer serializer];
}
}
For your third error, the method multiPartFormRequestWithMethod:path:parameters:constructingBodyWithblock should be replaced with:
[self POST:kAPIPath parameters:params constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
// attach file if needed
} success:^(NSURLSessionDataTask *task, id responseObject) {
// handle success
} failure:^(NSURLSessionDataTask *task, NSError *error) {
// handle failure
}];
I am new to iOS development.
I have an application which uses NSURLConnection methods for http transfers across the network. The application is using JSON classes SBJsonparser and SBJsonWriter classes for parsing the Json and Serialization protocols for coverting the objects to json and deserializing the specified dictionary into instace of objects and using Serialization properties. I have separate classes for each request to API which conforms to serializable protocol.
One of sample classes is as follows
+ (id) deserializeFromDictionary:(NSDictionary *)dictionary {
Class *obj = [super deserializeFromDictionary:dictionary];
return obj;
}
+ (NSArray *) serializableProperties {
static NSArray *properties = nil;
if (properties == nil) {
properties = [[NSArray alloc] initWithObjects:
[SerializableProperty propertyWithExternalName:#"username"
internalName:#"username" internalClass:[NSString class]],
[SerializableProperty propertyWithExternalName:#"pwd"
internalName:#"pwd" internalClass:[NSDate class]],
nil];
}
return properties;
}
- (NSDictionary *) serializeToDictionary {
NSMutableDictionary *userDictionary = [NSMutableDictionary
dictionaryWithDictionary:[super serializeToDictionary]];
return userDictionary;
}
Now I have to replace the whole architecture with AFNetworking
I have replaced the
[[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];
with the following AFNetworking.
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc]
initWithRequest:request];
/// validates and decodes JSON responses.
operation.responseSerializer = [AFJSONResponseSerializer serializer];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
// succes code
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
// failure code
}];
// 5
[operation start];
My Question is, is this ok or do I need to change the serialization of objects also? Is it possible to replace the serialization protocol with any of the AFNetworking Classes?. If YES, please let me know how to change this.
Thanks in advance.
Your can use the following code.
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager POST:urlparameters:params success:^(AFHTTPRequestOperation *operation, id responseObject) {
// Success Code
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
// Failure Code
}];
You can use GET/POST depending on your requirements. Using AFNetworking you don't need to handle JSON parsing manually.
I switched from AFnetworking to RestKit. In AFnetworking had an API class. The API.h class contained the following.
#import <UIKit/UIKit.h>
typedef void (^JSONResponseBlock)(NSDictionary* json);
#interface API : NSObject
//the authorized user
#property (strong, nonatomic) NSDictionary* user;
+(API*)sharedInstance;
//check whether there's an authorized user
//send an API command to the server
-(void)loginCommand:(NSMutableDictionary*)params onCompletion:(JSONResponseBlock)completionBlock;
And my API.m class looks like this.
+(API *)sharedInstance
{
static API *sharedInstance = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^ {
sharedInstance = [[self alloc]initWithBaseURL:[NSURL URLWithString:kAPIHost]];
});
return sharedInstance;
}
#pragma mark - init
//intialize the API class with the destination host name
-(API *)init
{
//call super init
self = [super init];
if (self != nil){
//initialize the object
user = nil;
[self registerHTTPOperationClass:[AFJSONRequestOperation class]];
// Accept HTTP Header; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1
[self setDefaultHeader:#"Accept" value:#"application/json"];
}
return self;
}
-(void)loginCommand:(NSMutableDictionary *)params onCompletion:(JSONResponseBlock)completionBlock{
NSLog(#"%#%#",kAPIHost,kAPILogin);
NSMutableURLRequest *apiRequest = [self multipartFormRequestWithMethod:#"POST" path:kAPILogin parameters:params constructingBodyWithBlock:^(id <AFMultipartFormData>formData){
//TODO: attach file if needed
}];
AFJSONRequestOperation *operation = [[AFJSONRequestOperation alloc] initWithRequest:apiRequest];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject){
//success!
NSLog(#"SUCCESSSS!");
completionBlock(responseObject);
}failure:^(AFHTTPRequestOperation *operation, NSError *error){
//Failure
NSLog(#"FAILUREE!");
completionBlock([NSDictionary dictionaryWithObject:[error localizedDescription] forKey:#"error"]);
}];
[operation start];
}
Like you can see I only instantiate it once and put all my methods in over here. In my view controller I only need to call this method with a parameter-dictionary. Then I could read the whole JSON file.
Now with restKit I do this all on viewController level. I want to split it up like I did by AFNetworking. This is what I do in RestKit, At the moment is this all on viewController level.
//let AFNetworking manage the activity indicator
[AFNetworkActivityIndicatorManager sharedManager].enabled = YES;
// Initialize HTTPClient
NSURL *baseURL = [NSURL URLWithString:#"http://virtuele-receptie.preview.sanmax.be"];
AFHTTPClient* client = [[AFHTTPClient alloc] initWithBaseURL:baseURL];
//we want to work with JSON-Data
[client setDefaultHeader:#"Accept" value:RKMIMETypeJSON];
// Initialize RestKit
RKObjectManager *objectManager = [[RKObjectManager alloc] initWithHTTPClient:client];
//Do mapping
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:dataMapping
pathPattern:nil
keyPath:#"data"
statusCodes:[NSIndexSet indexSetWithIndex:200]];
[objectManager addResponseDescriptor:responseDescriptor];
NSDictionary *dict = [[NSDictionary alloc]initWithObjectsAndKeys:_txtLogin.text,#"email",_txtPass.text,#"pwd", nil];
[objectManager getObject:nil path:#"/nl/webservice/company-user/login/apikey/key12345678" parameters:dict
success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
//Success
}
failure:^(RKObjectRequestOperation *operation, NSError *error) {
//Failure
}];
So far with RestKit I haven't seen a huge need for an API class like you might create with other HTTP frameworks. RestKit has its own HTTP client (actually, just AFNetworking's client), so there's no need to have a class for your HTTP client, and I've found that each time I use the RKObjectManager I generally want access to the method parameters and block callbacks within each view controller. In other words, I don't want to run RestKit networking code in an API class, because I would essentially have to wrap the entire call in a method that can be accessed in the view controller (success block, failure block, etc).
In essence, RestKit's design lightens the networking code so much that in my experience with it - 3 or 4 apps now - I've yet to see enough reason write an API class like you describe.
I'm using AFHTTPClient from AFNetworking to make a call from my IOS app to my server, which is using Django with TastyPie. It's working great when I turn authentication off on the server side; however, when I require authentication and insert the proper username and password into my code, the I receive the following 401 authentication error:
\2012-09-16 00:24:37.877 RESTtest[76909:f803]
Complex AF: Error Domain=AFNetworkingErrorDomain Code=-1011
"Expected status code in (200-299), got 401"
UserInfo=0x686ba00 {AFNetworkingOperationFailingURLResponseErrorKey=<NSHTTPURLResponse: 0x686f130>,
NSErrorFailingURLKey=http://127.0.0.1:8000/api/v1/shoppinglist,
NSLocalizedDescription=Expected status code in (200-299), got 401,
AFNetworkingOperationFailingURLRequestErrorKey=<NSMutableURLRequest http://127.0.0.1:8000/api/v1/shoppinglist>}
Here is my code:
AFAPIClient.h
#import "AFHTTPClient.h"
#interface AFAPIClient : AFHTTPClient
-(void)setUsername:(NSString *)username andPassword:(NSString *)password;
+ (AFAPIClient *)sharedClient;
#end
AFAPIClient.m:
#import "AFAPIClient.h"
#import "AFJSONRequestOperation.h"
static NSString * const baseURL = #"http://#127.0.0.1:8000/api/v1";
#implementation AFAPIClient
+ (AFAPIClient *)sharedClient {
static AFAPIClient *_sharedClient = nil;
static dispatch_once_t pred;
dispatch_once(&pred, ^{
_sharedClient = [[AFAPIClient alloc] initWithBaseURL:[NSURL URLWithString:baseURL]];
//[_sharedClient setAuthorizationHeaderWithUsername:#"myusername" password:#"mypassword"]; I tried putting the authorization command here
});
return _sharedClient;
};
#pragma mark - Methods
-(void)setUsername:(NSString *)username andPassword:(NSString *)password;
{
[self clearAuthorizationHeader];
[self setAuthorizationHeaderWithUsername:username password:password];
}
- (id)initWithBaseURL:(NSURL *)url
{
self = [super initWithBaseURL:url];
if (!self) {
return nil;
}
[self registerHTTPOperationClass:[AFJSONRequestOperation class]];
[self setParameterEncoding:AFJSONParameterEncoding];
//[self setAuthorizationHeaderWithUsername:#"myusername" password:#"mypassword"]; I also tried putting the authorization command here
// Accept HTTP Header; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1
[self setDefaultHeader:#"Accept" value:#"application/json"];
return self;
}
#end
TQViewController.h:
[...]
- (IBAction)sendAFClientRequest:(id)sender {
//[[AFAPIClient sharedClient] setUsername:#"myusername" andPassword:#"mypassword"];
[[AFAPIClient sharedClient] getPath:#"shoppinglist" parameters:nil success:^(AFHTTPRequestOperation *operation, id response) {
NSLog(#"Complex AF: %#", [response valueForKeyPath:#"objects"]);
} failure:^(AFHTTPRequestOperation *operation, id response) {
NSLog(#"Complex AF: %#", response);
}
];
}
[...]
I know this isn't a problem with my server or my username/password, as I can authenticate just fine by inserting the username/password into the URL:
#"http://myusername:mypassword#127.0.0.1:8000/api/v1/shoppinglist"
Any help on this would be great. It would be wonderful to be able to use AFHTTPClient without inserting the authentication information directly into the static base URL, which seems completely improper. Thanks in advance!
Based on this: https://github.com/AFNetworking/AFNetworking/issues/426
I override the - (void)getPath:(NSString *)path parameters... method in the AFHTTPClient
subclass to look something like this:
- (void)getPath:(NSString *)path parameters:(NSDictionary *)parameters
success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure
{
NSURLRequest *request = [self requestWithMethod:#"GET" path:path parameters:parameters];
AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request success:success failure:failure];
[operation setAuthenticationChallengeBlock:^(NSURLConnection *connection, NSURLAuthenticationChallenge *challenge) {
NSURLCredential *newCredential = [NSURLCredential credentialWithUser:self.username password:self.password persistence:NSURLCredentialPersistenceForSession];
[challenge.sender useCredential:newCredential forAuthenticationChallenge:challenge];
}];
[self enqueueHTTPRequestOperation:operation];
}
It only adds the authentication challenge block to the AFHTTPRequestOpertaion, the rest is the same as the original implementation https://github.com/AFNetworking/AFNetworking/blob/master/AFNetworking/AFHTTPClient.m