In my app I am using UIwebview to display websites, however whenever I click back button and start playing with other parts in the app, the app mostly crashes with no reason. I suspect the webview is causing this issue because it crashes only when I try to open the webview.
I have used NSURLConnection to load the webview and have made webview, connection objects to nil in the view will Disappear method.
#implementation NewsWebSiteViewController
#synthesize connection,rcvdData,spinner1,currentSite,webView,newsWebsite;
- (void)viewDidLoad {
[super viewDidLoad];
#try {
self.webView.delegate=self;
[UIApplication sharedApplication].networkActivityIndicatorVisible=YES;
self.title= self.newsWebsite.title;
self.webView.backgroundColor =[UIColor groupTableViewBackgroundColor];
self.spinner1 = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
CGRect center = [self.view bounds];
CGSize winCenter = center.size;
CGPoint pont = CGPointMake(winCenter.width/2,winCenter.height/2);
[spinner1 setCenter:pont];
[self.view addSubview:spinner1];
[self.spinner1 startAnimating];
NSString *url = newsWebsite.link;
NSURLRequest *theReq =[NSURLRequest requestWithURL:[NSURL URLWithString:url] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:20.0];
self.connection = [[NSURLConnection alloc] initWithRequest:theReq delegate:self];
if(self.connection) {
self.rcvdData = [[NSMutableData data] retain];
}
else {
UIAlertView *alert = [[[UIAlertView alloc] initWithTitle:#"Error!" message:#"We are having a problem connecting to the internet, why not try again or try sometime later!.." delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil] autorelease];
[alert show];
}
webView.multipleTouchEnabled=YES;
webView.scalesPageToFit=YES;
}
#catch (NSException * e) {
}
}
-(void) goBack {
self.webView =nil;
[self.navigationController popViewControllerAnimated:YES];
}
-(void) viewWillDisappear:(BOOL)animated {
[self.connection cancel];
self.connection=nil;
[self.webView stopLoading];
self.webView=nil;
[UIApplication sharedApplication].networkActivityIndicatorVisible=NO;
if (self.spinner1 ==nil) {
}
else {
[self.spinner1 stopAnimating];
}
}
-(void) webViewDidFinishLoad:(UIWebView *)webView {
[UIApplication sharedApplication].networkActivityIndicatorVisible=NO;
if (self.spinner1 ==nil) {
}
else {
[self.spinner1 stopAnimating];
}
}
-(void) viewDidAppear:(BOOL)animated {
[UIApplication sharedApplication].networkActivityIndicatorVisible=NO;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (void)viewDidUnload {
[super viewDidUnload];
}
-(void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[self.rcvdData setLength:0];
}
-(void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[self.rcvdData appendData:data];
}
-(void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
if (self.spinner1 ==nil) {
}
else {
[self.spinner1 stopAnimating];
}
[connection release];
[rcvdData release];
UIAlertView *alert = [[[UIAlertView alloc] initWithTitle:#"Error!" message:#"We are having a problem connecting to the internet, why not try again or try sometime later!.." delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil] autorelease];
[alert show];
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection {
[connection release];
[rcvdData release];
NSString *url = newsWebsite.link;
NSURL *url1 = [NSURL URLWithString:url];
[self.webView loadData:self.rcvdData MIMEType:#"text/html" textEncodingName:#"UTF-8" baseURL:url1];
}
- (void)dealloc {
[super dealloc];
[self.spinner1 release];
}
#end
Firstly, here's a small primer to equality/inequality in C/Objective-C:
Let's say you have a BOOL value (ie, a value that can be either YES or NO, 'On' or 'Off', 'True' or 'False'), called isEnabled. Now, if I had assigned this BOOL value (sometimes called a 'flag') to 'YES', I could conditionally test its value like so:
BOOL isEnabled = YES;
if (isEnabled)
{
// value set to yes
}
In addition to the above, I can use the negation operator (an exclamation mark - otherwise known as the NOT operator) to flip isEnabled's value, and test its opposite value:
BOOL isEnabled = YES;
// the following reads as "if is *not* enabled"
if (!isEnabled)
{
// value set to no
}
now of course in the above example isEnabled is set to YES, so the condition will fail. But, if we consider the following example, the property of if whereby if an else if is 'met' (ie, true) anywhere in a series of if's and else if's, it will execute all the code inside it, and then ignore anything else:
BOOL isEnabled = NO;
if (isEnabled)
{
// any code here will not run, as the above if condition will be false
}
else if (!isEnabled)
{
// this code will run, since the above condition (!isEnabled) will evaluate to true
}
else if (isEnabled)
{
// this code could never run, since the previous condition was true and all following else if's are ignored
}
else if (!isEnabled)
{
// this code could never run, since the previous condition was true and all following else if's are ignored
}
while the above has two redundant else if's at the end, it is a good way to demonstrate how conditional code works.
So, in your webViewDidFinishLoad: method, instead of having a blank if to evaluate an if/else condition, you can replace that with a simpler condition:
-(void) webViewDidFinishLoad:(UIWebView *)webView
{
[UIApplication sharedApplication].networkActivityIndicatorVisible=NO;
// or, (self.spinner1 != nil)
if (!self.spinner1)
{
[self.spinner1 stopAnimating];
}
}
When you've made the above change to all your if's and else if's, post a stack trace and I'll see what else it could be.
Related
I am building one iPhone application where I have two views one for login view and another for web view. When user enters the login credentials, then it will redirect to web view. while loading the webview from login view too much time is taking to load. hence I used alertview to show loading image.
#interface FocusViewController ()
#end
#implementation FocusViewController
#synthesize txtsecurecode;
#synthesize webView;
#synthesize OrganizationCode;
UIActivityIndicatorView *indicator;
UIAlertView *alert;
- (void)viewDidLoad
{
[super viewDidLoad];
appDelegate = (FocusAppDelegate *)[[UIApplication sharedApplication]delegate];
if(appDelegate.data.strOrganizationCode == nil || appDelegate.data.strAccessCode == nil)
{
NSLog(#"YOUR FIRST SCREEN");
_loginView.hidden = NO;
webView.hidden = YES;
}
else
{
NSLog(#"LOAD WEBVIEW DIRECTLY\n");
NSLog(#"Organization Code -> %# \n Secure Access Code -> %#",appDelegate.data.strOrganizationCode,appDelegate.data.strAccessCode);
OrganizationCode.text = appDelegate.data.strOrganizationCode ;
txtsecurecode.text = appDelegate.data.strAccessCode;
[self loginClicked:nil];
webView.hidden = NO;
_loginView.hidden = YES;
}
}
- (IBAction)loginClicked:(id)sender {
#try {
if([[txtsecurecode text] isEqualToString:#""] || [[OrganizationCode text] isEqualToString:#""] ) {
[self alertStatus:#"Please enter Access code" :#"Login Failed!":0];
}
else
{
NSString *post =[[NSString alloc] initWithFormat:#"txtsecurecode=%# #&password=%#",[txtsecurecode text],[OrganizationCode text]];
NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] init] autorelease];
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"http://myexample.com/AccountService/security/ValidateAccess?accesscode=%#&companycode=%#&type=1", txtsecurecode.text, OrganizationCode.text]];
NSString *responseData = [[NSString alloc]initWithData:[NSData dataWithContentsOfURL:url] encoding:NSUTF8StringEncoding];
if([responseData isEqualToString:#""]){
[self alertStatus:#"Please enter valid Access Code" :#"Login Failed !" :0];
}
else
{
appDelegate.data.strOrganizationCode = OrganizationCode.text;
appDelegate.data.strAccessCode = txtsecurecode.text;
[FocusAppDelegate addCustomObjectToUserDefaults:appDelegate.data key:kCredentails];
//Updated
_loginView.hidden = YES;
webView.hidden = NO;
responseData = [responseData stringByReplacingOccurrencesOfString:#" "" " withString:#""];
NSString* encodedString = [responseData stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSLog(#"Response ==> %#" ,encodedString);
alert = [[[UIAlertView alloc] initWithTitle:#"Loading\nPlease Wait..." message:nil delegate:self cancelButtonTitle:nil otherButtonTitles: nil] autorelease];
[alert show];
UIActivityIndicatorView *indicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
indicator.center = CGPointMake(alert.bounds.size.width / 2, alert.bounds.size.height - 50);
[indicator startAnimating];
[alert addSubview:indicator];
[indicator release];
webView.backgroundColor = [UIColor clearColor];
webView.opaque = NO;
webView.delegate = self;
webView.frame = self.view.bounds;
NSString* urlTwo = [[encodedString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]
stringByReplacingOccurrencesOfString:#"%22" withString:#""];
NSURL *url2;
if([urlTwo hasPrefix:#"http://"]){
url2 = [NSURL URLWithString:urlTwo];
}else{
url2 = [NSURL URLWithString:[NSString stringWithFormat:#"http://%#" , urlTwo]];
}
NSLog(#"url2:%#", url2);
NSURLRequest *requestObj = [NSURLRequest requestWithURL:url2];
[webView loadRequest:requestObj];
[[self view] addSubview:webView];
}
}
}
#catch (NSException * e) {
NSLog(#"Exception: %#", e);
[self alertStatus:#"Login Failed." :#"Login Failed!" :0];
}
}
-(void)webViewDidStartLoad:(UIWebView *)webView{
NSLog(#"webViewDidStartLoad");
[self.view addSubview:self.indicator];
alert.hidden = NO;
}
- (void) webViewDidFinishLoad:(UIWebView *)webView {
NSLog(#"webViewDidFinishLoad");
[self.indicator removeFromSuperview];
[self.alert dismissWithClickedButtonIndex:1 animated:NO] ;
}
- (IBAction)backgroundClick:(id)sender
{
[txtsecurecode resignFirstResponder];
[OrganizationCode resignFirstResponder];
}
#end
Until content in webview displays, loading image is displaying and working good. but content of webview is not editable and remaining static as I think I used 'web view.hidden = YES'. when I comment the alert method and run then content of webview is also editable and working good as required. I need to load the content of url after loading image stops loading.
I would suggest show the activity indicator from the Viewcontroller having the WebView and implement the WebView Delegate methods
- (void)webViewDidStartLoad:(UIWebView *)webView
{
[actvityIndicator startAnimating];
}
and
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
[actvityIndicator stopAnimating];
}
this will keep your webview Interactive and also show the indicator till the page loads completely
you can try something like this. The Delegate is important in .h file
FocusViewController.h
#interface FocusViewController : UIViewController <UIWebViewDelegate> {
UIActivityIndicatorView *indicator;
}
FocusViewController.m
- (void)viewDidLoad
{
// Loading Indicator
indicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
[indicator setColor:[UIColor colorWithRed:50.0/255.0 green:120.0/255.0 blue:200.0/255.0 alpha:1.0]];
}
- (void)webViewDidStartLoad:(UIWebView *)webView
{
[indicator startAnimating];
}
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
[indicator stopAnimating];
}
I am making a program that loads videos from a server and then saves them locally. The programmed worked fine when i was doing it synchronizely. When I changed it to do it asynchronously , it would crash when the person return to the pre screen and try to press any of the buttons with a sig bad memory error.
What happens is the vedio loads and plays ok. When they click the done button the methed
- (void) moviePlayBackDidFinish:(NSNotification*)notification;{
[ mp stop];
// [ mp release];
[self dismissModalViewControllerAnimated: true];
}
exicutes and it goes to the pre screen. Now on the pre screen, if they click on any button, i get a
I did the following
1. the file is big so I chnage my
[[NSMutableData alloc] initWithLebngth:0]; to [[NSMutableData alloc] initWithCapacity:200000];, did not work.
- (void)viewDidLoad {
[super viewDidLoad];
// construct the url
NSString *mServerName=[ [ NSString alloc] initWithString:#"http://www.besttechsolutions.biz/projects/golfflix/" ];
NSString *mFullName=[ mServerName stringByAppendingString: mVedioName ];
NSURL *movieUrl=[[NSURL alloc] initWithString:mFullName];
// start the transmision
NSURLRequest *theRequest = [NSURLRequest requestWithURL:movieUrl cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:60];
receivedData = [[NSMutableData alloc] initWithCapacity:100000000];
connection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self startImmediately:YES];
[movieUrl release];
[mServerName release];
}
///////////////////////////////////////////////////////////////////////////////////////////////
// background loading
- (void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
[receivedData setLength:0];
}
- (void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[receivedData appendData:data];
}
- (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
[connection release];
}
- (NSCachedURLResponse *) connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse {
return nil;
}
- (void) connectionDidFinishLoading:(NSURLConnection *)connection {
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
[connection release];
/////////////////////////////////////////////////////////////////////////////////
// Save vedio
NSFileManager *mFile= [NSFileManager defaultManager];
NSString *filename=[ NSHomeDirectory() stringByAppendingPathComponent:mVedioName];
[mFile createFileAtPath:filename contents: receivedData attributes:nil];
[ receivedData release ];
// play it
NSURL *fileUrl=[ NSURL fileURLWithPath:filename];
if (mp==nil)
{
mp=[[MPMoviePlayerController alloc] initWithContentURL: fileUrl];
[mp.view setFrame: self.view.bounds];
[self.view addSubview: mp.view];
// Set movie player layout
[mp setControlStyle:MPMovieControlStyleFullscreen];
[mp setFullscreen:YES];
// May help to reduce latency
[mp prepareToPlay];
[mp play];
}
else {
[mp stop];
mp.contentURL=fileUrl;
[mp play];
}
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayBackDidFinish:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:nil];
// movie reced save to file
}
- (void) moviePlayBackDidFinish:(NSNotification*)notification;{
[ mp stop];
// [ mp release];
[self dismissModalViewControllerAnimated: true];
}
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc. that aren't in use.
}
- (void)viewDidUnload {
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
any thoughts on this would be GREAT, ben stuck for days!!!!
Ted
If you are coming back to the pre screen then try to shift your code to
-(void)viewWillAppear:(BOOl)animated
{
//code
}
because the function viewDidLoad will be called only one time when the view is loaded.
but the function viewWillAppear will be called whenever that view will appear.
i got code like this
#import "UIWebImageView.h"
#interface UIWebImageView (hiddenMethods)
- (void) initDefaults;
#end
#implementation UIWebImageView (hiddenMethods)
- (void) initDefaults
{
self.showActivityIndicator = NO;
self.activityIndicatorStyle = UIActivityIndicatorViewStyleWhite;
self.activityIndicatorSize = CGSizeMake(20.0, 20.0);
//data = [[NSMutableData alloc] init];
}
#end
#implementation UIWebImageView
#synthesize showActivityIndicator;
#synthesize activityIndicatorStyle;
#synthesize activityIndicatorSize;
- (id) init
{
if (self = [super init])
{
[self initDefaults];
}
return self;
}
- (void) loadFromURL:(NSString *) url
{
[self.image release];
self.image = nil;
request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]
cachePolicy:NSURLRequestReturnCacheDataElseLoad
timeoutInterval:30.0];
if (connection == nil)
connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
// activity indicator start
indicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:activityIndicatorStyle];
indicator.frame = CGRectMake((self.frame.size.width - activityIndicatorSize.width)/2, (self.frame.size.height - activityIndicatorSize.height)/2,
activityIndicatorSize.width, activityIndicatorSize.height);
[self addSubview:indicator];
[indicator startAnimating];
}
- (void) dealloc
{
[data release];
[indicator release];
[connection release];
[super dealloc];
}
#pragma mark -
#pragma mark connection delegate
- (void) connection:(NSURLConnection *)theConnection didReceiveData:(NSData *)incrementalData
{
if (data == nil)
data = [[NSMutableData alloc] initWithCapacity:2048];
[data appendData:incrementalData];
}
- (void) connectionDidFinishLoading:(NSURLConnection *)theConnection
{
self.image = [UIImage imageWithData:data];
[indicator removeFromSuperview];
//data = nil;
[data release], data = nil;
[connection release], connection = nil;
[indicator release], indicator = nil;
}
- (void) connection:(NSURLConnection *)theConnection didFailWithError:(NSError *)error
{
self.image = [UIImage imageNamed:#"icon.jpg"];
[indicator removeFromSuperview];
//data = nil;
[data release], data = nil;
[connection release], connection = nil;
[indicator release], indicator = nil;
}
I'm using this for downloading images from web. one image for every cell in in table. and it works fine when image is not going out of the screen. BUT when u scrolling tableView fast and some images did not finished loading while they are on screen there huge memory leaks.
i know where is the leak and why its leaking. but i can't find solution.
any thoughts ?
thank you
PS sorry for my english
UPDATE
here is a code for adding images into tableView
UIWebImageView *tmpImageView = [[UIWebImageView alloc] initWithFrame:CGRectMake(0, 0, 57, 76)];
tmpImageView.showActivityIndicator = YES;
tmpImageView.contentMode = UIViewContentModeScaleAspectFit;
tmpImageView.activityIndicatorStyle = UIActivityIndicatorViewStyleGray;
[tmpImageView loadFromURL:[[tableArray objectAtIndex:indexPath.row] objectForKey:#"picurl"]];
[cell addSubview:tmpImageView];
[tmpImageView release];
and I'm repeating = ) its leaking only when it not finished loading and went off the screen while scrolling
The leaks are happening due to the allocation of UIWebImageView objects recursively (considering you are using reusable cells).
you should change your code to:
UIWebImageView *tmpImageView = [cell viewWithTag:2011];
if(!tmpImageView)
{
tmpImageView = [[UIWebImageView alloc] initWithFrame:CGRectMake(0, 0, 57, 76)];
tmpImageView.showActivityIndicator = YES;
tmpImageView.tag = 2011;
tmpImageView.contentMode = UIViewContentModeScaleAspectFit;
tmpImageView.activityIndicatorStyle = UIActivityIndicatorViewStyleGray;
[cell addSubview:tmpImageView];
[tmpImageView release];
}
[tmpImageView loadFromURL:[[tableArray objectAtIndex:indexPath.row] objectForKey:#"picurl"]];
you have to handle for the showActivityIndicator thing some how...based upon your code but the above mentioned change will remove your memory leaks.
Autorelase your NSURLConnection with this syntax
connection = [NSURLConnection connectionWithRequest:request delegate:self];
and delete your [connection release], connection = nil;
I have made an application that logs onto a simple UIWebview login page and then authenticates on the website that loads. The thing is, I want my app to autheticate on the website and as soon as it is authenticated I want it to redirect my app to the view I have made in Xcode. I am fairly new to iphone programming.
Any help would be appreciated.
The code I made so far also consists of cookies, and it looks as follows:
FOR MY APP DELEGATE:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[self initPreferences];
// Override point for customization after application launch.
NSArray *siteArray = [[NSArray alloc] initWithObjects:#"http://...com",
#"http://....com",
#"http://...com",
#"http://...com",
#"http://.com",
nil];
SignonWebView *webView = [[SignonWebView alloc] initWithURL:[siteArray objectAtIndex:2]];
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self selector:#selector(cookieChange:) name:#"NSHTTPCookieManagerCookiesChangedNotification" object:nil];
if ([Constants useAuthenticator])
{
[[self window] addSubview:[webView view]];
}
else
{
[self.window addSubview:navigationController.view];
}
// [self.window makeKeyAndVisible];
// Check for device
if (![self deviceConnected])
{
[Constants setConnectedToDevice:NO];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"ALERT!" message:#"Device Not Detected" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
[alert autorelease];
}
else
{
if ([Constants isLineaPro])
{
NSLog(#"Init LineaPro device");
}
else if ([Constants isVerifone])
{
NSLog(#"Init Verifone device");
DeviceControl *dc = [DeviceControl sharedInstance]; // Singleton initializes device
[[dc payControl] hostPowerEnabled:YES];
NSLog(#"---------------------- Sending message to MSR");
[[dc pinPad] sendStringCommand:#"Q40" calcLRC:YES];
}
}
//AdminViewController = [[AdminViewController alloc] init];
[self.window makeKeyAndVisible];
//[self.navigationController.navigationBar setTintColor:[UIColor colorWithRed:0.933 green:0.114 blue:0.149 alpha:1]];
//[[UIApplication sharedApplication] setupScreenMirroringOfMainWindow:navigationController framesPerSecond:20];
//[[UIApplication sharedApplication] setupScreenMirroringWithFramesPerSecond:20];
return YES;
//[self.parentViewController.view setHidden:YES];
}
-(void)cookieChange:(NSHTTPCookieStorage *)somethin
{
NSLog(#"----------- Cookies have changed sucessfully
---------------");
}
FOR MY LOGIN VIEW WHICH HAS COOKIES:
-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
NSLog(#"shouldStartLoadWithRequest");
return YES;
}
- (void)webViewDidStartLoad:(UIWebView *)webView
{
NSLog(#"webViewDidStartLoad");
}
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
NSLog(#"***************** webViewDidFinishLoad --- getting all cookies");
NSMutableArray *cookieList = [[NSMutableArray alloc] init];
NSHTTPCookie *cookie;
for (cookie in [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies]) {
[cookieList addObject:cookie];
// NSLog(#"%# expire: %#\n%#", [cookie name],[cookie expiresDate],cookie);
}
NSLog(#"Number of cookies is %d",[cookieList count]);
if (initialLoad)
{
NSLog(#"---- removing existing cookies -----");
for (NSHTTPCookie *currentCookie in cookieList)
{
NSLog(#"Removing cookie : %#",[currentCookie name]);
//[[NSHTTPCookieStorage sharedHTTPCookieStorage] deleteCookie:currentCookie];
}
initialLoad = NO;
}
else
{
for (NSHTTPCookie *currentCookie in cookieList)
{
NSLog(#"='%#'",currentCookie);
if ([[currentCookie name]isEqual:#"UserID"]) {
// we have a user id returned from services, so save it
[self setUserIDCookie:currentCookie];
NSLog(#" -- userIDCookie : %#",[[self userIDCookie] value]);
[self setUserID:([[self userIDCookie] value])];
}
if ([[currentCookie name]isEqual:#"UserName"]) {
// we have a user id returned from services, so save it
[self setUserNameCookie:currentCookie];
NSLog(#" -- userNameCookie : %#",[[self userNameCookie] value]);
[self setUserName:([[self userNameCookie] value])];
}
}
}
}
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
{
NSLog(#"didFailLoadWithError : %#",error);
}
#pragma mark -
#pragma mark Actions
-(void)loadUrl:(NSString*)URL
{
[myWebView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:URL]]];
}
#end
If the authentication is successful, have the server redirect to a certain URL. Then, in webView:shouldStartLoadWithRequest:navigationType:, check for that URL and move to your other view when it is loaded.
-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
NSLog(#"shouldStartLoadWithRequest");
if([[[request URL] absoluteString] isEqualToString:#"http://authSuccess.website.com"]) {
[[[UIApplication sharedApplication] delegate] authenticationSuccessful];
return NO;
}
return YES;
}
And, in the app delegate:
- (void)authenticationSuccessful {
[[[self.window subviews] objectAtIndex:0] removeFromSuperview];
[self.window addSubview:navigationController.view];
}
I´m writing an program that uses twitter. I want that my app shows an UIAlertView when the user presses on the "Tweet"-Button and the username or password is wrong.
For my Twitterfunction I use the TwitterRequest.m/h from Brandon Trebitowski. If everthing works great and the username/password is right, this happens in my app:
TwitterRequest * t = [[TwitterRequest alloc] init];
(...);
[t statuses_update:twittermessage.text delegate:self requestSelector:#selector(status_updateCallback:)];
loadingActionSheet = [[UIActionSheet alloc] initWithTitle:#"Posting to Twitter..." delegate:nil
cancelButtonTitle:nil destructiveButtonTitle:nil otherButtonTitles:nil];
[loadingActionSheet showInView:self.view];
}
- (void) status_updateCallback: (NSData *) content {
[loadingActionSheet dismissWithClickedButtonIndex:0 animated:YES];
[loadingActionSheet release];
NSLog(#"%#",[[NSString alloc] initWithData:content encoding:NSASCIIStringEncoding]);
}
But how can I show an UIAlertView when the username/password was wrong?
Here is the TwitterRequest.m:
#import "TwitterRequest.h"
#implementation TwitterRequest
#synthesize username;
#synthesize password;
#synthesize receivedData;
#synthesize delegate;
#synthesize callback;
#synthesize errorCallback;
-(void)friends_timeline:(id)requestDelegate requestSelector:(SEL)requestSelector{
isPost = NO;
// Set the delegate and selector
self.delegate = requestDelegate;
self.callback = requestSelector;
// The URL of the Twitter Request we intend to send
NSURL *url = [NSURL URLWithString:#"http://twitter.com/statuses/friends_timeline.xml"];
[self request:url];
}
-(void)statuses_update:(NSString *)status delegate:(id)requestDelegate requestSelector:(SEL)requestSelector; {
isPost = YES;
// Set the delegate and selector
self.delegate = requestDelegate;
self.callback = requestSelector;
// The URL of the Twitter Request we intend to send
NSURL *url = [NSURL URLWithString:#"http://twitter.com/statuses/update.xml"];
requestBody = [NSString stringWithFormat:#"status=%#",status];
[self request:url];
}
-(void)request:(NSURL *) url {
theRequest = [[NSMutableURLRequest alloc] initWithURL:url];
if(isPost) {
NSLog(#"ispost");
[theRequest setHTTPMethod:#"POST"];
[theRequest setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[theRequest setHTTPBody:[requestBody dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES]];
[theRequest setValue:[NSString stringWithFormat:#"%d",[requestBody length] ] forHTTPHeaderField:#"Content-Length"];
}
theConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if (theConnection) {
// Create the NSMutableData that will hold
// the received data
// receivedData is declared as a method instance elsewhere
receivedData=[[NSMutableData data] retain];
} else {
// inform the user that the download could not be made
}
}
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
//NSLog(#"challenged %#",[challenge proposedCredential] );
if ([challenge previousFailureCount] == 0) {
NSURLCredential *newCredential;
newCredential=[NSURLCredential credentialWithUser:[self username]
password:[self password]
persistence:NSURLCredentialPersistenceNone];
[[challenge sender] useCredential:newCredential
forAuthenticationChallenge:challenge];
} else {
[[challenge sender] cancelAuthenticationChallenge:challenge];
// inform the user that the user name and password
// in the preferences are incorrect
NSLog(#"Invalid Username or Password"); //THIS MUST be important. The console shows this message, if the username/password is wrong. Here is also the place, where I set the bool to TRUE
}
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
// this method is called when the server has determined that it
// has enough information to create the NSURLResponse
// it can be called multiple times, for example in the case of a
// redirect, so each time we reset the data.
// receivedData is declared as a method instance elsewhere
//[receivedData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
//NSLog([[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
// append the new data to the receivedData
// receivedData is declared as a method instance elsewhere
[receivedData appendData:data];
}
- (void)connection:(NSURLConnection *)connection
didFailWithError:(NSError *)error
{
// release the connection, and the data object
[connection release];
// receivedData is declared as a method instance elsewhere
[receivedData release];
[theRequest release];
// inform the user
NSLog(#"Connection failed! Error - %# %#",
[error localizedDescription],
[[error userInfo] objectForKey:NSErrorFailingURLStringKey]);
if(errorCallback) {
[delegate performSelector:errorCallback withObject:error];
}
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// do something with the data
if(delegate && callback) {
if([delegate respondsToSelector:self.callback]) {
[delegate performSelector:self.callback withObject:receivedData];
} else {
NSLog(#"No response from delegate");
}
}
// release the connection, and the data object
[theConnection release];
[receivedData release];
[theRequest release];
}
-(void) dealloc {
[super dealloc];
}
#end
I know that the important line in the TwitterRequest.m is in the else-cause of the -(void)connection-methode, because the Console writes always Invalid Username or Password, when they are wrong. So I tried to make there a bool as propertey, which will be set to TRUE, when the name/password is wrong(= when the else-cause will be used). In my ViewController I made this:
if (t.stimmtNicht == TRUE) {
[loadingActionSheet dismissWithClickedButtonIndex:0 animated:YES];
[loadingActionSheet release];
UIAlertView *alert;
alert = [[UIAlertView alloc] initWithTitle:#"Ouch!"
message:#"Your Username or Password is wrong!"
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles: nil];
[alert show];
[alert release];
}
But he always doesn't use the if-cause, even if the password is wrong. I think the code go faster through the if-quere than the TwitterRequest set it to TRUE. What can I do?
Thanks for your help and sorry for this stupid question, but I'm learning Objective-C and programming in general since just one week and I don´t know correctly how to interact from my ViewController with other classes.
Also sorry for my bad English!
Two ways I can think of:
Apparently your TwitterRequest class has a "delegate" ivar; try calling the delegate to tell him (her?) that your credentials are wrong.
Send an NSNotification through the NSNotificationCenter
In both cases, the class who gets notified should display the login view (with the username and password fields), and that's it.