How to manage sessions with AFNetworking?
Yes, your session ID should be sent automatically once you are logged in, as long as the cookie does not expire before the next request is sent (important detail to be sure of). NSURLConnection
, which AFNetworking uses, takes care of the details for this for you.
On the backend AFNetworking is using NSURLConnection
which in turn automatically updates NSHTTPCookieStorage
to store the session. You can manipulate or delete the cookies as you see fit by messing with the cookie storage.
Like if you wanted to appear to the service as not logged in, you could just delete the session cookie associated to that domain. Some services I have worked with will error if you are already logged in and attempt to login again. Additionally there was no way to check login status. Quick fix, get the cookies from URL and delete them :
NSArray *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL: networkServerAddress];
for (NSHTTPCookie *cookie in cookies)
{
[[NSHTTPCookieStorage sharedHTTPCookieStorage] deleteCookie:cookie];
}
From the developer himself
How do i set multiple http header using sessionManager (AFNetworking)
The Accept
header takes a comma separated list, so something like this should work:
[_sessionManager.requestSerializer setValue:@"application/json, application/xml" forHTTPHeaderField:@"Accept"];
Obviously replace application/xml
with whatever you need.
How to use AFNetworking in this situation?
Idea is to make use of blocks or delegates to inform other classes about the changes rather then putting the thread to sleep. Because am very much comfirtable with blocks lemme use blocks here.
The code provided here is only meant for explaining the concept and copy pasting may never work.
What to do :
I prefere creating a singleton class for web services though its completely optional and depends on your coding practices.
Have an array either in singleton model class that you will create to hold the array of currently running server or have a variable in app delegate so that it can be accessed by all the classes (preferably have a private variable and write setter and getter for it and make them public but then its up to you to declare property in .h as well)
Have a method in singleton class or in appdelegate that takes the completionblock as parameter and which will hit the master server get all the currently active servers and populate the array in model class and then invoke the completion block.
In ViewDidLoad or ViewWillAppear of your firstViewController check if array is nil or not if yes make call to the above declared method and pass a completion block to it when done your completion block will be involved and by the time it is invoked you will have the aray of urls as well.
Whenever url fails and server seems to be down call the same method again and pass the completion block to it repeat the same method as explained above.
Code
Assuming you are using AFNetworking updated version and making use of blocks here is the code. Even if you are using delegate approcah will be same.
Lets assume you have written a method named getActiveServers in appDelegate,
-(void)getActiveServers:(void(^)(NSError *)) completionBlock {
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.responseSerializer = [AFJSONResponseSerializer serializer];
[manager POST:@"http://myURL.com/user" parameters:dict success:^(AFHTTPRequestOperation *operation, id responseObject) {
//process the response get the array
//save it in array variable
self.activeServerArray = [responseObject valueForKey:@"serverArray"];
if (completionBlock) {
completionBlock(nil);
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
completionBlock(error);
}];
}
In viewDidLoad of yourViewControllers that makes the webservice call or at the beginning of any class that makes the webService class for that matter,
considering the example of ViewController here,
- (void)viewDidLoad {
[super viewDidLoad];
appdelegate=(AppDelegate *)[[UIApplication sharedApplication] delegate];
if(appDelegate.activeServerArray) {
//get the url you want and call your method to make webservice call
}
else {
[appdelegate getActiveServers:^(NSError *) {
if(error) {
//show alert fetching active server failed
}
else {
//call your method to make webservice call
}
}];
}
Finally in your method that calls the webservice if it finds out that server is down,
-(void)myMethodToMakeWebServiceCall {
//realised server down
appdelegate=(AppDelegate *)[[UIApplication sharedApplication] delegate];
[appdelegate getActiveServers:^(NSError *) {
if(error) {
//show alert fetching active server failed
}
else {
//call the same method to fetch the data now with updated url
[self myMethodToMakeWebServiceCall];
}
}];
}
Sharing session between AFNetworking and UIWebView
Actually, AFNetworking
and UIWebView
share the same cookies storage. So we don't need any special technique to let UIWebView
"share" a session initialized by AFNetworking
, or any native session-based request which uses NSHTTPCookieStorage
to store cookie. In my situation, the UIWebView
did not find shared session to be useful, just because the session initialized by AFNetworking
has lacked of a cookie which was sent only when browsing the site with a browser.
And here is what I did to solve the problem:
// Open a request to remote server with a User-Agent string set to the request header.
// We'll have browser-specific cookies in NSHTTPCookieStorage
NSString *userAgent = @"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36";
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.requestSerializer = [AFHTTPRequestSerializer serializer];
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
[manager.requestSerializer setValue:userAgent forHTTPHeaderField:@"User-Agent"];
[manager GET:kRemoteServerUrl parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
NSLog(@"Done");
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(@"Failure");
}];
Above code will ensure that we have all browser-specific cookies in NSHTTPCookieStorage, hence let the UIWebView
share any session initialized by native login routine.
AFNetworking 2 custom session manager
Well, the whole problem was that kMyBaseURL was:
#define kMGBaseURL @"http://example.com/api"
instead of
#define kMGBaseURL @"http://example.com/api/"
and later I've used links as @"/something"
instead of @"something"
.
Related Topics
How to Count Rows in a Parse Class Programmatically in an iOS App Using Swift
Please Clear Some Confusions Regarding Uiviewcontroller
What Is Nsmanagedobjectcontext's Performblock: Used For
How to Make Uibutton's Text Alignment Center? Using Ib
Why Does Uiviewcontroller Extend Under Uinavigationbar, While Uitableviewcontroller Doesn'T
How to Solve "Error Running Pod Install" in Flutter on MAC
How to Scroll to the Exact End of the Uitableview
How to Add Textfield to Uialertcontroller in Swift
App Transport Security Xcode 7 Beta 6
Custom Url Scheme for New Facebook iOS App
How to Use Multi-Path Update with the Rest API in Firebase? Error 400
Alamofire: Sending JSON as Request Parameter
Converting a Vision Vntextobservation to a String
How to Convert Nsinteger to Nsstring Datatype
Bringing a Subview to Be in Front of All Other Views
How Does Uiedgeinsetsmake Work
Xcode 8, iOS 10 - "Starting Webfilter Logging for Process"
Disable the Uitableview Highlighting But Allow the Selection of Individual Cells