Load all data from parse before displaying table - ios

I'm currently trying to populate a tableView with information stored on my Parse server (username, description, profile picture)
Currently... When I open the tableview I do not get any information showing, but if I click back and re open the table, all of my information shows and I'm unsure why that is.
A first get all information needed from Parse and store them into arrays like so:
let query = PFQuery(className: institutionTitle)
query.findObjectsInBackground {
(objects, error) in
if error == nil {
// The find succeeded.
// Do something with the found objects
if let objects = objects {
for object in objects {
self.postGrabber.append(object)
self.pSenderUsername.append(object["sender"] as! String)
self.pPostBody.append(object["textPost"] as! String)
}
}
} else {
// Log details of the failure
print("Error: \(error!)")
}
}
I'm currently using both the viewDidLoad() and viewWillAppear() to reloadData()
I then set the delegate and datasource of the table view in the viewDidLoad() function.
I then use the cellForRowAtIndexPath method to set up each cell on the table:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: UniversityFeedCellTableViewCell = tableView.dequeueReusableCell(withIdentifier: "postCell", for: indexPath) as! UniversityFeedCellTableViewCell
cell.sender.text = pSenderUsername[indexPath.section]
cell.senderPost.text = pPostBody[indexPath.section]
cell.profilePicture.layer.cornerRadius = cell.profilePicture.frame.size.width / 2
cell.profilePicture.layer.borderColor = UIColor.orange.cgColor
cell.backgroundColor = UIColor.white
return cell
}
I'm looking for some information on how I would make the user wait until all data has successfully loaded and has been populated. Would appreciate some help.
Thanks in advance and feel free to request more information from myself.

You need to reload data in table view after you have fetched all from your server... Something like this should do the trick:
let query = PFQuery(className: institutionTitle)
query.findObjectsInBackground {
(objects, error) in
if error == nil {
// The find succeeded.
// Do something with the found objects
if let objects = objects {
for object in objects {
self.postGrabber.append(object)
self.pSenderUsername.append(object["sender"] as! String)
self.pPostBody.append(object["textPost"] as! String)
}
dispatch_async(dispatch_get_main_queue(), {
self.tableView.reloadData() // Add this line and it should work
})
}
} else {
// Log details of the failure
print("Error: \(error!)")
}
}
If you want to load your data each time your view controller appears then do it in viewWillAppear(), otherWise, if you need to load data only first time, then in viewDidLoad()

You need to set callback method when u fetch json from server and then if result fetch you have to call reload method and mean while you can set indicator. Callback method done with fetch its will reload data
If u need some code example then i can mention the code hear

first you need to add this callback block in you .h file //Callback blocks
void (^successCallback)(id response);
void (^failCallback)(NSError *error);
+(BOOL)CallService3:(NSString*)serviceName postData:(NSString*)params qString:(NSString*)QueryStr callBackBlock:(void (^)(id response))responeBlock;
in you implementation file mean .m file create method for calling web api or web service
+(BOOL)CallService3:(NSString*)serviceName postData:(NSString*)params qString:(NSString*)QueryStr callBackBlock:(void (^)(id response))responeBlock{
NSString *jsonString =params;//if you have dictionary then [params JSONRepresentation];
NSString *post = [NSString stringWithFormat:#"json=%#", jsonString];
NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:NO];
NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
sessionConfiguration.HTTPAdditionalHeaders = #{
#"api-key" : #"API_KEY"
};
NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfiguration];
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"%#%#",baseURLS,serviceName]];
NSLog(#"url %#",[url absoluteString]);
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = #"GET";
NSURLSessionDataTask *postDataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSDictionary* jsonObject = [NSJSONSerialization JSONObjectWithData:data
options:kNilOptions
error:&error];
responeBlock(jsonObject);
}];
[postDataTask resume];
return TRUE;
}
After creating this method you have to call this for callback function
-(void)callWebApi{
//here you can call indicator if you need this class i can share with you
// [self startActivityIndicatorInView:self.view withMessage:#"please wait"];
[Connection CallService3:WebApi_Category postData:jsonstring qString:str callBackBlock:^(id response){
// NSLog(#"param .. %#",response);
// NSLog(#"%#",[response allKeys]);
//NSLog(#"param .. %#",response);
jsonArray=[[NSDictionary alloc]initWithDictionary:response];
dispatch_async(dispatch_get_main_queue(), ^(void){
//stop indicator here
// [self stopActivityIndicatorInView:self.view];
[self call_your_method_populating_table:[jsonArray objectForKey:kModel]];
//now call reload tableview
[_tableview reloadData];
});
}];
}

Related

Can't get result from NSURL

I'm trying to read remote txt file, which is located at remote hosting. I have a link, like http://www.link.com/file.txt.
I am using this code:
let myURLString = "http://google.com"
guard let myURL = NSURL(string: myURLString) else {
print("Error: \(myURLString) doesn't seem to be a valid URL")
return
}
do {
let myHTMLString = try String(contentsOfURL: myURL)
print("HTML : \(myHTMLString)")
} catch let error as NSError {
print("Error: \(error)")
}
But always getting empty string. File is not empty for sure.
I'm running my app on iOS simulator in Xcode.
What am I doing wrong?
Sorry for my bad English.
Don't use stringWithContentsOfURL and friends to retrieve data from a remote server. That's a synchronous API that was designed solely for use with local files. It isn't even guaranteed to work right for network requests on background threads, much less in your main thread.
The right way to retrieve data from remote URLs is with NSURLSession. I'm not a Swift programmer, so I'm not going to attempt a Swift snippet, but the Objective-C equivalent is:
NSURL *url = ...
NSURLSessionDataTask *task =
[NSURLSession sharedSession dataTaskWithURL:url
completionHandler:^(NSData *data,
NSURLResponse *response,
NSError *error) {
if (error) {
// Handle client-side errors here
} else if (((NSHTTPURLResponse *)response).statusCode != 200) {
// Handle server-side errors here
} else {
NSString *stock = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
// Do something with data here.
}
}];
[task resume];
Haven't test the code, but this should lead you on the right direction.
var statsRequest: String = "http://www.link.com/file.txt"
var statsRequestURL: NSURL = NSURL(string: statsRequest)!
var error: NSError? = nil
var stockNews: String = try! String.stringWithContentsOfURL(statsRequestURL, encoding: NSUTF8StringEncoding)
If the text file has a different encoding you can just use NSASCIIStringEncoding and then parse the html file.

How can I add Status code to an Error?

I have a 'JSON' data with different status codes, as shown in the image, I'm using 'AFHTTPSessionManager', And if we call the API I get 200 as success code, Apart from that in my response object I have status codes So I want to do different operations based on the status codes, For this I have written code like this..
-(void)validateOTP:(NSString *)OTP andUserID:(NSString *)userID withCompletion:(void(^)(NSDictionary* dictionary, NSError* error))completion
{
UTValidateOTPRequest *request = [UTValidateOTPRequest validateOTPRequestWithOTP:OTP andUserID:userID];
NSDictionary *paramDict = [request dictionaryRepresentation];
NSURLSessionDataTask *task = [self postRequestToResouce:[NSString stringWithFormat:#"%#/ValidateOTP",kServerCommonEndPoint] arguments:paramDict successHandler:^(NSDictionary *response) {
NSNumber *statusCode = response[kStatusCodeKey];
if (statusCode.integerValue == UTStatusCodeSuccess) {
completion(response, nil);
}
else {
NSError *error = [NSError mapStatusCodeToError:statusCode.integerValue details:response];
completion(nil, error);
}
} errorHandler:^(NSError *error) {
NSError *newError = [NSError mapStatusCodeToError:error.code details:error.userInfo];
completion(nil, newError);
}];
[self addDataTask:task];
}
As you can see, even inside success handler I'm passing error and calling a category method we have created.
NSError *error = [NSError mapStatusCodeToError:statusCode.integerValue details:response];
This method implemented as follows
+ (NSError *)mapStatusCodeToError: (NSInteger)statusCode details:(NSDictionary*) errorInfo
{
NSString *bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier];
NSString *domain = [bundleIdentifier stringByAppendingString:kErrorDomainKey];
NSString *errorMessage = nil;
if (errorInfo[kErrorMessageKey] && ![errorInfo[kErrorMessageKey] isEqualToString:kEmptyString]) {
errorMessage = errorInfo[kErrorMessageKey];
}
else{
// use common message
errorMessage = kInternetNotAvailableMessage;
}
NSDictionary *userInfo = #{NSLocalizedDescriptionKey:NSLocalizedString(errorMessage, nil)};
NSLog(#"User INFO : %#",userInfo);
NSError *internetUnavailableError = [NSError errorWithDomain:domain
code:NSURLErrorNotConnectedToInternet
userInfo:userInfo];
NSLog(#"Error Code : %ld",(long)internetUnavailableError.code);
return internetUnavailableError;
}
Here I want to use the statusCode that I'm passing as parameter to this method so that I can get that status code where I'm calling this method
[[UTServerManager sharedInstance] validateOTP:self.enterOTPText.text andUserID:self.userId withCompletion:^(NSDictionary *dictionary, NSError *error) {
// Here I want to get the status code of error not like -1009 , but what ever statusCode that I'm getting from the API response.
}];
So in this method can I get the response status code if it is not success code means as you see in the image in the first response is success and remaining are error responses.
And I know that I can use the statusCode in the category method but I dont know how to use it, If I store this status-Code in the category method for error as above , that I'm passing as a parameter to the methods then I can call them where ever I require How to get this ?
And my restriction is I should these methods only but I have to add the response status code to error ??
Looks like you are passing a userInfo dict to the NSError. You could add to this dictionary prior to creating the NSError you are returning, and then later it would be available in the NSError callback.

How to return a value from a function that is generated from a parse query within the function?

Problem: when I call the below function within my ViewController tableView cellForRowAtIndexPath method, I get nil, but I need to set the generated object to a PFObject variable called rankObject that I declared globally in my ViewController. I've tried a lot of things, including completion handlers, and am still stuck. How would I accomplish this task?
func getOrMakeRankRelations(sound: PFObject) {
var rankRelation = sound.relationForKey("userRanks")
let currentUser = PFUser.currentUser()!
var relationQuery = rankRelation.query()
relationQuery?.whereKey("user", equalTo: currentUser)
relationQuery?.findObjectsInBackgroundWithBlock { (theObject: [AnyObject]?, error: NSError?) -> Void in
if (theObject?.isEmpty == true) {
println("Rank object is empty")
//Make Ranking PFObject
var ranking = PFObject(className: "Ranking")
ranking["user"] = PFUser.currentUser()!
ranking["Rank"] = 0
//Upload ranking to Parse
ranking.saveInBackgroundWithBlock { (saved: Bool, error: NSError?) -> Void in
if saved {
println("Saved ranking")
//Add relation between sound and ranking
rankRelation.addObject(ranking)
sound.saveInBackgroundWithBlock { (saved: Bool, error: NSError?) -> Void in
if saved {
println("Saved relation")
var theObject = (theObject![0] as? PFObject)!
self.rankObject = theObject //////////NOTE: the variable saves while in this closure /////////////
} else {
println("Relation not saved :(")
}
}
} else {
println(error)
}
}
} else {
var theObject = (theObject![0] as? PFObject)!
self.rankObject = theObject //////////NOTE: the variable also saves while in this closure /////////////
}
}
}
Here is how I call the function in tableView:
getOrMakeRankRelation(sound)
Not dealing with the specifics of the asynch call, just the fact that it is asynchronous, in Objective-C (and Swift) we declare a function to take at least two parameters: whatever is needed to parameterize the remote request, and a block to run when the request completes.
Reading your code, I'd also advise breaking the get and the create part into their own functions, just to remain sane, so...
- (void)getOrCreateRankForSound:(PFObject *)sound completion:(void (^)(PFObject *, NSError *))completion {
[self getRankForSound:sound completion:^(PFObject *rank, NSError *error) {
if (!rank && !error) { // there's no rank, and no error either, so we must create one
[self createRankForSound:sound completion:^(PFObject *rank, NSError *error) {
completion(rank, error);
}];
} else {
completion(rank, error);
}
}];
}
- (void)createRankForSound:(PFObject *)sound completion:(void (^)(PFObject *, NSError *))completion {
// build a PFObject rank for the sound, then save it and tell our
// caller what happened by invoking the completion block
// ...
[newlyCreatedRank saveInBackgroundWithBlock:^(BOOL success, NSError *error) {
return (success)? completion(newlyCreatedRank, nil) : completion(nil, error);
}];
}
Now your cellForRowAtIndexPath can safely call this method, because it caches the results.
// pseudo code in cellForRowAtIndexPath
PFObject *sound = self.myDatasourceArray[indexPath.row];
// we want to change some cell subview to present the rank object
// don't make network requests in this method without caching the result
// assume we have a dictionary of rank objects indexed by the sound object id to which they correspond
PFObject *rank = self.ranksForSound[sound.objectId];
if (rank) {
// no need to make a network request, use the rank, presumably to update the cell
cell.rankLabel.text = // some function of rank
} else {
// we need to make a network request, put a placeholder value in the cell and call our function
cell.rankLabel.text = // some placeholder value
[self getOrCreateRankForSound:sound completion:^(PFObject *rank, NSError *error) {
// this is important, the cell might have scrolled away by the time this block runs
// don't alter the cell directly, just reload it. cellForRowAtIndexPath will
// get called again, but now the cache will be primed
if (!error) {
[tableView reloadRowsAtIndexPaths:#[indexPath]];
}
}];
}
// configure other parts of the cell
return cell;

Retrieving data from web service and populating SQLite3 database efficiently

I am currently developing an app that that will be used by association members that are going to a large annual conference.
The app will pull data from a database that is created by the app and populate it via a web service. The web service is split into 8 pages (this will likely go up). Each page represents a table in the database. The app will have several table views that will be populated by data in one or more of the tables in the database.
What I need is a the best method for going through the list of tables, connecting to their respective web service pages and then populating the respective database tables. This updating needs to take place in the background so the UI doesn't become unresponsive and/or show a downloading/updating/waiting kind of status.
So far I have a static array of the table names and have a loop that goes through the array and appends a URL string with the names, for example:
-(void)startUpdate
{
NSArray* tableNames = #[#"speaker", #"exhibitor", #"workshop", #"workshopspeakers", #"schedule", #"location", #"feedback", #"note", #"usage", #"user"];
NSUInteger loopCount = tableNames.count;
for (int i = 0; i < loopCount; ++i){
NSString *tableName = [tableNames objectAtIndex:i];
[self fetchObjectsWithTableName:[tableName mutableCopy] completion:^(NSArray* objects, NSError*error){
if (error) {
} else {
}
}];
}
}
fetchObjectsWithTableName method then has the connections and retrieves the data:
-(void)fetchData:(NSString *)tableName
withCompletion:(completion_t)completionHandler
{
NSString *currentURL = [NSString stringWithFormat:#"https://testapi.someURL.com/api/congress/%#", tableName];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:currentURL]];
[request addValue:#"application/json" forHTTPHeaderField:(#"Accept")];
[NSURLConnection sendAsynchronousRequest:request
queue:[[NSOperationQueue alloc] init]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
{
NSError* err = error;
NSArray* objects; // final result array as a representation of JSON Array
if (response) {
NSHTTPURLResponse *newResp = (NSHTTPURLResponse*)response;
if (newResp.statusCode == 200) {
NSLog(#"FetchData - Status code = %li", (long)newResp.statusCode);
if ([data length] >0 && error == nil)
{
NSError* localError;
objects = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
if (objects) {
if (completionHandler) {
completionHandler(objects, nil);
}
//NSLog(#"Objects in current table - %# = %#", tableName, objects);
[self.tables addObject:objects];
// NSLog(#"Tables now = %#", self.tables);
NSLog(#"FetchData - Objects in current table - %# = %lu", tableName, (unsigned long)objects.count);
return;
} else {
err = localError;
}
} else {
NSLog(#"FetchData - objects is empty");
return;
// err = ...
}
}
NSLog(#"FetchData - Response code not 200#");
}
if (objects == nil) {
NSLog(#"FetchData - Nothing found in table: %#", tableName);
//assert(err);
if (completionHandler) {
completionHandler(nil, err);
}
}
}];
}
This currently goes through the array of table names, makes a connection based on each one and pulls back JSON data and stores it in a temporary array 'objects'. I think what I need now is that in each iteration of this 'objects' array is copied to the relevant table in the database, i.e. 'speaker' table name makes a connection: https://testapi.someURL.com/api/congress/speaker and the JSON is entered into the database under the table 'speaker'. How and where do I do that? Will I need to add a completion handler to startUpdate? If so, how? I don't understand completion handlers despite looking at several examples. Thanks.
No, do it in the NSURLConnection completion block after you have updated your temporary storage.
But, change your approach overall.
If you're only willing to change a bit, start using NSOperationQueue to limit the number of connections that you're trying to make at the same time. Preferably also use Core Data.
If you're willing to make a bigger change, definitely move to Core Data and look at using a framework like RestKit to do all of the download, mapping and storage for you.
(note, in both cases you need to set the max concurrent operation limit to prevent the app from flooding the network with requests - a limit of 5 should be good).

AFNetworking: Handle error globally and repeat request

I have a use case that should be rather common but I can't find an easy way to handle it with AFNetworking:
Whenever the server returns a specific status code for any request, I want to:
remove a cached authentication token
re-authenticate (which is a separate request)
repeat the failed request.
I thought that this could be done via some global completion/error handler in AFHTTPClient, but I didn't find anything useful. So, what's the "right" way to do what I want? Override enqueueHTTPRequestOperation: in my AFHTTPClient subclass, copy the operation and wrap the original completion handler with a block that does what I want (re-authenticate, enqueue copied operation)? Or am I on the wrong track altogether?
Thanks!
EDIT: Removed reference to 401 status code, since that's probably reserved for HTTP basic while I'm using token auth.
I use an alternative means for doing this with AFNetworking 2.0.
You can subclass dataTaskWithRequest:success:failure: and wrap the passed completion block with some error checking. For example, if you're working with OAuth, you could watch for a 401 error (expiry) and refresh your access token.
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)urlRequest completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))originalCompletionHandler{
//create a completion block that wraps the original
void (^authFailBlock)(NSURLResponse *response, id responseObject, NSError *error) = ^(NSURLResponse *response, id responseObject, NSError *error)
{
NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
if([httpResponse statusCode] == 401){
NSLog(#"401 auth error!");
//since there was an error, call you refresh method and then redo the original task
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
//call your method for refreshing OAuth tokens. This is an example:
[self refreshAccessToken:^(id responseObject) {
NSLog(#"response was %#", responseObject);
//store your new token
//now, queue up and execute the original task
NSURLSessionDataTask *originalTask = [super dataTaskWithRequest:urlRequest completionHandler:originalCompletionHandler];
[originalTask resume];
}];
});
}else{
NSLog(#"no auth error");
originalCompletionHandler(response, responseObject, error);
}
};
NSURLSessionDataTask *task = [super dataTaskWithRequest:urlRequest completionHandler:authFailBlock];
return task;
}
In the AFHTTPClient's init method register for the AFNetworkingOperationDidFinishNotification which will be posted after a request finishes.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(HTTPOperationDidFinish:) name:AFNetworkingOperationDidFinishNotification object:nil];
In the notification handler check the status code and copy the AFHTTPRequestOperation or create a new one.
- (void)HTTPOperationDidFinish:(NSNotification *)notification {
AFHTTPRequestOperation *operation = (AFHTTPRequestOperation *)[notification object];
if (![operation isKindOfClass:[AFHTTPRequestOperation class]]) {
return;
}
if ([operation.response statusCode] == 401) {
// enqueue a new request operation here
}
}
EDIT:
In general you should not need to do that and just handle the authentication with this AFNetworking method:
- (void)setAuthenticationChallengeBlock:(void (^)(NSURLConnection *connection, NSURLAuthenticationChallenge *challenge))block;
Here is the Swift implementation of user #adamup 's answer
class SessionManager:AFHTTPSessionManager{
static let sharedInstance = SessionManager()
override func dataTaskWithRequest(request: NSURLRequest!, completionHandler: ((NSURLResponse!, AnyObject!, NSError!) -> Void)!) -> NSURLSessionDataTask! {
var authFailBlock : (response:NSURLResponse!, responseObject:AnyObject!, error:NSError!) -> Void = {(response:NSURLResponse!, responseObject:AnyObject!, error:NSError!) -> Void in
var httpResponse = response as! NSHTTPURLResponse
if httpResponse.statusCode == 401 {
//println("auth failed")
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), { () -> Void in
self.refreshToken(){ token -> Void in
if let tkn = token{
var mutableRequest = request.mutableCopy() as! NSMutableURLRequest
mutableRequest.setValue(tkn, forHTTPHeaderField: "Authorization")
var newRequest = mutableRequest.copy() as! NSURLRequest
var originalTask = super.dataTaskWithRequest(newRequest, completionHandler: completionHandler)
originalTask.resume()
}else{
completionHandler(response,responseObject,error)
}
}
})
}
else{
//println("no auth error")
completionHandler(response,responseObject,error)
}
}
var task = super.dataTaskWithRequest(request, completionHandler:authFailBlock )
return task
}}
where refreshToken (...) is an extension method I wrote to get a new token from the server.
Took a similar approach, but I couldn't get the status code object with phix23's answer so I needed a different plan of action. AFNetworking 2.0 changed a couple of things.
-(void)networkRequestDidFinish: (NSNotification *) notification
{
NSError *error = [notification.userInfo objectForKey:AFNetworkingTaskDidCompleteErrorKey];
NSHTTPURLResponse *httpResponse = error.userInfo[AFNetworkingOperationFailingURLResponseErrorKey];
if (httpResponse.statusCode == 401){
NSLog(#"Error was 401");
}
}
If you are subclassing AFHTTPSessionManager or using directly an AFURLSessionManager you could use the following method to set a block executed after the completion of a task:
/**
Sets a block to be executed as the last message related to a specific task, as handled by the `NSURLSessionTaskDelegate` method `URLSession:task:didCompleteWithError:`.
#param block A block object to be executed when a session task is completed. The block has no return value, and takes three arguments: the session, the task, and any error that occurred in the process of executing the task.
*/
- (void)setTaskDidCompleteBlock:(void (^)(NSURLSession *session, NSURLSessionTask *task, NSError *error))block;
Just perform whatever you want to do for each tasks of the session in it:
[self setTaskDidCompleteBlock:^(NSURLSession *session, NSURLSessionTask *task, NSError *error) {
if ([task.response isKindOfClass:[NSHTTPURLResponse class]]) {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)task.response;
if (httpResponse.statusCode == 500) {
}
}
}];
EDIT:
In fact if you need to handle an error returned in the response object the above method won't do the job.
One way if you are subclassing AFHTTPSessionManager could be to subclass and set a custom response serializer with it's responseObjectForResponse:data:error: overloaded like that:
#interface MyJSONResponseSerializer : AFJSONResponseSerializer
#end
#implementation MyJSONResponseSerializer
#pragma mark - AFURLResponseSerialization
- (id)responseObjectForResponse:(NSURLResponse *)response
data:(NSData *)data
error:(NSError *__autoreleasing *)error
{
id responseObject = [super responseObjectForResponse:response data:data error:error];
if ([responseObject isKindOfClass:[NSDictionary class]]
&& /* .. check for status or error fields .. */)
{
// Handle error globally here
}
return responseObject;
}
#end
and set it in your AFHTTPSessionManager subclass:
#interface MyAPIClient : AFHTTPSessionManager
+ (instancetype)sharedClient;
#end
#implementation MyAPIClient
+ (instancetype)sharedClient {
static MyAPIClient *_sharedClient = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_sharedClient = [[MyAPIClient alloc] initWithBaseURL:[NSURL URLWithString:MyAPIBaseURLString]];
_sharedClient.responseSerializer = [MyJSONResponseSerializer serializer];
});
return _sharedClient;
}
#end
To ensure that multiple token refreshes are not issued at around the same time, it is beneficial to either queue your network requests and block the queue when the token is refreshing, or add a mutex lock (#synchronized directive) to your token refresh method.

Resources