I have a standalone UIViewController with a UIWebView. I need to check if a certain URL has been hit, and if so, present a new UIViewController inside of a UINavigationController.
Here is my code:
-(BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType {
NSURL *url = request.URL;
NSString *urlString = url.absoluteString;
//Check if special link
if ( [ urlString isEqualToString: #"http://www.mysite.com/store" ] ) {
//Here present the new view controller
StoreViewController *controller = [[StoreViewController alloc] init];
[self presentViewController:controller animated:YES completion: nil];
return NO;
}
return YES;
}
However, when I run the app, I get the following error:
WebKit threw an uncaught exception in the method
webView:decidePolicyForNavigationAction:request:frame:decisionListener:
delegate:
<'NSInvalidArgumentException'> * -[__NSArrayM insertObject:atIndex:]:
object cannot be nil
If I try and open the UINavigationController itself it works fine...but then how do I pass data to the StoreViewController itself?
Let's try these solutions:
Destroy webview's delegate in your view controller:
-(void)dealloc{ self.yourWebView.delegate = nil}
Stop request from webView:
-(BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType {
StoreViewController *controller = [[StoreViewController alloc] init];
[self presentViewController:controller animated:YES completion: nil];
//stop loading here
[webview stopLoading];
return NO;
}
Double check in new view controller, do you have any array which it's element is assigned to nil
Hope this helps you
Lets go through the problems one by one:
WebKit Exception: You can resolve this by stopping the webview loading. Just call [webView stopLoading];
Pass data: If you declare your required data in the StoreViewController.h you can easily set them when you are initializing the view controller.
StoreViewController *controller = [[StoreViewController alloc] init];
controller.myStringData = #"Required Data";
controller.myDataDictionary = someDictionary;
You will be able to get the data in the viewDidLoad method of StoreViewController
Hope this helps.
Related
In my webView's delegate method I am checking for the condition when webview loading fully completes by using this code:
if ([[webView stringByEvaluatingJavaScriptFromString:#"document.readyState"] isEqualToString:#"complete"]) {
//Code to handle other things
//Sometimes after this block shouldStartLoadWithRequest is called
}
Sometimes even control goes to if block even then -shouldStartLoadWithRequest this method is being called and my code breaks.
Is their any other alternative? I also tried webview.isLoading but this also doesn't work.
You could use javascript and the userContentController as a way for your page to message back to your native code that it is loaded and ready. When you setup your WkWebView, setup the handler like this:
WKWebViewConfiguration *theConfiguration = [[WKWebViewConfiguration alloc] init];
WKUserContentController *controller = [[WKUserContentController alloc] init];
[controller addScriptMessageHandler:self name:#"observe"];
theConfiguration.userContentController = controller;
CGRect statusBarFrame = [UIApplication sharedApplication].statusBarFrame;
CGRect frame = self.view.frame;
frame.origin.y = statusBarFrame.size.height;
frame.size.height -= statusBarFrame.size.height;
self.primaryWebView = [[WKWebView alloc] initWithFrame:frame configuration:theConfiguration];
Then add a method to your ViewController called userContentController, like this:
- (void)userContentController:(WKUserContentController *)userContentController
didReceiveScriptMessage:(WKScriptMessage *)message {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Check the details in message.body for what your javascript said
NSLog(#"javascript message: %#", message.body);
});
}
I have found one workaround to stop any further execution of scripts after didFinishLoading.
I used following condition to stop reqeust:
- (BOOL)webView:(UIWebView *)webView
shouldStartLoadWithRequest:(NSURLRequest *)request
navigationType:(UIWebViewNavigationType)navigationType
{
if(navigationType == UIWebViewNavigationTypeLinkClicked)
{
//my code
}
}
I have a code (objective-c) that should open a new window (viewcontroller) when a link with a certain string in a uiwebview is clicked. But it doesn't work.
Here's the code from the .m file:
-(BOOL)webView2:(UIWebView*)webView2 shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType {
NSURL *url = request.URL;
NSString *urlString = url.absoluteString;
//Check if special link
if ( [ urlString isEqualToString: #"http://google.com/" ] ) {
//Here present the new view controller
ViewController *ViewController8 = [[ViewController alloc] init];
[self presentViewController:ViewController8 animated:YES completion:nil];
return NO;
}
return YES;
}
The new viewcontroller subclass name is: ViewController8 and the UIWebView subclass is: webView2
Here's the code from the .h file:
#import <UIKit/UIKit.h>
#interface ViewController8 : UIViewController
#end
#interface ViewController : UIViewController{
IBOutlet UIScrollView *scrollView;
IBOutlet UIButton *openMenu;
int draw1;
}
- (IBAction)OpenMenu:(id)sender;
#property (retain, nonatomic) IBOutlet UIScrollView *scrollView;
#end
How do I fix it so a new window (viewcontroller) is opened when a link with a certain string in a uiwebview is clicked.
First, are you sure about your method signature for the shouldStartLoadWithRequest delegate method?
Did you really override the default method to have it call:
-(BOOL)webView2:(UIWebView*)webView2 shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType
???
Or should you instead be replacing "webview2" with "webView" there?
Even if you did, the naming convention would be very confusing.
The default implementation is for a class named "UIWebView", but the delegate method references "webView".
But in your case, you have a class called "webView2", and you're calling a delegate method that should be named:
-(BOOL)webView2:(webView2 *)webView2 shouldStartLoadWithRequest...
Doesn't look right at all.
Somehow I think the problem is mixed up in there. But maybe I'm wrong. So the second question is, have you set a breakpoint at the beginning of your shouldStartLoadWithRequest method to see if it ever gets called?
When you say it "doesn't work", what does that mean? How far does it get?
If it actually gets to the method, then perhaps the problem is that the URL it contains is formatted differently than the string you're looking for. Perhaps the trailing '/' isn't there or "www." is there.
Edit:
I would try something like this:
-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType {
NSRange rangeOfGoogle = [request.URL.absoluteString rangeOfString:#"google.com"];
//Check if special link
if (rangeOfGoogle.location != NSNotFound) {
//Here present the new view controller
ViewController8 *viewController = [[ViewController8 alloc] initWithNibName:nil bundle:nil];
[self presentViewController:viewController animated:YES completion:nil];
return NO;
}
return YES;
}
I hope this will work for you
-(BOOL)webView:(UIWebView*)webView2 shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType {
if (navigationType == UIWebViewNavigationTypeLinkClicked) {
NSURL *url = request.URL;
NSString *urlString = url.absoluteString;
//Check if special link
if ( [ urlString isEqualToString: #"http://google.com/" ] ) {
//Here present the new view controller
ViewController *ViewController8 = [[ViewController alloc] init];
[self presentViewController:ViewController8 animated:YES completion:nil];
return NO;
}
}
return YES;
}
it works for me.
Here is an excerpt from the MyYouTube class where I create a YouTube video:
#interface MyYouTube : NSObject <UIWebViewDelegate>
#end
#implementation
- (void) createYouTubeVideoInView: (UIView*) mainView withContent: (NSDictionary*) contentDict {
// create url request
NSString * compiledUrl=[[NSString alloc] initWithFormat:#"http://_xxx_.com/app/youtube.php?yt=%#",[contentData objectForKey:#"cnloc"]];
NSURL * url=[[NSURL alloc] initWithString:compiledUrl];
NSURLRequest * request=[[NSURLRequest alloc] initWithURL:url];
// create the web view
webView=[[UIWebView alloc] initWithFrame:viewRef.bounds];
[webView loadRequest:request];
[webView setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
[[webView scrollView] setScrollEnabled:NO];
[[webView scrollView] setBounces:NO];
[webView setMediaPlaybackRequiresUserAction:NO];
[webView setDelegate:self];
NSLog(#"YOUTUBE: self: %#",self);
NSLog(#"YOUTUBE: delegate: %#",webView.delegate);
// add the webview to the main view
[mainView addSubview:webView];
}
Here's the thing:
If I set the Delegate to nil then the YouTube video plays fine.
BUT
If I set the Delegate to self then the app crashes and the console shows the following:
YOUTUBE: self: <MyYouTube: 0x16e05f70>
YOUTUBE: delegate: <MyYouTube: 0x16e05f70>
*** -[MyYouTube respondsToSelector:]: message sent to deallocated instance 0x16e2f420
Can anyone explain to me why the instances are different?
Why is there a call to respondsToSelector: on an instance which is different to the delegate? And how can this be fixed?
Many thanks.
I think the reason is that mainView can be released, causing releasing your webview after exiting from createYouTubeVideoInView method.
Insure that mainView is still alive. Place it on another view before calling this method.
And insure that you are having strong reference on MyYouTube object(NSObject). Make it an instance variable, for example.
I load a webpage in a uiwebviewcontroller,after click one link, it will pop a popovercontroller, is it possible to get this controller in my code?
Actually, this popovercontroller is not created by my code. The html detect the webpage is loaded by iDevice and pop this. That means, if I use safari to open webpage, it also will display this popovercontroller.
Thanks.
implement the UIWebView delegate method.
-(BOOL) webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
NSURL *url = request.URL;
NSString *urlString = url.absoluteString;
if([urlString isEqualToString :#"abc.com") // link on which want to open popoverview
{
UIPopoverController itemPopover = [[UIPopoverController alloc] initWithContentViewController:viewController];
[itemPopover presentPopoverFromRect:customCell.addImage.bounds inView:webViewpermittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
return NO; //if wanted to load the link on UIWebview return YES else return NO
}
return YES;
}
My app is crashing while releasing view controller object.
Here is my code.
TagCloudWebViewController *controller=[[[TagCloudWebViewController alloc]init]autorelease];
controller.htmlString=[[notification userInfo] valueForKey:#"url"];
[self.navigationController pushViewController:controller animated:YES];
This is my code from wheny above method is called
-(void)viewDidLoad{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(openTextInWebview:) name:#"kTouchTextUrl" object:Nil];
}
and
#pragma mark - UIGestureDelegate
- (void)longPressRecognized:(UILongPressGestureRecognizer *)longPressRecognizer {
CGPoint touchPoint = [longPressRecognizer locationInView:self];
NSArray *subviews = self.subviews;
for (int i=0; i<subviews.count; i++) {
TagView * tagLabel = (TagView *)[subviews objectAtIndex:i];
if ( CGRectContainsPoint( [tagLabel frame], touchPoint ) ) {
NSArray*objectArray=[[[NSArray alloc] initWithObjects:tagLabel.customLink, nil] autorelease];
NSArray*keyArray=[[[NSArray alloc] initWithObjects:#"url", nil] autorelease];
NSDictionary *userInfo = [NSDictionary dictionaryWithObjects:objectArray forKeys:keyArray ];
[[NSNotificationCenter defaultCenter] postNotificationName:#"kTouchTextUrl" object:nil userInfo:userInfo];
//[[UIApplication sharedApplication] openURL:[NSURL URLWithString: tagLabel.customLink]];
break;
}
}
}
and this is notification method
DidLoad method
- (void) viewDidLoad {
[super viewDidLoad];
_webView = [[UIWebView alloc] initWithFrame:self.view.bounds];
_webView.delegate = self;
_webView.autoresizingMask = (UIViewAutoresizingFlexibleWidth
| UIViewAutoresizingFlexibleHeight);
_webView.scalesPageToFit = YES;
[self.view addSubview:_webView];
[self initSpinner];
if (htmlString) {
[self openURL:[NSURL URLWithString:htmlString]];
}
}
WebView delgate method
-(void) webViewDidStartLoad:(UIWebView *)webView {
self.navigationItem.title = #"Loading...";
[spinnerView startAnimating];
isLoading = YES;
}
-(void) webViewDidFinishLoad:(UIWebView*)webView {
self.navigationItem.title = [_webView stringByEvaluatingJavaScriptFromString:#"document.title"];
[self performSelector:#selector(stopSpinner) withObject:nil afterDelay:0.1];
isLoading = NO;
}
-(void) webView:(UIWebView*)webView didFailLoadWithError:(NSError*)error {
[self webViewDidFinishLoad:webView];
[self performSelector:#selector(stopSpinner) withObject:nil afterDelay:0.1];
isLoading = NO;
}
(void) openURL:(NSURL*)URL {
NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:URL];
[_webView loadRequest:request];
}
Update: The following answer was in response to the original question of why the UIViewController with a UIWebView was not appearing. The OP's original theory was that it was related to some problem regarding the premature releasing of the view controller object. But, as outlined in my answer below, I suspect the problem was related to the creation of the view controller itself. Anyway, my answer to the original question follows (but it unfortunately has nothing to do with the revised question):
I personally don't suspect the problem has anything to do with the
releasing of the controller. I think it is in the creation of the
controller's view. There's nothing in the above code that causes the
object to be released, so you problem rests elsewhere and you need to
show more code. If you're concerned about your notification center
stuff, try bypassing it and just add a button that does your
TagCloudWebViewController alloc/init, sets htmlString and pushes,
and see if that still causes your program to crash, which I suspect it
will.
I notice that you're creating your controller via alloc and init,
but not initWithNibNamed. According to the UIViewController Class
Reference:
"If you cannot define your views in a storyboard or a nib file,
override the loadView method to manually instantiate a view
hierarchy and assign it to the view property."
So, bottom line, either use a NIB, use a storyboard or define a
loadView. Defining a viewDidLoad doesn't preclude the need for a
loadView. You need to create a view for your controller, which is
done for you if you use NIB or storyboard, or you have to do manually
via loadView, if you don't use NIB or storyboard.
See
iPhone SDK: what is the difference between loadView and viewDidLoad?
for a discussion of the differences between viewDidLoad and
loadView.
I don not see any thing that causing crashing.I think you have changed your question.As per question you not using ViewController any where.Please show more details.
Updated: Please check, you are creating autoreleased object, it might be you are releasing some where by mistake.Try to avoid autoreleased object as it remain in the Pool and later releases ,which may causes a memory issue for you.
The above problem is occurs due to WebView delgate. After pressing back button the reference of the object is deallocating from memory due to this app is crashing while releasing the viewcontroller object. I did some thing like
-(void) viewDidDisappear:(BOOL)animated{
if([_webView isLoading]) {
[_webView stopLoading];
}
[_webView setDelegate:nil];
}
due to above code my crashing has been resolved