Response twice when using NSURLRequest - objective-c

I am using the code below to send request and reading the results via PHP file which connected to MySql. The code is working but it gives the results twice. I am using UIAlert and also its appear twice.
Her is the code:
// to check if the user name chosen has been registred bu some one else
NSString *userName = self.textUserName.text;
NSString *queryString = [NSString stringWithFormat:#"http:/MyWebSite/PHP.php?userName=%#",userName];
NSURLRequest *theRequest=[NSURLRequest
requestWithURL:[NSURL URLWithString:
queryString]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
[NSURLConnection sendAsynchronousRequest:theRequest queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if (error) {
} else {
NSString *responseText = [[NSString alloc] initWithData:data encoding: NSASCIIStringEncoding];
NSLog(#"Response: %#", responseText);
if ([responseText isEqualToString:#"null"]) {
// if the user is not registered then show the tick image
self.userNameTickImage.hidden = NO;
}else {
// to show alert if found user is already taken
UIAlertView *message = [[UIAlertView alloc] initWithTitle:NSLocalizedString(#"appName", nil)
message:NSLocalizedString(#"userNameRegisterd", nil)
delegate:nil
cancelButtonTitle:NSLocalizedString(#"done", nil)
otherButtonTitles:nil];
[message show];
// to return nill value to the user name text
self.textUserName.text = #"";
}
NSString *newLineStr = #"\n";
responseText = [responseText stringByReplacingOccurrencesOfString:#"<br />" withString:newLineStr];
}
}];
And her is the result in Xcode:
2015-05-17 13:02:34.851 App[3710:141871] Response: {"1":{"userName":"admin"}}
2015-05-17 13:02:35.052 App[3710:141871] Response: {"1":{"userName":"admin"}}

Related

How to show alert controller after getting response from api in objective-c?

I have a method that posts HTTP data, After getting the response from API I want to display an UIAlertController on the basis of status codes.
Suppose the status code I got is 409, So the controller will say "data already exists".
How to present alert controller and in which class, service class or any other view controller?
ViewController.h
- (IBAction)logIn:(id)sender {
if (username.text == nil || [password.text isEqualToString:#""])
{
UIAlertController *alert = [UIAlertController alertControllerWithTitle:
#"all the fields are mendetary"
message:#"missing username or password " preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *action = [UIAlertAction
actionWithTitle:#"OKAY" style:UIAlertActionStyleDefault handler:^(UIAlertAction *_Nonnull action)
{
//[self dismissViewControllerAnimated:YES completion:nil];
}];
[alert addAction:action];
[self presentViewController:alert animated:YES completion:nil];
}
else
{
[[service SharedInstance] logIn:[NSDictionary dictionaryWithObjectsAndKeys:username.text,#"username",password.text,#"password",nil] params:#"logIn" block:^(const BOOL success, id resultObject, NSError *error )
{
// [self performSegueWithIdentifier:#"Loggedin" sender:self];
}];
}
username.text =#"";
password.text =#"";
}
Service.m
-(void)logIn:(NSDictionary *)Details params:(NSString *)params block:(ResponseBlock)block{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSError *error;
NSString *URL = #"http://localhost:8080";
NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfiguration delegate:nil delegateQueue:nil];
NSString *requestURL = [URL stringByAppendingString:#"/api/signupUser"];
NSURL *url = [NSURL URLWithString:requestURL]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url
cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:120.0]; NSData *data = [params dataUsingEncoding:NSDataBase64Encoding64CharacterLineLength];
NSString *base64Encoded = [data base64EncodedStringWithOptions:0];
NSLog(#"base64Encoded%#",base64Encoded);
NSString *basicString = #"Basic";
basicString = [NSString stringWithFormat:#"%#%#",basicString,base64Encoded];
NSLog(#"basicString%#",basicString);
[request addValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request addValue:basicString forHTTPHeaderField:#"Authorization"];
[request setHTTPMethod:#"POST"];
NSData *bodyData = [NSJSONSerialization dataWithJSONObject:Details options:0 error:&error];
[request setHTTPBody:bodyData];NSURLSessionTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * data, NSURLResponse *response, NSError *error)
{
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
long statusCode =[httpResponse statusCode];
NSLog(#"response status code: %ld", statusCode);
f (error)
{
block(NO, response,error);
}
else
{
NSError *err = nil;
id responseData = [NSJSONSerialization
JSONObjectWithData:data options:kNilOptions error:&err];
NSDictionary* headers= [(NSHTTPURLResponse *)response allHeaderFields];
NSLog(#"all header fields %#",headers);
[defaults removeObjectForKey:#"userToken"];
NSLog(#"token %#",[defaults valueForKey:#"userToken"]);
NSDate *expireDate = [[NSDate date]dateByAddingTimeInterval:60*25];
[defaults setObject:expireDate forKey:#"sessionDate"];
if(err)
{
block(NO, response, error);
}
else
{
block(YES, responseData,nil);
}
[task cancel];
}
}];
[task resume];
}
#end
It looks like you are making some http call from a service file. There are few options here:
Implement delegate of your service class in ViewController to perform any task there.
Use blocks.
Use framework like Rx here.
or if you just need to display the alert add the alert to current window e.g.
I have created an extension for this purpose:
extension UIAlertController {
/// display alert with custom number of buttons
static func presentAlert(_ title: String?, message: String?, alertButtonTitles: [String], alertButtonStyles: [UIAlertActionStyle], vc: UIViewController, completion: #escaping (Int)->Void) -> Void
{
let alert = UIAlertController(title: title,
message: message,
preferredStyle: UIAlertControllerStyle.alert)
for title in alertButtonTitles {
let actionObj = UIAlertAction(title: title,
style: alertButtonStyles[alertButtonTitles.index(of: title)!], handler: { action in
completion(alertButtonTitles.index(of: action.title!)!)
})
alert.addAction(actionObj)
}
vc.present(alert, animated: true, completion: nil)
}
}
use:
UIAlertController.presentAlert("My Title", message: "My message", alertButtonTitles: "OK", alertButtonStyles: [.default], vc: (UIApplication.shared.keyWindow?.rootViewController)!, completion: { (btnIndex) in
})
Above code is adding UiAlerController over window.

How to upload UIImage from iOS to Azure storage

I try to upload an image to Azure storage through MVC 4 web API. But the server side always return:
"Invalid length for a Base-64 char array or string."
Below is Objective-C code:
- (IBAction)btnUploadReceipt:(id)sender {
UIImage *img = self.imgReceipt.image;
NSData *dataObj = UIImagePNGRepresentation(img);
NSString *fff = [dataObj base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
//NSString *ddd = [self base64EncodeString:imgData];
//NSString *ddd = [dataObj base64EncodedString];
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"%#/api/upload/UploadAzure",baseUrl]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:#"Post"];
NSString *jsonData = [NSString stringWithFormat:#"FileName=%#&FileData=%#&FolderName=%#&UserName=%#&Point=%#&DateTime=%#&MerchantName=%#&OutletID=%#",fileName,fff,imgFolder,userName,#"3",dateTime,_mName,_mOutletID];
[request setHTTPBody:[jsonData dataUsingEncoding:NSUTF8StringEncoding]];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response,
NSData *data, NSError *connectionError)
{
if (data.length > 0 && connectionError == nil)
{
NSString * json =[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"%#",json);
if ([json isEqualToString:#"\"True\""]) {
NSLog(#"%#",#"Success Add Photo");
//[self dismissViewControllerAnimated:YES completion:nil];
//[[self navigationController]popViewControllerAnimated:YES];
}
else
{
UIAlertView *messageAlert = [[UIAlertView alloc]initWithTitle:#"Connection Error" message:#"Please Check Internet Setting" delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil];
[messageAlert show];
}
}
else
{
UIAlertView *messageAlert = [[UIAlertView alloc]initWithTitle:#"Connection Error" message:#"Please Check Internet Setting" delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil];
[messageAlert show];
}
}];
}
- (NSString *)base64String2 {
UIImage *img = self.imgReceipt.image;
NSData * data = [UIImagePNGRepresentation(img) base64EncodedDataWithOptions:NSDataBase64Encoding64CharacterLineLength];
return [NSString stringWithUTF8String:[data bytes]];
}
Anyone face this kind of problem?
Have you tried using the Azure Storage iOS Library? The Getting Started documentation should be able to help with your scenario.

Handling a String From a Web API Service in Object-C

I have a simple Web API Service POST
// POST api/values
public string Post(SimpleRequest request)
{
if (request == null || string.IsNullOrEmpty(request.Field1) || string.IsNullOrEmpty(request.Password))
return "Something is missing.";
return string.Format("Success. You sent {0}!", request.Field1);
}
Which is consumed in an a object-c method (for an iphone project):
- (IBAction)doSomethingButtonWasPressed:(id)sender {
NSString * urlString = #"http://192.168.0.XXX/api/Test";
NSDictionary *postDict = [[NSDictionary alloc] initWithObjectsAndKeys:
_field1.text, #"Field1",
_field2.text, #"Field2",
nil];
NSURL *url=[NSURL URLWithString:[urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSData *req= [NSJSONSerialization dataWithJSONObject:postDict options:NSJSONWritingPrettyPrinted error:nil];
NSMutableURLRequest *request=[NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:#"POST"];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];//
[request setHTTPBody:req];
NSURLResponse* response;
NSError* error = nil;
NSData* responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
NSLog(#"The output is:%#",responseString);
UIAlertView *alert = [[UIAlertView alloc] initWithTitle: #"Result"
message:responseString
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
It all works, except the result has "quotes" around it. I feel like maybe I'm missing a decoding step?
It's possible the service is returning JSON, like {"foo"} that would appear as a quoted string. Try interpreting the data as JSON with ...
NSError *error;
id result = [NSJSONSerialization JSONObjectWithData:responseData options:nil error:&error];
NSLog(#"result is %#, error is %#", result, error);

Fetch only MyContacts from gmail account in iOS

I am trying to fetch gmail & yahoo contacts in my iPhone application.
For Gmail I have used GTMOauth2.0. I can see all contacts but when I want only contacts from MyContacts group. I have used following code to get contacts:
-(void)signInToGoogle:(id)sender
{
[self signOutFromGoogle];
NSString *keychainItemName = nil;
NSString *scope = #"https://www.google.com/m8/feeds/contacts/default/full";
NSString *clientID = #"CLIENTID";
NSString *clientSecret = #"CLIENTSECRETID";
SEL finishedSel = #selector(viewController:finishedWithAuth:error:);
GTMOAuth2ViewControllerTouch *viewController;
viewController = [GTMOAuth2ViewControllerTouch controllerWithScope:scope
clientID:clientID
clientSecret:clientSecret
keychainItemName:keychainItemName
delegate:self
finishedSelector:finishedSel];
NSDictionary *params = [NSDictionary dictionaryWithObject:#"en" forKey:#"hl"];
viewController.signIn.additionalAuthorizationParameters = params;
NSString *html = #"<html><body bgcolor=silver><div align=center>Loading sign-in page...</div></body></html>";
viewController.initialHTMLString = html;
[[self navigationController] pushViewController:viewController animated:YES];
}
- (void)viewController:(GTMOAuth2ViewControllerTouch *)viewController
finishedWithAuth:(GTMOAuth2Authentication *)auth
error:(NSError *)error {
[[NSNotificationCenter defaultCenter] removeObserver:self];
if (error != nil) {
[processObj removeFromSuperview];
self.view.userInteractionEnabled = YES;
NSLog(#"Authentication error: %#", error);
NSData *responseData = [[error userInfo] objectForKey:#"data"]; // kGTMHTTPFetcherStatusDataKey
if ([responseData length] > 0) {
// show the body of the server's authentication failure response
NSString *str = [[NSString alloc] initWithData:responseData
encoding:NSUTF8StringEncoding];
NSLog(#"%#", str);
}
self.auth = nil;
} else {
self.auth = auth;
[self doAnAuthenticatedAPIFetch];
}
}
- (void)doAnAuthenticatedAPIFetch {
NSString *urlStr = #"https://www.google.com/m8/feeds/groups/default/full/Contacts";
NSURL *url = [NSURL URLWithString:urlStr];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[self.auth authorizeRequest:request
completionHandler:^(NSError *error) {
NSString *output = nil;
if (error) {
output = [error description];
} else {
NSURLResponse *response = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:request
returningResponse:&response
error:&error];
if (data) {
// API fetch succeeded :Here I am getti
output = [[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding];
} else {
// fetch failed
output = [error description];
}
}
}];
}
In the API I am passing "Contacts" as a group id but it is returning error "Group Id Not Found". I have the google document from
https://developers.google.com/google-apps/contacts/v3/?csw=1
but still can't solve the problem. Help me on these.
You'll need to fetch the groups feed to get the ID for a group. See the groups feed documentation, or try the ContactsSample app provided with the Google Data APIs Objective-C Client Library.

Activity indicator with SBJson framework

I'm currently working on an app that uses a basic login page to check if the user has access to the app. I've made the login part with help of this tutorial which uses this frame work to use username and password from a simple web script.
I'm hoping that someone else maybe have worked with it or can help me with my issue. I wan't to show an activity indicator, I'm using MBProgressHUD as an activity indicator.
So I've experimented with it but can't get it to show the activity indicator when the app is connecting to the URL. I've done some bad connection simulating with the login process but the activity indicator won't show up when the app is connecting to the URL. It only shows on errors and the only thing that shows any kind of loading on success is that the login buttons pressed state is "active" (blue highlighted) until the loading is done.
So here's my code that runs when the user has typed in username and password and clicks on the login button:
// Login button
- (IBAction)loginBtnClicked:(id)sender
{
// Show the activity indicator
[HUD showUIBlockingIndicatorWithText:#"Loggar in..."];
#try {
if([[userNameTxtField text] isEqualToString:#""] || [[passwordTxtField text] isEqualToString:#""] ) {
// No username or password entered
[self alertStatus:#"Du måste ange användarnamn och lösenord" :#"Något gick fel!"];
// Hide activity indicator
[HUD hideUIBlockingIndicator];
} else {
NSString *post =[[NSString alloc] initWithFormat:#"username=%#&password=%#",[userNameTxtField text],[passwordTxtField text]];
NSLog(#"PostData: %#",post);
NSURL *url=[NSURL URLWithString:#"http://www.nebulon.se/json/sendus/jsonlogin.php"];
NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *postLength = [NSString stringWithFormat:#"%d", [postData length]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:url];
[request setHTTPMethod:#"POST"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:postData];
//[NSURLRequest setAllowsAnyHTTPSCertificate:YES forHost:[url host]];
NSError *error = [[NSError alloc] init];
NSHTTPURLResponse *response = nil;
NSData *urlData=[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSLog(#"Response code: %d", [response statusCode]);
if ([response statusCode] >=200 && [response statusCode] <300){
NSString *responseData = [[NSString alloc]initWithData:urlData encoding:NSUTF8StringEncoding];
NSLog(#"Response ==> %#", responseData);
SBJsonParser *jsonParser = [SBJsonParser new];
NSDictionary *jsonData = (NSDictionary *) [jsonParser objectWithString:responseData error:nil];
NSLog(#"%#",jsonData);
NSInteger success = [(NSNumber *) [jsonData objectForKey:#"success"] integerValue];
NSLog(#"%d",success);
if(success == 1){
// Login success, grant user access to app
NSLog(#"Login SUCCESS");
[self loginSuccess];
// Hide activity indicator
[HUD hideUIBlockingIndicator];
// Store username
NSString *userName = [userNameTxtField text];
NSUserDefaults *UserDefaults = [NSUserDefaults standardUserDefaults];
[UserDefaults setObject:userName forKey:#"userName"];
[UserDefaults synchronize];
[self dismissViewControllerAnimated:NO completion:nil];
} else {
// Login error
NSString *error_msg = (NSString *) [jsonData objectForKey:#"error_message"];
[self alertStatus:error_msg :#"Inloggningen misslyckades"];
[self loginFailed];
// Hide activity indicator
[HUD hideUIBlockingIndicator];
}
} else {
// Login error
if (error) NSLog(#"Error: %#", error);
[self alertStatus:#"Ingen nätverksuppkoppling hittades." :#"Ett fel har inträffat!"];
[self loginFailed];
// Hide activity indicator
[HUD hideUIBlockingIndicator];
}
}
}
#catch (NSException * e) {
// Login error
NSLog(#"Exception: %#", e);
[self alertStatus:#"Inloggningen misslyckades." :#"Ett fel har inträffat!"];
[self loginFailed];
// Hide activity indicator
[HUD hideUIBlockingIndicator];
}
}
I believe the issue is due to the use of sendSynchronousRequest:returningResponse:error:
This method will be blocking the main/UI thread so the HUD never actually gets a chance to show until the method has returned, at which point the code continues and the HUD is hidden.
I think you should be looking at using an asynchronous request. and implementing the NSURLConnection delegate methods.
EDIT: Added code sample.
Assuming you're targeting iOS 5 and higher you can use the following code snippet which takes advantage of blocks with sendAsynchronousRequest:queue:completionHandler: and GCD.
NSOperationQueue *backgroundQueue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:request
queue:backgroundQueue
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
// NOTE: This block is called on the background queue.
// Use GCD to get back onto the main thread
dispatch_async(dispatch_get_main_queue(), ^{
// This block will process the response and data on the main thread
});
}];
It really is very little work to port your existing code to use this mechanism. If you don't know how blocks work you should read the documentation as they are a very powerful language feature and are being used in an increasing amount of Apple and third-party frameworks.
I would also recommend staying AWAY from third-party networking libraries for now until you understand the nuances that can cause issues such as this.