App crashed when using QBSimpleSyncRefreshControl in tableview pull to refresh - ios

I'm using tabview controller, one of the view controller having table view I use QBSimpleSyncRefreshControl for pull down refresh, its working fine in first time load tab controller,
when I logout my user, I reload my Tab controller (root view controller) that time app crashed unexpectedly.
This is the code I'm using
in tableview controller
QBSimpleSyncRefreshControl *refreshControl = [[QBSimpleSyncRefreshControl alloc] init];
refreshControl.delegate = self;
self.myRefreshControl = refreshControl;
[self.tvTableView addSubview:self.myRefreshControl];
i did in logout
UIStoryboard *board = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
UINavigationController *Tabctrl = [board instantiateViewControllerWithIdentifier:#"vcInitialViewNavId"];
UIWindow *window = AppDelegate.window;
[window addSubview:Tabctrl.view];
window.rootViewController = Tabctrl;
If I block this line
[self.tvTableView addSubview:self.myRefreshControl];
App working fine, If unblock this app crashed when logout (Reload root view controller)
Can anyone help for this.
Full code Here:
view.h File
#interface MyTCView : UIViewController <UICollectionViewDataSource, UICollectionViewDelegate, QBRefreshControlDelegate>
{
// some declaration here
}
#property (weak, nonatomic) IBOutlet UITableView *tvTableView;
#property (nonatomic, strong) QBSimpleSyncRefreshControl *myRefreshControl;
view.m
- (void)viewDidLoad
{
[super viewDidLoad];
FeaturedItemTitle = #"";
HUD = [[MBProgressHUD alloc] initWithView:self.view];
HUD.mode = MBProgressHUDModeIndeterminate;
[self.view addSubview:HUD];
AppDelegate = (TCAppDelegate *) [UIApplication sharedApplication].delegate;
board = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
QBSimpleSyncRefreshControl *refreshControl = [[QBSimpleSyncRefreshControl alloc] init];
refreshControl.delegate = self;
self.myRefreshControl = refreshControl;
[self.tvTableView addSubview:self.myRefreshControl];
}
- (void)refreshControlDidBeginRefreshing:(QBRefreshControl *)refreshControl
{
[self GetDetails];
}
-(void) GetDetails
{
// Calling web service here
NSString *strURL = #"URL HERE";
NSURL *url = [NSURL URLWithString: strURL];
NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:url];
[theRequest addValue: #"text/xml; charset=utf-8" forHTTPHeaderField:#"Content-Type"];
[theRequest setHTTPMethod:methodType];
NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:delegate];
if ( theConnection ) {
//Connection successful
receivedData = [NSMutableData data];
} else {
//Failure
NSLog(#"Error");
}
}
//*** HTTP Connection ***//
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
receivedData = [[NSMutableData alloc] init];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[receivedData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
[HUD hide:YES];
[self ShowAlertMessage:ServerErrorMsg Tilte:#""];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSError *error;
NSDictionary *res = [NSJSONSerialization JSONObjectWithData:receivedData options:NSJSONReadingAllowFragments error:&error];
// Array of data get from Res(NSDictionary)
[tvTableView reloadData]; // Tableview Reload
[collView reloadData]; // Collectionview reload
[self.myRefreshControl endRefreshing];
[HUD hide:TRUE];
}

I think this is not the right way to logout a navigationcontroller based application, just use the standard way to load the rootController using
[self.navigationController popToRootViewControllerAnimated:YES];

Related

Pass json response to another view controller in iOS

At first i just send data to server using GET method, I receive a response like below
2015-11-16 14:21:42.168 smartschool[1963:348015] Item actcode: ZQRTNN68
2015-11-16 14:21:42.169 smartschool[1963:348015] Item parentid: 8
How can i display the activation code to a label of the next viewController.
Here is my code:
#import "RegistrationViewController.h"
#interface RegistrationViewController ()
#end
#implementation RegistrationViewController
{
NSMutableData *mutableData;
#define URL #"http://192.168.1.166/bustracking/activation/requestActivationCode"
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
-(IBAction)sendDataUsingGet:(id)sender{
[self sendDataToServer : #"GET"];
}
-(void) sendDataToServer : (NSString *) method
{
NSString *parentName = parent_name.text;
NSString *contactNumber = contact_number.text;
NSString *beaconid = #"145801000095";
//NSString *beaconMacAdd = #"14:58:01:00:00:95";
if(parentName.length > 0 && contactNumber.length > 0){
NSLog (#"Getting response from server...");
NSMutableURLRequest *request = nil;
// Only Difference between POST and GET is only in the way they send parameters
if([method isEqualToString:#"GET"]){
NSString *getURL = [NSString stringWithFormat:#"%#?parent_name=%#&contact_number=%#&beacon_id=%#", URL, parentName, contactNumber, beaconid];
//url = [NSURL URLWithString: getURL];
getURL = [getURL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *url = [NSURL URLWithString: getURL];
request = [NSMutableURLRequest requestWithURL:url];
NSLog(#"urlinfo: %#", url);
NSLog(#"link: %#", getURL);
}
[request setHTTPMethod:method];
[request addValue: #"application/x-www-form-urlencoded; charset=utf-8" forHTTPHeaderField:#"Content-Type"];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
NSLog(#"connection: %#", connection);
if( connection )
{
mutableData = [NSMutableData new];
}
else
{
NSLog (#"NO_CONNECTION");
return;
}
}
else
{
NSLog(#"NO_VALUES");
}
}
#pragma mark NSURLConnection delegates
-(void) connection:(NSURLConnection *) connection didReceiveResponse:(NSURLResponse *)response
{
[mutableData setLength:0];
}
-(void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[mutableData appendData:data];
}
-(void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog (#"NO_CONNECTION");
return;
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSError *error = nil;
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:mutableData options:kNilOptions error:&error];
NSArray *fetchedArr = [json objectForKey:#"response"];
NSString *responseActCode;
for (NSDictionary *user in fetchedArr)
{
responseActCode = [user objectForKey:#"activation_code"];
NSLog(#"Item actcode: %#", responseActCode);
NSLog(#"Item parentid: %#", [user objectForKey:#"parent_id"]);
//NSLog(#"Item actcode: %#", [user objectForKey:#"activation_code"]);
}
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:responseActCode forKey:#"HighScore"];
[defaults synchronize];
NSLog(#"from data: %#", [defaults objectForKey:#"HighScore"]);
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:#"Activation Code"
message:(#"%#", responseActCode)
delegate:nil //or self
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
#end
If the returning data is in dictionary format, declare nsdictionary in header.h class on which you wan to transfer data, similarly you can use array and string, now if you are using a storyboard, below is the method.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Make sure your segue name in storyboard is the same as this line
if ([[segue identifier] isEqualToString:#"YOUR_SEGUE_NAME_HERE"])
{
// Get reference to the destination view controller
YourViewController *vc = [segue destinationViewController];
// Pass any objects to the view controller here, like...
vc.dictionary = self.dictionary.
}
}
and you want to transfer data upon cell tap this is what you have to do.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self performSegueWithIdentifier:#"YOUR_SEGUE_NAME_HERE"" sender:self];
}
When "performSegueWithIdentifier" is called, this method automatically redirected to "prepareForSegue" method:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSIndexPath *indexPath= [self.tableView indexPathForSelectedRow];
// Make sure your segue name in storyboard is the same as this line
if ([[segue identifier] isEqualToString:#"YOUR_SEGUE_NAME_HERE"])
{
// Get reference to the destination view controller
YourViewController *vc = [segue destinationViewController];
// Pass any objects to the view controller here, like...
now this time its array.
vc.array= [array[indexpath.row] valueforkey#"jsonkey"];
}
}
There are many ways to pass data between view controllers. Here's one example:
Create a public property in "SomeViewController" class(eg: responseActCodeString) and set that property to your activation code(eg: responseActCode).
SomeViewController *someViewController = [[SomeViewController alloc] initWithNib:#"SomeViewController " bundle:nil];
someViewController.responseActCodeString = responseActCode;
[self pushViewController:someViewController animated:YES];
You can also use notifications, user defaults as an alternatives.
Also look at this link.
For storyboards add following method in initial view controller:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([segue.identifier isEqualToString:#"someIdentifier"]){
SomeViewController*someViewController= (SomeViewController*)segue.destinationViewController;
someViewController.responseActCodeString = responseActCode;
}
}

My app is asking for permission to “Have offline access”, why?

My app is asking for permission to “Have offline access”, why? It's the weirdest thing. I've done a bit of searching and haven't really found anything that's worked. I've tried using these for scopes:
https://www.googleapis.com/auth/plus.profile.emails.read
https://www.googleapis.com/auth/plus.login
and that didn't seem to help.
Below is a screenshot and some of my code to help you see what's going on:
Some of my code:
#import "ViewController.h"
NSString *callbakc = #"http://localhost/";
NSString *client_id = #“CLIENT ID“;
NSString *scope = #"https://www.googleapis.com/auth/userinfo.email+https://www.googleapis.com/auth/userinfo.profile+https://www.google.com/reader/api/0/subscription";
NSString *secret = #“SECRET”;
NSString *visibleactions = #"http://schemas.google.com/AddActivity";
#interface ViewController () {
NSString *authAccessToken;
UIAlertController *alertController;
}
#property (strong, nonatomic) NSMutableData *receivedData;
#property (weak, nonatomic) IBOutlet UIWebView *webView;
#end
#implementation ViewController
#pragma mark - Lifecycle
- (void)viewDidLoad {
[super viewDidLoad];
NSString *url = [NSString stringWithFormat:#"https://accounts.google.com/o/oauth2/auth?response_type=code&client_id=%#&redirect_uri=%#&scope=%#&data-requestvisibleactions=%#",client_id,callbakc,scope,visibleactions];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url] cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:10];
[_webView loadRequest:request];
}
#pragma mark - WebView Delegate
- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType {
[self performSelector:#selector(progressDelay:) withObject:nil afterDelay:0.0];
if ([[[request URL] host] isEqualToString:#"localhost"]) {
// Extract oauth_verifier from URL query
NSString* verifier = nil;
NSArray* urlParams = [[[request URL] query] componentsSeparatedByString:#"&"];
for (NSString* param in urlParams) {
if (![param isEqualToString:#"error=access_denied"]) {
NSArray* keyValue = [param componentsSeparatedByString:#"="];
NSString* key = [keyValue objectAtIndex:0];
if ([key isEqualToString:#"code"]) {
verifier = [keyValue objectAtIndex:1];
// NSLog(#"verifier %#",verifier);
break;
}
}
else {
[self.navigationController popViewControllerAnimated:NO];
}
}
if (!verifier==0) {
[self showAlertViewWithTitle:#"" message:#"Please wait" okAction:NO];
NSString *data = [NSString stringWithFormat:#"code=%#&client_id=%#&client_secret=%#&redirect_uri=%#&grant_type=authorization_code", verifier,client_id,secret,callbakc];
NSString *url = [NSString stringWithFormat:#"https://accounts.google.com/o/oauth2/token"];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:url]];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:[data dataUsingEncoding:NSUTF8StringEncoding]];
[request setHTTPShouldHandleCookies:NO];
NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
NSLog(#"Connection: %#", theConnection);
self.receivedData = [[NSMutableData alloc] init];
}
else {
// cancel button click
NSLog(#"not Verified!!");
}
return NO;
}
return YES;
}
- (void)webViewDidStartLoad:(UIWebView *)webView {
// show progress
}
- (void)webViewDidFinishLoad:(UIWebView *)webView {
[alertController dismissViewControllerAnimated:YES completion:nil];
}
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
if (error.code==102) //Frame load interrupted
return;
[alertController dismissViewControllerAnimated:YES completion:nil];
[self showAlertViewWithTitle:#"Error" message:[error localizedDescription] okAction:YES];
}
#pragma mark - NSURLConnection Delegate
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[self.receivedData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
[self showAlertViewWithTitle:#"Error" message:[NSString stringWithFormat:#"%#", error] okAction:YES];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSString *response = [[NSString alloc] initWithData:self.receivedData encoding:NSUTF8StringEncoding];
NSData *data = [response dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *tokenData = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
if ([tokenData objectForKey:#"access_token"]) {
authAccessToken = [tokenData objectForKey:#"access_token"];
[self getUserInfo:authAccessToken];
}
else {
[alertController dismissViewControllerAnimated:YES completion:nil];
NSLog(#"RESULT: %#", tokenData);
[self showAlertViewWithTitle:[tokenData objectForKey:#"name"] message:[NSString stringWithFormat:#"%#", tokenData] okAction:YES];
// Flush all cached data
[[NSURLCache sharedURLCache] removeAllCachedResponses];
}
}
#pragma mark - Private Method Implementation
-(void)getUserInfo:(NSString *)token {
NSString *url = [NSString stringWithFormat:#"https://www.googleapis.com/oauth2/v1/userinfo?access_token=%#",token];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:url]];
[request setHTTPMethod:#"GET"];
[request setHTTPShouldHandleCookies:NO];
NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:request delegate:self];
NSLog(#"Connection: %#", theConnection);
self.receivedData = [[NSMutableData alloc] init];
}
-(void)progressDelay:(id)sender {
// Dismiss progress
}
#end
Any help would be greatly appreciated!
Thank you
This is from https://stackoverflow.com/questions/32210920/why-is-my-app-asking-for-permission-to-have-offline-access?answertab=oldest#tab-top:
This is normal behavior and occurs when the user has granted
permission already.
Basically, no need to worry about it unless you really don't want that
showing up, in that case, you need to un auth the users old token
before requesting a new one.
I'm not exactly sure how because I haven't done this before, but before you authorize a new token you need to un-authorize the old one.
You'll need to modify the -(void)getUserInfo:(NSString *)token method.
For some reason unknown to me. The email scope pops up with
Have offline access
If you want to remove the have offline access remove the email scope. Personally I think it is miss leading to users that you are asking for email access yet are prompted for offline access. Technically speaking all OAuth2 that returns a refresh token gives offline access so the user should always be told that you are getting offline access but it doesnt.

Delay displaying a LoginViewController

I have this app that uses an accessToken that only remains for two hours. My app has three UINavigationController (with UITableViewController) inside a UITabBarController. Every time I click on one of my tabs, a new connection is created and I check if the statusCode of the HTTP response is 200 or 401. If the statusCode is 401 is because my accessToken is no longer operative and I have to relog again.
The problem I have is that when the current viewController calls the LoginViewController because the 401, the LoginViewController shows with delay and you can see the cells of UITableViewController.
My code is:
- (void)viewDidLoad
{
[super viewDidLoad];
[self.tableView registerClass:[CaseCell class] forCellReuseIdentifier:#"identifier"];
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
self.accessToken = [userDefaults objectForKey:#"accessToken"];
if (self.accessToken == nil) {
LoginViewController *loginViewController = [[LoginViewController alloc] init];
[self presentViewController:loginViewController animated:NO completion:nil];
} else {
[self refresh];
}
}
- (void)refresh
{
NSURLSession *session = [NSURLSession sharedSession];
NSString *urlString = [[NSString alloc] initWithFormat:#"myURL", self.accessToken];
NSURL *url = [[NSURL alloc] initWithString:urlString];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
NSURLSessionDownloadTask *task = [session downloadTaskWithRequest:request completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
NSData *data = [[NSData alloc] initWithContentsOfURL:location];
NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
NSInteger statusCode = [httpResponse statusCode];
if (statusCode == 200) {
NSArray *responseArray = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
self.cases = responseArray;
}
dispatch_async(dispatch_get_main_queue(), ^{
if (statusCode == 200) {
[self.tableView reloadData];
} else {
LoginViewController *loginViewController = [[LoginViewController alloc] init];
[self presentViewController:loginViewController animated:NO completion:nil];
}
});
}];
[task resume];
}
I really don't know what is the problem. I mean, I know it has to be related with things happening in background and dispatch_async but I've made everything and I don't know why this delay.
PD: Don't pay attention to NSUserDefaults. I know I have to store the token in Keychain.
THANK YOU VERY MUCH!
You could use the delegate method
- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController
that gets called by your UITabBarController to check that the session is still valid, and then either proceed to the view controller or launch your login controller. If you try adding it to the view controller's view before the view loads, it won't have anything to add it to, and if you call it after the view loads, you're going to see the original view before it can launch the login screen.

Push to new ViewController from connectionDidFinishLoading

Is it possible to push to a new view controller from ConnectionDidFinishLoading ?
I have the following and it performs the ConnectionDidFinishLoading but does not push to new view controller.
-(void)connectionWithURLString:(NSMutableArray *)urlString
{
NSDate *now = [NSDate date];
int userID = [[clientDataStruct.clientData objectForKey:#"number"] intValue];
NSDate *date = self.datePicker.date;
// NSLog(#"obj: %#", urlString);
NSString *extrString = [NSString stringWithFormat:#", customerdetails:{customer_id = %d, job_date = %#, date_created = %#}",userID,date, now];
NSString *post = [NSString stringWithFormat:#"json=quote:{%#%#}", urlString, extrString ];
NSLog(#"post: %#", post);
NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:NO];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *value = [defaults objectForKey:#"value"];
NSString *jsonUrl = [NSString stringWithFormat:#"xxx?task=add_quote&user_id=%#&customer_id=%#",value, [clientDataStruct.clientData valueForKey:#"number"]];
[request setURL:[NSURL URLWithString:jsonUrl]];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:postData];
NSURLConnection *connection = [NSURLConnection connectionWithRequest:request delegate:self];
if (!connection)
NSLog(#"Connection failed!");
}
- (void)Success
{
UIStoryboard *subVc = [UIStoryboard storyboardWithName:#"MainStoryboard_iPad" bundle:nil];
UserTableView *userTable = [subVc instantiateViewControllerWithIdentifier:#"UserTableView"];
userTable.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self.navigationController pushViewController:userTable animated:YES];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(#"%#", error);
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
[self performSelectorOnMainThread:#selector(Success) withObject:Nil waitUntilDone:YES];
NSLog(#"connectionDidFinishLoading%#", connection);
}
Everything works, and returns my data and data gets added into the SQL. My NSLog shows that ConnectionDidFinishLoading. But it does not push to the new View Controller.
Thanks for the help, being scratching my head on this one.
Thanks to Fahim advise allowed me to debug further, The Navigation view broke with a returned model controller. Changed it to push and all is working
Point 1
This is not working with you because you don't have navigation controller. Make sure that you have navigation controller.
Point 2
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
[self performSelectorOnMainThread:#selector(LoginSuccess) withObject:Nil waitUntilDone:YES];
NSLog(#"connectionDidFinishLoading%#", connection);
}
This is something wrong. Even if user have entered incorrect username or password, you are still allowing user to get logged in.
Check the response that you are getting in connectionDidFinishLoading and then based on this response do the transition.
e.g. if you have PHP at backend your code will be
sql query here to add data
if (data added) {
echo "valid";
} else {
echo "invalid";
}
now check this response in connectionDidFinishLoading and based on this do the transition
First check that if your LoginSuccess is getting called if yes then paste this
UserTableView * userTable =[self.storyboard instantiateViewControllerWithIdentifier:#"UserTableView"];
[self.navigationController pushViewController:userTable animated:YES]
like this but replace ResultsTableView with UserTableView

NSURLConnection Hangs under certain conditions

I'm posting to a RESTful webservice and receiving a response, this works great if I'm getting back only a few records however there is a threshold where didReceiveData: stops being called (6 records) and it just hangs. (does not matter what records, just the number)
I can't seem to figure out why. I'm getting a status message of 200 application/json in didReceiveResponse: however that's the last I hear from my connection.
From other clients I can get the full data with any number of records so it's related to my NSURLConnection code.
See full NSURLConnection Post class below.
the .h
#import <Foundation/Foundation.h>
#import "MBProgressHUD.h"
#protocol PostJsonDelegate <NSObject, NSURLConnectionDelegate>
#optional
- (void) downloadFinished;
- (void) downloadReceivedData;
- (void) dataDownloadFailed: (NSString *) reason;
#end
#interface PostURLJson : NSObject {
NSMutableData *receivedData;
int expectedLength;
MBProgressHUD *HUD;
}
#property (strong, nonatomic) NSMutableData *receivedData;
#property (weak) id <PostJsonDelegate> delegate;
#property (assign, nonatomic) int expectedLength;
+ (id)initWithURL:(NSString *)url dictionary:(NSDictionary *)dictionary withDelegate:(id <PostJsonDelegate>)delegate;
#end
the .m
#import "PostURLJson.h"
#define SAFE_PERFORM_WITH_ARG(THE_OBJECT, THE_SELECTOR, THE_ARG) (([THE_OBJECT respondsToSelector:THE_SELECTOR]) ? [THE_OBJECT performSelector:THE_SELECTOR withObject:THE_ARG] : nil)
#implementation PostURLJson
#synthesize delegate;
#synthesize receivedData;
#synthesize expectedLength;
+ (id)initWithURL:(NSString *)url dictionary:(NSDictionary *)dictionary withDelegate:(id <PostJsonDelegate>)delegate
{
if (!url)
{
NSLog(#"Error. No URL");
return nil;
}
PostURLJson *postJson = [[self alloc] init];
postJson.delegate = delegate;
[postJson loadWithURL:url dictionary:dictionary];
return postJson;
}
- (void)loadWithURL:(NSString *)url dictionary:(NSDictionary *)dictionary
{
[self setExpectedLength:0];
receivedData = [[NSMutableData alloc] init];
NSError* error;
NSDictionary *tmp = [[NSDictionary alloc] initWithDictionary:dictionary];
NSData *postdata = [NSJSONSerialization dataWithJSONObject:tmp options:0 error:&error];
NSString *someString = [[NSString alloc] initWithData:postdata encoding:NSASCIIStringEncoding];
NSLog(#"%#",someString);
NSString *postLength = [NSString stringWithFormat:#"%d", [postdata length]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:url]];
[request setHTTPMethod:#"POST"];
[request setTimeoutInterval:10.0f];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:postdata];
NSURLConnection *connection = [NSURLConnection connectionWithRequest:request delegate:self];
[connection start];
[self setLoadingModeEnabled:YES];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
NSHTTPURLResponse * httpResponse = (NSHTTPURLResponse *) response;
int errorCode = httpResponse.statusCode;
NSString *fileMIMEType = [[httpResponse MIMEType] lowercaseString];
NSLog(#"%d",errorCode);
NSLog(#"%#",fileMIMEType);
[receivedData setLength:0];
// Check for bad connection
expectedLength = [response expectedContentLength];
if (expectedLength == NSURLResponseUnknownLength)
{
NSString *reason = [NSString stringWithFormat:#"Invalid URL"];
SAFE_PERFORM_WITH_ARG(delegate, #selector(dataDownloadFailed:), reason);
[connection cancel];
return;
}
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[receivedData appendData:data];
SAFE_PERFORM_WITH_ARG(delegate, #selector(downloadReceivedData), nil);
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
SAFE_PERFORM_WITH_ARG(delegate, #selector(downloadFinished), nil);
[self setLoadingModeEnabled:NO];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
NSLog(#"Something went wrong...");
HUD.labelText = #"Something went wrong...";
[self performSelector:#selector(didFailHideHud) withObject:nil afterDelay:2];
}
- (void)setLoadingModeEnabled:(BOOL)isLoading
{
//when network action, toggle network indicator and activity indicator
if (isLoading) {
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
UIWindow *window = [UIApplication sharedApplication].keyWindow;
HUD = [[MBProgressHUD alloc] initWithWindow:window];
[window addSubview:HUD];
HUD.labelText = #"Loading";
[HUD show:YES];
} else {
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
[HUD hide:YES];
[HUD removeFromSuperview];
}
}
-(void)didFailHideHud
{
[HUD hide:YES];
[HUD removeFromSuperview];
}
#end
Edit Server was not giving back a valid length after a certain size triggering NSURLResponseUnknownLength which I had mistakenly not logged so I was not getting my "Invalid URL" message in the console.
if (expectedLength == NSURLResponseUnknownLength)
{
NSString *reason = [NSString stringWithFormat:#"Invalid URL"];
SAFE_PERFORM_WITH_ARG(delegate, #selector(dataDownloadFailed:), reason);
[connection cancel];
return;
}
Try this:
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];
[connection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
[connection start];
Because if you run the connection in the NSDefaultRunLoopMode and there is UITableView scrolling, it will hang the connection delegate.
However your problem is different. Some servers will limit the number of simultaneous connections from a single client. If you are in the case, then the first connections would succeed and the others would hang until previous connections complete.

Resources