Delegate method not called after dismissing modal view controller - ios

I am using NSURLSessionDataTask to retrieve JSON from a url in my JsonClient class, this class has a delegate protocol to notify when the json task is complete.
JsonClient.h
#import <Foundation/Foundation.h>
#protocol JsonDelegate <NSObject>
- (void)jsonFetchComplete;
#end
#interface JsonClient : NSObject
#property (weak,nonatomic) id <JsonDelegate> delegate;
- (void)fetchJsonData;
#end
JsonClient.m
#import "JsonClient.h"
#implementation JsonClient
- (void)fetchJsonData {
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
NSString *urlString = #"http://api.kivaws.org/v1/loans/search.json?status=fundraising";
urlString = [urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
//urlString = [urlString stringByAppendingString:#".json"];
NSURL *url = [NSURL URLWithString:urlString];
NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:1 timeoutInterval:10];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *task = [session dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
NSLog(#"error: %#",error.localizedDescription);
dispatch_sync(dispatch_get_main_queue(), ^{
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"ERROR"
message:error.localizedDescription
delegate:self
cancelButtonTitle:#"Cancel"
otherButtonTitles:nil];
[alert show];
});
} else {
NSLog(#"got data");
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
NSError *jsonerror = nil;
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&jsonerror];
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(#"json is \n %#",dict);
[self.delegate jsonFetchComplete];
NSLog(#"done");
});
}
}];
[task resume];
}
#end
Fetching the json works fine. But for some reason the delegate method is not getting called in my first view controller. ViewController presents ViewController2 with a modal segue. A button in ViewController2 fetches the json when tapped and dismisses back to the first ViewController.
ViewController.m
#import "ViewController.h"
#import "JsonClient.h"
#interface ViewController () <JsonDelegate>
#property (weak,nonatomic) IBOutlet UILabel *label;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.label.text = #"Loaded VC";
}
- (void)viewWillAppear:(BOOL)animated {
NSLog(#"view will appear");
JsonClient *jc = [[JsonClient alloc] init];
jc.delegate = self;
}
// delegate method from JsonClient
- (void)jsonFetchComplete {
NSLog(#"fetch complete");
self.label.text = #"Completed!";
}
- (IBAction)toHome:(UIStoryboardSegue *)segue {
// unwind segue
}
#end
ViewController2.m
#import "ViewController2.h"
#import "JsonClient.h"
#import "ViewController.h"
#interface ViewController2 ()
#end
#implementation ViewController2
- (IBAction)getJsonData:(id)sender {
JsonClient *jsonClient = [[JsonClient alloc] init];
[jsonClient fetchJsonData];
[self dismissViewControllerAnimated:YES completion:nil];
}
#end
Why is the delegate method in the first view controller ViewController not called?

Unless JsonClient is a Singleton, and you're not telling us, you're creating two instances of JsonClient, one in the viewWillAppear method of ViewController and another in the getJsonData method of ViewController2.
These two instances track their delegates separately, and you're only setting one of them. The second one, the one that gets called when you click the button in ViewController2, never has its delegate set, so it defaults to nil, and messages sent to nil do nothing.
You need something like:
#implementation ViewController2
- (IBAction)getJsonData:(id)sender {
JsonClient *jsonClient = [[JsonClient alloc] init];
jsonClient.delegate = otherViewController;
[jsonClient fetchJsonData];
[self dismissViewControllerAnimated:YES completion:nil];
}
#end

Related

Obj-C UITable not populating with MutableArray

I have an array that loads when the app starts and it gets the correct data and fills the array but once I go to the tableviewcontroller it says the array is null.
This is where I get the data
AppDelegate.h
#interface AppDelegate : UIResponder <UIApplicationDelegate>
{
NSMutableArray *tableDicsArrayTickets;
NSMutableArray *dictionaryStack;
NSMutableString *textInProgress;
NSError *errorPointer;
}
#property (strong, nonatomic) NSMutableArray *tableDicsArrayTickets;
#property (strong, nonatomic) UIWindow *window;
#property (strong, nonatomic) NSString *photo_URL;
+(NSDictionary *)dictionaryForXMLData:(NSData *)data error:(NSError **)errorPointer;
+(NSDictionary *)dictionaryForXMLString:(NSString *)string error:(NSError **)errorPointer;
+(AppDelegate *) getInstance;
AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
self.tableDicsArrayTickets = [[NSMutableArray alloc] init];
NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration:defaultConfigObject delegate:nil delegateQueue:[NSOperationQueue mainQueue]];
NSURL *url = [NSURL URLWithString:#"http://MYURLexample.php"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
NSString *deviceCode = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
NSString *post = [[NSString alloc] initWithFormat:#"parameter=%#", deviceCode];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:[post dataUsingEncoding:NSUTF8StringEncoding]];
NSURLSessionDataTask *dataTask = [defaultSession dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSLog(#"Response:%# %#\n", response, error);
if(error == nil)
{
NSString *text =[[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
NSLog(#"Data = %#",text);
NSDictionary *dics = [[NSDictionary alloc]initWithDictionary:[AppDelegate dictionaryForXMLString:text error:nil]];
NSLog(#"dics is %#", dics);
[self.tableDicsArrayTickets addObject:[[dics valueForKey:#"response"] valueForKey:#"text"]];
NSLog(#"Array2 is %#", self.tableDicsArrayTickets);
}
}];
[dataTask resume];
ViewController.h
#interface HistoryViewController : UIViewController<UITableViewDataSource, UITableViewDelegate>
{
AppDelegate *mainDelegate;
}
#property (strong, nonatomic) AppDelegate *mainDelegate;
ViewController.m
#pragma
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [mainDelegate.tableDicsArrayTickets count];
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 60;
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSMutableArray *array = mainDelegate.tableDicsArrayTickets;
NSString *cellIdentifier = #"Cell";
PhotoTableViewCell *cell = (PhotoTableViewCell *) [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if(cell == nil)
{
cell = [[PhotoTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
NSLog(#"Array is %#", [[array objectAtIndex:indexPath.row] objectForKey:#"text"]);
cell.ticketNumber.text = [[array objectAtIndex:indexPath.row] objectForKey:#"text"];
return cell;
}
Im not having a problem getting the data for the array its just once I finally go to the view controller with the table on it the array becomes null.
I think you're doing a number of things wrong...
First:
// AppDelegate.h
#interface AppDelegate : UIResponder <UIApplicationDelegate>
{
// this should NOT be here
NSMutableArray *tableDicsArrayTickets;
NSMutableArray *dictionaryStack;
NSMutableString *textInProgress;
NSError *errorPointer;
}
#property (strong, nonatomic) NSMutableArray *tableDicsArrayTickets;
// ...
That should give you a compile warning:
autosynthesized property 'tableDicsArrayTickets' will use synthesized instance
variable '_tableDicsArrayTickets', not existing instance variable 'tableDicsArrayTickets'
Same with:
//HistoryViewController.h
#interface HistoryViewController : UIViewController<UITableViewDataSource, UITableViewDelegate>
{
// this should NOT be here
AppDelegate *mainDelegate;
}
#property (strong, nonatomic) AppDelegate *mainDelegate;
Which should give you:
autosynthesized property 'mainDelegate' will use synthesized instance
variable '_mainDelegate', not existing instance variable 'mainDelegate'
Then, you're not showing where you have this in HistoryViewController.m (should probably be in viewDidLoad()):
_mainDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];

Objective c iOS passing data

hi I am new to iOS and below is my code I have to pass the top that I get from request reply...please help me I am stuck here
first view controller is otp view second vc is verifyviewcontroller
Otp view c.h
#import <UIKit/UIKit.h>
#interface OtpViewController : UIViewController
#property (nonatomic, retain) NSString *str;
#end
otpviewcontroller.m
#import "OtpViewController.h"
#import "VerifyViewController.h"
#interface OtpViewController () <VerifyViewControllerDelegate>
#property (weak, nonatomic) IBOutlet UIImageView *bbi;
#property (weak, nonatomic) IBOutlet UIButton *submittf;
#property (weak, nonatomic) IBOutlet UITextField *mobiletf;
#property (weak,nonatomic) NSArray *tmp;
#property(weak,nonatomic) NSString *requestReply ;
//#property(weak,nonatomic) NSDictionary *A;
#end
#implementation OtpViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"background"]];
NSLog(#"viewDidLoad");
[super viewDidLoad];
}
- (IBAction)submitb:(id)sender
{
if (_mobiletf.text && _mobiletf.text.length >0 )
{
/* not empty - do something */
NSString *post = [NSString stringWithFormat:#"phone=%#",_mobiletf.text];
NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
// Next up, we read the postData's length, so we can pass it along in the request.
NSString *postLength = [NSString stringWithFormat:#"%d", [postData length]];
// Now that we have what we'd like to post, we can create an NSMutableURLRequest, and include our postData.
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:#"http://www.sitesandflats.com/send_otp.php"]];
[request setHTTPMethod:#"POST"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setHTTPBody:postData];
NSLog(#"the data Details is %#", post);
// And finally, we can send our request, and read the reply by creating a new NSURLSession:
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
[[session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSString *requestReply = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
NSLog(#"requestReply: %#", requestReply);
NSString *str=requestReply;
VerifyViewController *vc = [[VerifyViewController alloc] init];
NSString *tmp=requestReply;
NSLog(#"%#",str);
NSLog(#"%#",_tmp);
}] resume];
[ self performSegueWithIdentifier:#"b1" sender:self];
}
else
{
/* what ever */
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error"
message:#"Please check your input!!."
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(nullable id)sender{
VerifyViewController *loadCtr = (VerifyViewController *)segue.destinationViewController;
loadCtr.delegate = self;
loadCtr.tmpStr = (#"otp: %#",_tmp);
NSLog(#"passing val: %#",_tmp);
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
Verify view controller.h
#import <UIKit/UIKit.h>
#protocol VerifyViewControllerDelegate <NSObject>
-(void)moveToA:(NSString *)str;
#end
#interface VerifyViewController : UIViewController
#property (nonatomic, copy) NSString *tmpStr;
#property (nonatomic, assign) id <VerifyViewControllerDelegate> delegate;
//#property (nonatomic, strong) OtpViewController *received;
//#property (strong, nonatomic) IBOutlet UITextField *textDisplay;
#property(nonatomic,weak) NSMutableArray *myAray;
#property(nonatomic,strong) NSString *object;
#property(strong,nonatomic) NSString *tmp1;
#end
Verify view controller.m
#import "VerifyViewController.h"
#import "OtpViewController.h"
#interface VerifyViewController ()
#property (weak, nonatomic) IBOutlet UITextField *otptf;
#property (weak, nonatomic) IBOutlet UIButton *submitb;
//#property (weak,nonatomic) textDisplay;
//#property (weak,nonatomic) NSString *received;
#end
#implementation VerifyViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"background"]];
// Do any additional setup after loading the view.
}
- (IBAction)submitb:(id)sender {
NSLog(#"%#",_tmpStr);
if(_otptf.text==_tmpStr)
{
[self performSegueWithIdentifier:#"b2" sender:self];
}
else{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error"
message:#"Incorrect otp please check the input!!!."
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
at nslog I get reply as ("success":"1";"otp":"985123") I need this otp to store and verify in next page please help
First you need to change property
From
#property (weak,nonatomic) NSArray *tmp;
To
#property (strong,nonatomic) NSStirng *tmp;
Assign value to tmp as below
[[session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSString *requestReply = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]; // this is json string
NSError *error;
NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error]; // you need to convert to dictionary object
NSLog(#"requestReply: %#", jsonDict);
self.tmp=[jsonDict valueForKey:#"otp"] ; // you need to extract value using the key [requestReply valueForKey:#"otp"];
NSLog(#"%#",self.tmp);
}] resume];
Pass tmp to VerifyVIewController
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(nullable id)sender{
VerifyViewController *loadCtr = (VerifyViewController *)segue.destinationViewController;
loadCtr.delegate = self;
loadCtr.tmpStr = self.tmp;
NSLog(#"passing val: %#",_tmp);
}

Code keeps crashing with passing data

I'm building my first iOS app with a login system. I've built some simple things before, but this is on a whole new level. Currently I'm able to login and get some data back from the server. The app then performs a model segue to MainView with MainController attached to it.
When I log in, the app gets token and success back from the server. This token is needed for further requests to the server. However, I can't seem to figure out how to pass the token to MainController. It doesn't matter what I try, the app crashes with an unknown error.
Right now - with the code below - it throws:
2014-10-11 14:30:14.077 LoginScreen[29076:4688502] -[UINavigationController setXAuthToken:]: unrecognized selector sent to instance 0x7bfd1140
2014-10-11 14:30:14.104 LoginScreen[29076:4688502] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UINavigationController setXAuthToken:]: unrecognized selector sent to instance 0x7bfd1140'
ViewController.h
#import <UIKit/UIKit.h>
#import "MainController.h"
#interface ViewController : UIViewController <UITextFieldDelegate>
#property (weak, nonatomic) IBOutlet UITextField *txtUsername;
#property (weak, nonatomic) IBOutlet UITextField *txtPassword;
- (IBAction)sigininClicked:(id)sender;
- (IBAction)backgroundTap:(id)sender;
#end
ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)sigininClicked:(id)sender {
NSInteger success = 0;
#try {
if([[self.txtUsername text] isEqualToString:#""] || [[self.txtPassword text] isEqualToString:#""] ) {
[self alertStatus:#"Please enter Email and Password" :#"Sign in Failed!" :0];
} else {
NSString *post =[[NSString alloc] initWithFormat:#"username=%#&password=%#",[self.txtUsername text],[self.txtPassword text]];
NSLog(#"PostData: %#",post);
NSURL *url=[NSURL URLWithString:#"http://www.mywebsite.com/auth"];
NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *postLength = [NSString stringWithFormat:#"%lu", (unsigned long)[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: %ld", (long)[response statusCode]);
if ([response statusCode] >= 200 && [response statusCode] < 300)
{
NSString *responseData = [[NSString alloc]initWithData:urlData encoding:NSUTF8StringEncoding];
NSLog(#"Response ==> %#", responseData);
NSError *error = nil;
NSDictionary *jsonData = [NSJSONSerialization
JSONObjectWithData:urlData
options:NSJSONReadingMutableContainers
error:&error];
success = [jsonData[#"success"] integerValue];
NSLog(#"Success: %ld",(long)success);
if(success == 1)
{
NSLog(#"Login SUCCESS");
} else {
NSString *error_msg = (NSString *) jsonData[#"error_message"];
[self alertStatus:error_msg :#"Sign in Failed!" :0];
}
} else {
//if (error) NSLog(#"Error: %#", error);
[self alertStatus:#"Connection Failed" :#"Sign in Failed!" :0];
}
}
}
#catch (NSException * e) {
NSLog(#"Exception: %#", e);
[self alertStatus:#"Sign in Failed." :#"Error!" :0];
}
if (success) {
[self performSegueWithIdentifier:#"login_success" sender:self];
}
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"login_success"]) {
MainController *controller = (MainController *)segue.destinationViewController;
controller.xAuthToken = #"test string";
}
}
- (void) alertStatus:(NSString *)msg :(NSString *)title :(int) tag
{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:title
message:msg
delegate:self
cancelButtonTitle:#"Ok"
otherButtonTitles:nil, nil];
alertView.tag = tag;
[alertView show];
}
- (IBAction)backgroundTap:(id)sender {
[self.view endEditing:YES];
}
-(BOOL) textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];
return YES;
}
#end
MainController.h
#import <Foundation/Foundation.h>
#interface MainController : UIViewController
#property (nonatomic,strong) NSString *xAuthToken;
#end
MainController.m
#import "MainController.h"
#interface MainController ()
#end
#implementation MainController
- (void)viewDidLoad
{
NSLog(#"%#",_xAuthToken);
}
#end
The stack trace tells you what the problem is - you are trying to set the XAuthToken property on a UINavigationController - but a UINavigationController doesn't have that property.
Your MainController instance is embedded in a UINavigationController, so that is what you get from destinationViewController in prepareForSegue.
You need to access the view controller stack -
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"login_success"]) {
UINavigationController *navController = (UINavigationController *)segue.destinationViewController;
MainController *controller = (MainController *)navController.topViewController
controller.xAuthToken = #"test string";
}
}

how to access value form completionHandler and pass it to another view IOS

I'm trying to return String from this method i have two class
first one is for UI and it have two input text user and pass and also i have submit button , another one only doing the following method .
I'm trying to return string from the other class to this class and show the string in alert .
#import "LoginPage.h"
#implementation LoginPage
-(NSString *)responsData:(NSString *)loginUrl input1:(NSString *)username input2:(NSString *)password
{
NSString *urlAsString = loginUrl;
NSString*test;
inUsername = username;
inPassword = password;
NSURL *url = [NSURL URLWithString:urlAsString];
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url];
[urlRequest setTimeoutInterval:30.0f];
[urlRequest setHTTPMethod:#"POST"];
// Setting Username and password
NSString *body = [NSString stringWithFormat:#"sended=yes&username=%#&password=%#",username,password];
[urlRequest setHTTPBody:[body dataUsingEncoding:NSUTF8StringEncoding]];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[NSURLConnection
sendAsynchronousRequest:urlRequest
queue:queue
completionHandler:^(NSURLResponse *response,
NSData *data,
NSError *error)
{
if ([data length] >0 && error == nil){ NSString *html =
[[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding];
// NSLog(#"%#", html);
self.lastValue = [NSString stringWithFormat:#"%#",html];
}
else if ([data length] == 0 && error == nil){
//NSLog(#"Nothing was downloaded.");
self.lastValue = [NSString stringWithFormat:#"No thing was downloaded"];
}
else if (error != nil){
// NSLog(#"Error happened = %#", error);
self.lastValue = [NSString stringWithFormat:#"%#",error];
} }];
NSLog(#"%#",self.lastValue);
return self.lastValue;
}
// Do any additional setup after loading the view, typically from a nib.
#end
i want to use this function in another view ( already i include the header of this file ) but i can't , can any one solve this >
another view
- (IBAction)submit:(id)sender {
LoginPage * login = [[LoginPage alloc]init];
NSString * dataRe;
dataRe = [login responsData:#"http://fahads-macbook-pro.local/ios/post.php" input1:#"admin" input2:#"1234"];
NSLog(#"%#",login.lastValue);
if (dataRe != nil) {
UIAlertView * alert =[[UIAlertView alloc]
initWithTitle:#"Hello Fahad"
message:[NSString stringWithFormat:#"%#",dataRe] delegate:self cancelButtonTitle:#"Okay ! " otherButtonTitles:nil, nil];
[alert show];
}
}
Thank you again
When you call the function on the other view, it send an asynch request to the web.
So when you do:
return self.lastValue;
lastValue is still empty or with the previous value because the competionHandler need still to be called. Code of the completionHandler, is just a peace of code passed to the function, that will be called at right moment. So the function arrive to the end where is your return.
When instead the completion handler block is called (because the request has produced a response), you assign the value:
self.lastValue = [NSString stringWithFormat:#"%#",html];
Now lastValue is right.
So your function shouldn't return an NSString, but should return void.
To pass the string to the other controller, you should use the delegation pattern.
This is a very quickly example
SecondViewController.h
#protocol SecondViewControllerDelegate <NSObject>
- (void)lastValueDidUpdate:(NSString *)lastValue;
#end
#interface SecondViewController : UIViewController
#property (weak, nonatomic) id<SecondViewControllerDelegate>delegate;
#end
SecondViewController.m
#import "SecondViewController.h"
#implementation SecondViewController
-(NSString *)responsData:(NSString *)loginUrl input1:(NSString *)username input2:(NSString *)password
{
NSString *urlAsString = loginUrl;
NSString*test;
inUsername = username;
inPassword = password;
NSURL *url = [NSURL URLWithString:urlAsString];
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url];
[urlRequest setTimeoutInterval:30.0f];
[urlRequest setHTTPMethod:#"POST"];
// Setting Username and password
NSString *body = [NSString stringWithFormat:#"sended=yes&username=%#&password=%#",username,password];
[urlRequest setHTTPBody:[body dataUsingEncoding:NSUTF8StringEncoding]];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
__weak typeof (self) weakSelf = self;
[NSURLConnection
sendAsynchronousRequest:urlRequest
queue:queue
completionHandler:^(NSURLResponse *response,
NSData *data,
NSError *error)
{
if ([data length] >0 && error == nil){ NSString *html =
[[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding];
// NSLog(#"%#", html);
weakSelf.lastValue = [NSString stringWithFormat:#"%#",html];
}
else if ([data length] == 0 && error == nil){
//NSLog(#"Nothing was downloaded.");
weakSelf.lastValue = [NSString stringWithFormat:#"No thing was downloaded"];
}
else if (error != nil){
// NSLog(#"Error happened = %#", error);
weakSelf.lastValue = [NSString stringWithFormat:#"%#",error];
}
[weakSelf.delegate lastValueDidUpdate:weakSelf.lastValue];
}];
}
#end
FirstViewController.h
#import "SecondViewController.h"
#interface FirstViewController : UIViewController <SecondViewControllerDelegate>
#property (strong, nonatomic) SecondViewController *secondViewController;
#end
FirstViewController.m
#import "FirstViewController.h"
#implementation FirstViewController
- (void)viewDidLoad {
//your code
[_secondViewController setDelegate:self];
//your code
}
//your code
#end
Note that i use a weak reference to self because otherwise you can create retain cycle.
Define a method in your first class i.e. UI class like:
- (void)callFromBlock:(NSString*)stringFromResponse
{
if (stringFromResponse != nil) {
UIAlertView * alert =[[UIAlertView alloc]
initWithTitle:#"Hello Fahad"
message:[NSString stringWithFormat:#"%#",stringFromResponse] delegate:self cancelButtonTitle:#"Okay ! " otherButtonTitles:nil, nil];
[alert show];
}
}
and the submit method should look like:
- (IBAction)submit:(id)sender {
LoginPage * login = [[LoginPage alloc]init];
NSString * dataRe;
dataRe = [login responsData:#"http://fahads-macbook-pro.local/ios/post.php" input1:#"admin" input2:#"1234"];
}
Now instead of return statement in the block, call the callFromBlock method from the block when you get the response and pass the string to this method you were trying to return.
Hope it helps.

NSUrlConnection doesnt seem to be working,

I'm trying to use googletts converted and seem to be running into trouble. I think I made the class correctly in terms of structure. But I dont think the NSURLConnection is returning any useful data. Can someone please help me check if its working and if not why?
In the connectiondidfinishloading section I am checking download length
NSLog(#"hmmmm %lu", (unsigned long)[downloadedData length])
which is returning 0. Thats why I think its not working.
The goal is to have the app speak what is downloaded
Thanks!!!
I just have a button in my view controller that launches everything
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#import "RJGoogleTTS.h"
#interface ViewController : UIViewController <CLLocationManagerDelegate>
#property (weak, nonatomic) IBOutlet UILabel *userLabel;
#property (strong, nonatomic) CLLocationManager *locationManager;
#property (strong, nonatomic) CLGeocoder *geoCoder;
#property (strong, nonatomic) RJGoogleTTS *googleTTS;
- (IBAction)geoCodeLocation:(id)sender;
- (IBAction)rjGoogleButton:(id)sender;
#end
here is the implementation file
- (IBAction)rjGoogleButton:(id)sender {
googleTTS = [[RJGoogleTTS alloc]init];
[googleTTS convertTextToSpeech:#"How are you today user?"];
}
RJGoogleTTS.h
#import <Foundation/Foundation.h>
#protocol RJGoogleTTSDelegate <NSObject>
#required
- (void)receivedAudio:(NSMutableData *)data;
- (void)sentAudioRequest;
#end
#interface RJGoogleTTS : NSObject {
id <RJGoogleTTSDelegate> delegate;
NSMutableData *downloadedData;
}
#property (nonatomic, retain) id <RJGoogleTTSDelegate> delegate;
#property (nonatomic, retain) NSMutableData *downloadedData;
- (void)convertTextToSpeech:(NSString *)searchString;
#end
.m
#import "RJGoogleTTS.h"
#import <AVFoundation/AVFoundation.h>
#implementation RJGoogleTTS
#synthesize delegate, downloadedData;
- (id)init
{
self = [super init];
if (self) {
// Initialization code here.
}
return self;
}
- (void)convertTextToSpeech:(NSString *)searchString {
NSString *search = [NSString stringWithFormat:#"http://translate.google.com/translate_tts?q=%#", searchString];
search = [search stringByReplacingOccurrencesOfString:#" " withString:#"%20"];
NSLog(#"Search: %#", search);
self.downloadedData = [[NSMutableData alloc] initWithLength:0];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:search]];
[request setValue:#"Mozilla/5.0" forHTTPHeaderField:#"User-Agent"];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];
[delegate sentAudioRequest];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
NSLog(#"did you receive response user");
[self.downloadedData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
NSLog(#"did you receive data user");
[self.downloadedData appendData:data];
// AVAudioPlayer *audioPlayer = [[AVAudioPlayer alloc]initWithData:downloadedData error:nil];
// [audioPlayer play];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
NSLog(#"Failure");
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSLog(#"it worked user!!!");
[delegate receivedAudio:self.downloadedData];
NSLog(#"hmmmm %d", [self.downloadedData length]);
// NSString *txt = [[NSString alloc] initWithData:downloadedData encoding: NSASCIIStringEncoding];
// NSLog(#"%#hello",txt);
}
#end
Remember that this is happening asynchronously. You set the size of downloadedData to 0 after your call the NSURLConnection.
Move:
self.downloadedData = [[NSMutableData alloc] initWithLength:0];
before your call to NSURLConnection.
There's nothing wrong with your NSURLConnection methods. Your search string is wrong. It should be:
NSString *search = [NSString stringWithFormat:#"http://translate.google.com/translate_tts?tl=en&q=%#",searchString];
You didn't start the URLConnection. Change [[NSURLConnection alloc] initWithRequest:request delegate:self]; like this [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];

Resources