Changing the architecture to AFNetworking in iOS - ios

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.

Related

AFNetworking : Re-use Method

We know that we can get return value from a normal method, for example :
-(NSString*)ASimpleFunction:(NSString*)str{
return str;
}
Calling this : [self ASimpleFunction:#"abc"] will return "abc".
If I have declared it in singleton class, so that I can use it from anywhere like:
+(NSString*)ASimpleFunction:(NSString*)str{
return str;
}
Calling it: [Singleton ASimpleFunction:#"xyz"] will return "xyz".
Hence above method, declared in Singleton class can be accessed/Re-used from anywhere by class name itself i.e. Singleton.
Similarly, I want to reuse the AFNetworking Method, I will pass NSDictionary of parameters , NSString for URL etc. But the thing is AFNetworking's Success and Failure blocks don't return values. So , I can't get reponseObject on success and error on failure in return.
Am I doing it right writing same code i.e, url, parameters, [success..]/[failure..] block again an again for each networking request?
Or is there is a good suggested architecture is available?
P.S - I have googled a lot for it but found nothing.
Here is how you can create your own helper class and use anywhere you can.
First let's create method to call AFNetworking response, success and failure:
+(void)getWebserviceWithURL:(NSString*)strUrl withParam:(NSDictionary*)dictParam withCompletion:(void(^)(NSDictionary*response))completion withFailure:(void(^)(NSDictionary*response))failure withLoadingText:(NSString*)text
{
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
AFJSONResponseSerializer *responseSerializer = [AFJSONResponseSerializer serializerWithReadingOptions:NSJSONReadingAllowFragments];
manager.responseSerializer = responseSerializer;
[manager GET:strUrl parameters:dictParam success:^(AFHTTPRequestOperation *operation, id responseObject) {
// [[Helper sharedInstance] dismissProgressBar];
completion(responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
failure([NSMutableDictionary dictionaryWithObjects:[NSArray arrayWithObjects:error, operation, nil] forKeys:[NSArray arrayWithObjects:#"error",#"operation", nil]]);
// [[Helper sharedInstance] dismissProgressBar];
}];
}
Now you can create your own method and get response, success and failure using the completion block:
- (void)WebSeries:(void(^)(bool status, NSMutableArray *seriesResponseData, NSString *compMessage))completion
{
//NSDictionary *dict = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:#"data", nil] forKeys:[NSArray arrayWithObjects:#"iComicBookId", nil]];
NSDictionary *dict = [NSDictionary dictionaryWithObject:#"1" forKey:#"fk_iWebSeriesId"];
[Helper postWebserviceWithURL:EPISODESURL withParam:dict withCompletion:^(NSDictionary *response) {
NSLog(#"%#",response);
NSMutableArray *webSeriesData = response[#"data"];
completion(YES, webSeriesData, response[#"msg"]);
} withFailure:^(NSDictionary *response) {
} withLoadingText:#"Loading"];
}
Hope this helps!

singleton class for webservices in ios

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:...];

AFNetworking replacing - Replace for AFHTTPClient

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

AFNetworking 2.0 implementation code not working

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
}];

handling the Response with the AFNetworking 2

i am really new to IOS development. i want to develop an application which is dealing with some web services and display in a table view. somehow i found a 3rd party library for do the networking stuffs [AFNetworking 2]. below is my code to get the json response for any given url and parameters.
-(NSDictionary*)getWebServiceResponce:(NSString *)url :(NSDictionary *)object
{
// NSDictionary *parameters = [[NSDictionary alloc] initWithObjectsAndKeys:#"47", #"caregiverPersonId", nil];
__block NSDictionary* result=Nil;
__block NSString* person=Nil;
AFSecurityPolicy *policy = [[AFSecurityPolicy alloc] init];
[policy setAllowInvalidCertificates:YES];
AFHTTPRequestOperationManager *operationManager = [AFHTTPRequestOperationManager manager];
[operationManager setSecurityPolicy:policy];
operationManager.requestSerializer = [AFJSONRequestSerializer serializer];
operationManager.responseSerializer = [AFJSONResponseSerializer serializer];
[operationManager POST:url
parameters:object
success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"JSON: %#", [responseObject description]);
person = [responseObject[#"d"]objectForKey:#"PersonId"];
// [self returnedResponce:responseObject];
result = (NSDictionary *) responseObject[#"d"];
NSLog(#"RESULT: %#", result);
NSLog(#"personm: %#", person);
[operation waitUntilFinished];
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", [error description]);
//result = [error];
}
];
return result;
}
this code works perfectly.. but my point is when i put some breakpoints to check what are the values i got for several variables, it shows null. but my log shows the entire json response.
and i want to return my response object as a dictionary. because i want to do some process with the response.. can some one help me with this ?
The problem is that result is nil when it gets returned. AFNetworking uses ObjC's awesome blocks, they get executed asynchronously. Read more about it here.
You should include a callback block in your getWebServiceResponce method. I've thrown together a bit of code but you should really read more about blocks.
-(void)webServiceResponceForURL:(NSString *)url dictionary:(NSDictionary *)object success:(void (^)(NSDictionary *responseObject))success {
// NSDictionary *parameters = [[NSDictionary alloc] initWithObjectsAndKeys:#"47", #"caregiverPersonId", nil];
__block NSDictionary* result=Nil;
__block NSString* person=Nil;
AFSecurityPolicy *policy = [[AFSecurityPolicy alloc] init];
[policy setAllowInvalidCertificates:YES];
AFHTTPRequestOperationManager *operationManager = [AFHTTPRequestOperationManager manager];
[operationManager setSecurityPolicy:policy];
operationManager.requestSerializer = [AFJSONRequestSerializer serializer];
operationManager.responseSerializer = [AFJSONResponseSerializer serializer];
[operationManager POST:url
parameters:object
success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"JSON: %#", [responseObject description]);
person = [responseObject[#"d"]objectForKey:#"PersonId"];
// [self returnedResponce:responseObject];
result = (NSDictionary *) responseObject[#"d"];
NSLog(#"RESULT: %#", result);
NSLog(#"personm: %#", person);
//We are executing the block as soon as we have the results.
if (success) {
success(responseObject);
}
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", [error description]);
//result = [error];
}
];
}
Edit:
[self webServiceResponceForURL:#"foo://foo" dictionary:nil success:^(NSDictionary *responseObject) {
//your code here
}
[self webServiceResponceForURL:#"foo://foo" dictionary:nil success:^(NSDictionary *responseObject) {
//your code here
}
Here you will got complete responseObject in form NSDictionary. You can assign responseObject to instance variable. Now This instance Variable will be used at point time. in your case, it will passed on button event.

Resources