I am currently building an Iphone app that is using storyboards. I know how to open new views with buttons via the ctrl+click method etc. The problem I have is that when the user clicks the button, I need to do some calculations and processing, as well as opening a web connection to pull data so I can populate the table in the next view but the view opens first before I can do any of this.
What I'm running into is the view is loading long before I am finished connecting to the web service and have calculated and stored the data for the table in the next view, so it loads blank. I need to either call the view in the button programmatically or somehow slow down the processes with some kind of "loading" screen but don't know how to do either. I guess if its possible to fill the data in the table after the view loads, that could work as well. (if its possible)
Any tips or articles that can point me in the right direction would be appreciated. I haven't found anything myself.
Thanks.
--connect method--
- (IBAction)connect:(id)sender {
//First begin by logging into the web service.
_email = self.logintxt.text;
// ---SOAP 1.1---
//large soap creation. edited for privacy etc.
NSString *soapMsg =
[NSString stringWithFormat:#"",_logintxt.text
];
//---print it to the Debugger Console for verification---
//NSLog(soapMsg);
NSURL *url = [NSURL URLWithString:
#""];
NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url];
//---set the headers---
NSString *msgLength = [NSString stringWithFormat:#"%d", [soapMsg length]];
[req addValue:#"" forHTTPHeaderField:#"Host"];
[req addValue:#"text/xml; charset=utf-8" forHTTPHeaderField:#"Content-Type"];
[req addValue:#"" forHTTPHeaderField:#"SOAPAction"];
[req addValue:msgLength forHTTPHeaderField:#"Content-Length"];
//---set the HTTP method and body---
[req setHTTPMethod:#"POST"];
[req setHTTPBody: [soapMsg dataUsingEncoding:NSUTF8StringEncoding]];
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:req delegate:self];
if (conn) {
XMLData = [NSMutableData data];
}
[self performSelector:#selector(getXMLList) withObject:NULL afterDelay:2.0];
[self performSegueWithIdentifier:#"LoginSegue" sender:sender];
You can have your button or whatever linked to a method in your controller, and inside the method after your processing you can call performSegueWithIdentifier: to force the transition when you're done. This will automatically still call prepareForSegue: before the view appears.
I've done something similar to check login details on a login page in my tutorial here.
what I can suggest is to write the button action yourself. to achieve this you have to put stuff in your .h like
#interface MyClass : UIViewController {
IBOutlet UIButton *my_btn;
}
#property (nonatomic, retain) IBoutlet UIButton *my_btn;
- (IBAction)MyBtnTapped:(id)sender;
in your .m remember to
#synthesize my_btn;
then just link the action to your button by using IB, and voila'
the first step is done.
in your .m you can now implement a function MybtnTapped that deals with the data retrival and then opens up the new UIView fulfilled with your new data.
Related
I am developing an application that integrates a payment gateway. This works by opening the page "https://sis.sermepa.es/sis/realizarPago" passing some parameters by POST, from there the customer can make the payment.
My problem is that I can not find how to open the browser giving a URL and parameters. I've seen that open the browser using Intents but does not allow parameters and I have seen that you can send POST parameters to a URL and wait for the response, but not open the URL itself.
Does anyone have the solution to my problem?
Thank you very much.
I've solved the problem, here you have the solution in case anyone else needs the answer.
NSString *code=codeTF.text;
NSString *price=priceTF.text;
NSString *email=emailTF.text;
NSString *body = [NSString stringWithFormat:Code=%#&Price=%#&E-mail=%#", code, price, email];
NSURL *url = [NSURL URLWithString:#"https://***/index.php"];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc]initWithURL:url];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:[body dataUsingEncoding:NSUTF8StringEncoding]];
//initialize the webViem in the *.h
// #property (nonatomic, retain) UIWebView *webView;
[webView loadRequest:request];
I am consuming Web Service to fetch data and it returns a set of data from server, this works great before i install xcode 5, previously my app was compatible with ios6 now i changed to ios 7. Now i have one issue while fetching data from web service .
When i go first time to the UIViewController view i call web service in -(void)ViewDidLoad and no data return and if i call one more time ( without going back from view, i call again the same web service) it returns data, when i call first time it returns empty data but second time it return data, This is happening in ios 6 but the same code work perfect without any web service issue in ios 7. after i change
I am Receiving response from server but the data inside is null for first time, but the same time i run in ios 7 device its return data, so i don't understand where i am wrong??????
NSMutableData *serverData;
//delegate methods for NSURLConnection
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSString *str = [[NSString alloc] initWithData:serverData encoding:NSUTF8StringEncoding];//here i am initializing
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[serverData appendData:data]; // here i get data that is null but i get response from server
}
Myviewwillappear code here...
- (void)viewWillAppear:(BOOL)animated {
[self performSelector:#selector(GetDataFromServer) withObject:nil afterDelay:0.001];
}
- (void) GetDataFromServer {
NSString *soapMessage = [NSString stringWithFormat:#"<?xml version=\"1.0\" encoding=\"utf-8\"?>"
#"<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">"
#"<soap:Body>"
#"<GetProductList xmlns=\"http://tempuri.org/\">"
#"<inCompany>%#</inCompany>"
#"<inUserName>%#</inUserName>"
#"<inType>%#</inType>"
#"<inTypeValue>%#</inTypeValue>"
#"<inSearchVal>%#</inSearchVal>"
#"<inPage>%#</inPage>"
#"</GetProductList>"
#"</soap:Body>"
#"</soap:Envelope>",Company,Username,type,typevalue,searchval,page];
NSURL *url = [NSURL URLWithString:PVBASE_URL];
NSString *msgLength = [NSString stringWithFormat:#"%d",[soapMessage length]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request addValue:#"text/xml; charset=utf-8" forHTTPHeaderField:#"Content-Type"];
[request addValue:PVPRODUCTLIST forHTTPHeaderField:#"SOAPAction"];
[request setHTTPMethod:#"POST"];
[request addValue:msgLength forHTTPHeaderField:#"Content-Length"];
[request setHTTPBody:[soapMessage dataUsingEncoding:NSUTF8StringEncoding]];
connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
if (connection) {
if (serverData) {
serverData = nil;
}
serverData = [[NSMutableData alloc] init];
}
connection = nil;
}
Basically i have en-counted this issue several times as when ever viewDidLoad execute didn't get any data but explicit call from IBaction it does. this is nothing to deal with iOS. basic problem with your web-service call.
You might be be calling data with using public variable which not execute or initialize.
Please provide your code for better understanding.
Thanks !!
I thought I would share my answer here as a possible solution. I had a similar problem occur with iOS6 and when I upgraded to iOS7 the network stack appeared to not be working because I was not getting data on the didRecieveResponse function of NSURLConnection. When in actuality from comparing how my code acted between iOS platforms it only looked like I was not receiving data from the didRecieveResponse function because sometimes the expectedContentLength mostly returned -1, but this also happened in iOS 6. In iOS7 the problem originated from another source that is unrelated to this example or my network connection that was affecting my use of NSOperation. So my point is, possibly the problem is not your platform differences but your code running your functionality. I would go through your code again for errors.
I am trying to set up a cache, however the method I am using 'as below' is not being accessed by the thread.
- (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse
I am initializing the connection like this, and connectionDidFinishLoading is accessed so I am not sure what I am missing.
- (IBAction)searchRequest:(NSData *)postBodyData
{
//Set database address
NSMutableString *databaseURL = [[NSMutableString alloc] initWithString:#"https://127.0.0.1:88"];
NSURL *url = [NSURL URLWithString:databaseURL];
NSString *postLength = [NSString stringWithFormat:#"%d", [postBodyData length]];
//SynchronousRequest to grab the data, also setting up the cachePolicy
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:5.0]; //if request dose not finish happen within 60 second timeout.
// NSInputStream *fileStream = [NSInputStream inputStreamWithData:postBodyData];
[request setHTTPMethod: #"POST"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/octet-stream" forHTTPHeaderField:#"content-type"];
[request setHTTPBody:postBodyData];
NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:request delegate:self];
if (theConnection) {
// Create the NSMutableData to hold the received data.
// receivedData is an instance variable declared elsewhere.
receivedData = [NSMutableData data];
} else {
// Inform the user that the connection failed from the connection:didFailWithError method
}
}
any help would be appreciated.
connection:willCacheResponse: is only called in cases when the response will be cached. POST requests are not cacheable in most cases. (More details: Is it possible to cache POST methods in HTTP?)
You should probably look at something like MKNetworkKit which handles a lot of this kind of caching, particularly for REST protocols.
You can also look at Drop-in offline caching for UIWebView. You'd have to modify it significantly, but NSURLProtocol can be used to solve this kind of problem. AFCache is currently working to integrate this approach, and is another toolkit to consider. (Read through the comments in the blog post for more background on the issues.)
I see the rate limit is 150/hr per IP. This'd be fine, but my application is on a mobile phone network (with shared IP addresses).
I'd like to query twitter trends, e.g. GET /trends/1/json.
This doesn't require authorization, however what if the user first authorized with my application using OAuth, then hit the JSON API?
The request is built as follows:
- (void) queryTrends:(NSString *) WOEID {
NSString *urlString = [NSString stringWithFormat:#"http://api.twitter.com/1/trends/%#.json", WOEID];
NSURL *url = [NSURL URLWithString:urlString];
NSURLRequest *theRequest=[NSURLRequest requestWithURL:url
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:10.0];
NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:theRequest delegate:self startImmediately:YES];
if (theConnection) {
// Create the NSMutableData to hold the received data.
theData = [[NSMutableData data] retain];
} else {
NSLog(#"Connection failed in Query Trends");
}
//NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:urlString]];
}
I have no idea how I'd build this request as an authenticated one however, and haven't seen any examples to this effect online.
I've read through the twitter OAuth documentation, but I'm still puzzled as to how it should work.
I've experimented with OAuth using Ben Gottlieb's prebuild library, and calling this in my first viewDidLoad:
OAuthViewController *oAuthVC = [[OAuthViewController alloc]
initWithNibName:#"OAuthTwitterDemoViewController" bundle:[NSBundle mainBundle]];
// [self setViewController:aViewController];
[[self navigationController] pushViewController:oAuthVC animated:YES];
This should store all the keys required in the app's preferences, I just need to know how to build the GET request after authorizing!
Maybe this just isn't possible? Maybe I'll have to proxy the requests through a server side application?
Any insight would be appreciated!
Authorizing through OAuth will provide you an authorization token, which you need to pass to each request you make later on.
Refer to Twitter docs, read about how authorization works.
Okay, after a lot of searching I've managed to figure how to construct a request to the JSON API programmatically in Xcode.
Firstly, you need to use the OAuth demo code to authenticate and authorize your application.
Then, you'll be retrieving the key by doing: [prefs stringForKey:#"authData"] - if this doesn't exist, you haven't been OAuth'd properly.
I had to reverse engineer this by looking through the code of the OAuth library, and while it's easy to use the library for stuff like sending a status update, it doesn't allow you to retrieve trends...:
#import "OAMutableURLRequest.h"
#import "MGTwitterHTTPURLConnection.h"
NSMutableString *dataString;
// Using OAuth:
OAConsumer *consumer = [[OAConsumer alloc] initWithKey:#"YOURCONSUMERKEY"
secret:#"YOURCONSUMERSECRET"];
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
NSString *authData = [prefs stringForKey:#"authData"];
// [_engine
OAMutableURLRequest *theRequest = [[[OAMutableURLRequest alloc] initWithURL:[NSURL URLWithString:#"http://stream.twitter.com/1/statuses/filter.json"]
consumer:consumer
token: (authData) ? [[OAToken alloc] initWithHTTPResponseBody:authData] : nil
realm: nil
signatureProvider:nil] autorelease];
[theRequest setHTTPMethod:#"POST"];
[theRequest setHTTPBody: [httpBody dataUsingEncoding:NSUTF8StringEncoding]];
[theRequest setHTTPShouldHandleCookies:NO];
// Set headers for client information, for tracking purposes at Twitter.
[theRequest setValue:#"Trendy" forHTTPHeaderField:#"X-Twitter-Client"];
[theRequest setValue:#"1.0" forHTTPHeaderField:#"X-Twitter-Client-Version"];
[theRequest setValue:#"http://www.inisdesign.com" forHTTPHeaderField:#"X-Twitter-Client-URL"];
// Set the request body if this is a POST request.
[theRequest prepare];
// Create a connection using this request, with the default timeout and caching policy,
// and appropriate Twitter request and response types for parsing and error reporting.
MGTwitterHTTPURLConnection *connection;
connection = [[MGTwitterHTTPURLConnection alloc] initWithRequest:theRequest
delegate:self
requestType:MGTwitterFollowedTimelineRequest // Wrong type
responseType:MGTwitterStatuses]; // as above - doesnt seem to matter
if (!connection) {
return;
} else {
// [_connections setObject:connection forKey:[connection identifier]];
// [connection release];
dataString = [[NSMutableData data] retain];
[connection start];
}
}
The rest is implemented as a standard URL connection with didReceiveData methods etc..
I haven't verified this is alleviating my rate limiting problems, but hey.. It's a start if anybody has similar problems.
NSString *reqURL = [NSString stringWithFormat:#"%#/login",SERVER_URL];
NSMutableURLRequest *req = [[NSMutableURLRequest alloc]initWithURL:[NSURL URLWithString:reqURL]];
[req setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"content-type"];
NSData *myRequestData = [NSData dataWithBytes:[#"username=whatever&password=whatever" UTF8String] length: [#"username=whatever&password=whatever" length]];
[req setHTTPMethod: #"POST"];
[req setHTTPBody: myRequestData];
NSData *returnData = [NSURLConnection sendSynchronousRequest:req returningResponse: nil error: nil];
NSString *html = [[NSString alloc] initWithData:returnData encoding:NSUTF8StringEncoding];
I got this code from another question I asked. But what happens if there is more than one submit button. I really have no idea how to ask this question. An example of such situation is on the logout page for this site. There are no fields to enter data into, but there are 2 submit buttons.
How can I "simulate clicking" on one of those buttons using code like the above (so not using a UIWebView)
The way those forms usually tell which button was pressed is by naming their buttons and checking the value. Simply put, a basic page receiving form data will check if a form was even submitted by checking if ($_POST['submit'] == "Send!") which tells the page that the user got there by pressing the button. The same concept is used when deciding what button was pressed.
if ($_POST["submit"] == "Send!") addDataToDB();
else if ($_POST["submit"] == "Update!") updateUser();
else if ($_POST["submit"] == "Remove me!") removeUser();
So now, what you need to do is check the source of the html page with the form and find out the name and value of the submit button you want to simulate and add that data to your POST body data in your request
Update: Oops! misunderstood your question, thought you meant multiple submit buttons in one form on one page, but now i think you meant one form going to another "confirmation" form...In your didRecieveData delegate method you will need to store all the html you get and in your didFinishLoading delegate method you will need to pull out any hidden field names & values and then create a new request with them as your POST data and the url being the "action" url of the form