UIWebView will not loadRequest inside a separate class file - objective-c

I have a UIWebView that is successfully being created dynamically from an included class file (I think... there are no errors being spit out). My function that creates this webview in the Foo.m class file is:
+(void) openWebView {
dispatch_async(dispatch_get_main_queue(), ^{
UIWebView *webView = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, 16, 16)];
[webView setDelegate:self];
[webView setHidden:YES];
NSURL *url = [NSURL URLWithString:address];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
[webView loadRequest:urlRequest];
NSLog(#"Successful web open: ", url);
});
}
I do get a warning error message on the setDelegate line (it doesn't crash the app though) that reads:
Incompatible pointer types sending 'const Class' to parameter of type 'id:<UIWebViewDelegate>'
The problem is that while the NSLog does log the correct URL it is trying to open, the page actually never gets called (I can tell this because I have a PHP counter on that page that increments each time it is opened).
So my questions are:
Am I missing something in the .h file? I've added nothing there in
respect to this new WebView
I feel like I am missing the object that self references to. It was also made mention here in my precursor question to this one.
How can I check the response of the loadRequest
Sorry everyone, as you probably can figure out from my questions, Obj-C is a little new to me, but I am really struggling here and would appreciate the help! Thanks.

You are implementing a class method (indicated by the + sign). self in a class method refers to the class itself, not an instance. The delegate of a UIWebView (or anything really) has to be an object though.

Your openWebView method is a class method because of the + at the beginning. For this reason, you don't have an object. self in this case returns the class (hence the warning). Perhaps you want openWebView to be an instance method, so change the + to - and then self will point to your instantiated object.
To check if the loadRequest worked, you implement the UIWebViewDelegate delegate methods webViewDidStartLoad and webViewDidFinishLoad in your delegate (ie Foo.m) and see if they get called.

Related

Obj-C: EXC_BAD_ACCESS strange error with ARC

So I have a WebView inside a custom NSObject subclass called GoogleLinkFetcher and what I do is load a request from the webview and in webView:didFinishLoadForFrame: I call self to call a method on it. If I don't call that method everything works fine, if I do an EXC_BAD_ACCESS error points to that line. I read something about EXC_BAD_ACCESS regarding deallocating and memory allocations but I'm in an ARC environment so I would expect not to have problems with that... Here is the code:
-(void)searchLinks
{
NSLog(#"searching links at googlelinksearcher url: %#", googleUrl);
NSURLRequest *request = [NSURLRequest requestWithURL:googleUrl];
[[webView mainFrame] loadRequest:request];
[webView setFrameLoadDelegate:self];
}
-(void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame
{
if(frame == sender.mainFrame)
{
NSLog(#"main frame");
[self getLinks];
}
}
The error points right to [self getLinks].
I hope somebody could help, thanks in advance!
The problem might be that you start the loading process but don't hold a strong reference to your GoogleLinkFetcher instance and it is released before the web view finishes loading (actually right after it starts).
Put a breakpoint in webView:didFinishLoadForFrame: method and check if self is still a valid instance of GoogleLinkFetcher. Or NSLog self before you call getLinks.

How do you override the amount of redirects a webView can handle. Obj-C, Cocoa

This is really annoying me. I have a webView, and I am trying to get it too load drive.google.com. However, because of the amount of redirects on that site, the webView does nothing. I know that the code for loading a webView works, and that URL is correct, as I get the didFailWithProvisionalLoadWithError message. That is how I know that it is the redirect problem.
I have looked all over, but can find no way to alter the amount of allowed redirects. I know that it is possible, as Safari can handle it. There has to be some kind of delegate method to override. No code today, as all my searches (4 days worth of them) have lead me to nothing.
If anyone has an idea, let me know. FYI, this is Cocoa (WebView) not cocoa touch (UIWebView). Thanks.
That for which you have been searching is
– webView:decidePolicyForNavigationAction:request:frame:decisionListener:
which is part of the WebPolicyDelegate protocol.
Read the documentation for WebPolicyDelegate, particularly the discussion for this delegate method. The documentation for WebPolicyDecisionListener describes the messages you can send to the listener. You might identify a redirect inside this delegate method, and you could instruct the decision listener to use or ignore it.
EDIT:
I appreciate the 50 points, but if I didn't help you solve your problem, I hardly think I deserve them, and that was enough guilt to motivate me to sit down and try out your problem.
I built a tiny app, one that isn't document based, or uses ARC or garbage collection. I turned off Auto Layout in the MainMenu.xib file, and simply placed an instance of WebView inside it. I modified AppDelegate to include an outlet for the WebView instance.
I then created fleshed out the -applicationDidFinishLaunching: stub like this:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
NSString *urlString = #"http://drive.google.com";
NSURL *url = [NSURL URLWithString:urlString];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
[[[self webView] mainFrame] loadRequest:urlRequest];
}
and if I'm getting redirects, they don't seem to be affecting my ability to display the page.
Are we on the same page (no pun intended)?
EDIT 2:
Good news (or bad news, depending on your POV): Redirects were never the problem (though they did help to shed light on what was really going on).
When it comes to Google Drive, WebView isn't an approved browser. You can, however, fix that (N.B., below) by modifying the user agent string. Here's the revised code:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
NSString *urlString = #"http://drive.google.com";
NSURL *url = [NSURL URLWithString:urlString];
NSString *customUserAgent = [NSString stringWithFormat:#"%# Version/6.0.2 Safari/8536.26.17", [[self webView] userAgentForURL:url]];
[[self webView] setCustomUserAgent:customUserAgent];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
[[[self webView] mainFrame] loadRequest:urlRequest];
}
N.B.: The user interface appears to be fully functional, but even so, Google may change its means of determining what the browser is and break this scheme, so consider yourself warned. You might want to explore their SDK for possible alternate means of accessing Google Drive.
As always, good luck to you in your endeavors.
According to the WebView reference class in the Apple documentation, you have to set a delegate that conforms to the webframeloaddelegate protocol.
[webView setFrameLoadDelegate:object];
Then in object, you have to set this method:
- (void)webView:(WebView *)sender willPerformClientRedirectToURL:(NSURL *)URL delay:(NSTimeInterval)seconds fireDate:(NSDate *)date forFrame:(WebFrame *)frame

incompatible pointer to integer conversion sending viewcontroller * to parameter of type BOOL

I was trying to work out how to read a text file stored on a web server and display the contents in a text view. I have followed the documentation from Apple website NSURLConnection of how to establish a NSURLConnection and receiveData and display the received data.
I have created a button where I want to load the text view on button click. For that I wrote this method
- (void)loadWeb:(BOOL)animated
{
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://nowayweb.com/mytext.txt"] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:30.0];
NSURLConnection *myConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
if (myConnection) {
downloadedData = [[NSMutableData data] retain];
}
else{
NSLog(#"Error");
}
}
But I am getting a warning in my .m file which can be seen in the screenshot as shown here:
It works fine and I can view the text in the text view, but I am wondering where am I making the mistake. If somebody throws some light on this, would be helpful.
Or is there a better way to load the contents from web by button click. Any help is appreciated.
Thanks
self is a pointer to an object, not a BOOL value. You should do this:
[self loadWeb: YES];
Except your method does not seem to use the parameter anyway, so you might as well get rid of it.
[self loadWeb];
and
- (void)loadWeb
{
// all the stuff inside
}
The reason it worked for you is a) you weren't using the parameter, b) the compiler will automatically convert self into a BOOL by chopping off all but the least significant byte of the pointer. If you had been using the parameter, most of the time it would have been YES by chance and occasionally it would have been NO by chance.
ObjC's BOOL is not a real boolean type. it is a typedef for a signed char.
The method's signature is:
- (void)loadWeb:(BOOL)animated
the expression [self loadWeb:self]; doesn't make sense, and it's not a real bool conversion. the compiler warns you that you are converting a pointer to a signed char.
It should read either:
[self loadWeb:YES];
-or-
[self loadWeb:NO];
-or-
BOOL someBOOLVariableOrParameter = ...; // YES or NO
[self loadWeb:someBOOLVariableOrParameter];

IOS values passed to a view are lost or forgotten

This is my first app, and actually isn't even fully mine but rather involves re-working an existing app to add functionality.
It involves a JSON feed which I'm successfully reading in and then trying to pass the value of a URL to a view. Here's the code from my app delegate that is successfully fired once the feed is read in:
- (void)JSONFetch:(MYJSONFetch *)fetch gotTheCollection:(id)collection
{
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
self.testViewController.feedURL = [NSURL URLWithString:[collection objectForKey:#"Listings"]];
[JSONFetch release];
JSONFetch = nil;
}
Then in my testViewController I have this viewDidLoad method:
- (void)viewDidLoad {
[super viewDidLoad];
if(self.feedURL)
{
[self startDownload];
}
}
Eventhough, when I debug, the gotTheCollection method passes a value to the feedURL of the view, it then fails on the if(self feedURL) check within the view and thus the view never gets populated.
As I'm so new to this code I've no idea if the sequence is wrong, or maybe it's how I'm passing the variable.
I know the description is relatively vague but even on a basic level I don't know if this functionality works in objective C, it doesn't cause any errors though, just sits there not loading because it can't get the data.
UPDATE: Definition of FeedURL follows, in the H file:
NSURL *feedURL;
then
#property (nonatomic, retain) NSURL *feedURL;
then in the M file:
#synthesize feedURL;
Thanks for the help guys, I finally decided to just restart the entire upgrade as the project had become a mess of reworked code and I couldn't be sure what worked and what didn't. As a result there's no clear answer to this but I imagine Franks was probably the closest so I'll mark that as the answer.
The NSURL is being autoreleased, you will need to retain it yourself
Assign the NSURL to feedURL, like so
self.testViewController.feedURL = [[NSURL URLWithString:[collection objectForKey:#"Listings"]] retain];
This will also mean you will have to release it yourself.

How can I troubleshoot my custom URL scheme?

I set up a simple event handler as mentioned here, but it appears that the selector isn't called. I put the code in my AppDelegate class and wired up the delegate in IB. Tried putting in some NSLog()s and breakpoints in the selector I expect to be called, but none of it is hit. The URL scheme works inasmuch as it launches my app, but it doesn't do anything after that. Can anyone advise how to troubleshoot this? Thanks!
Well, I can't help but notice that you're -init method is mis-declared. If should have return type id and have a return self; at the end.
- (id)init
{
self = [super init];
if (self) {
[[NSAppleEventManager sharedAppleEventManager] setEventHandler:self andSelector:#selector(getUrl:withReplyEvent:) forEventClass:kInternetEventClass andEventID:kAEGetURL];
}
return self;
}
With those fixes, I was able to paste those two routines into a test AppController class and have it print out the URLs (with a custom scheme) that I typed into Safari. I'd put a breakpoint on that -init method and step through it to make absolutely sure that -setEventHandler: method is getting called.
The big question is: Where are you calling NSAppleEventManager's -setEventHandler:...? You need to call this before your app finishes launching if you want to catch a URL that started your app. If your app delegate is created in your MainMenu.nib, then either its -init or -awakeFromNib methods will work, but, for example, -applicationDidFinishLaunching: won't.
Also, make sure that the selector you provide to -setEventHandler: is exactly the same as your method name, paying particular attention to capitalization and the proper number of colons.
Obviously, if you posted your app delegate's relevant code, it would be quite helpful.
Thanks for the suggestions. I double-checked those things. I'm sure it's some newbie mistake, but I'd appreciate anyone looking at the code. (The URL bits are stored in info.plist.) Right now I'm just trying to confirm that it's working before I try to do anything with the URL.
- (void)init{
self = [super init];
if(self){
[[NSAppleEventManager sharedAppleEventManager] setEventHandler:self andSelector:#selector(getUrl:withReplyEvent:) forEventClass:kInternetEventClass andEventID:kAEGetURL];
}
}
- (void)getUrl:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent
{
NSString *url = [[event paramDescriptorForKeyword:keyDirectObject] stringValue];
NSLog(url);
// now you can create an NSURL and grab the necessary parts
}
Newbie mistake #2: Didn't set the class of my app delegate in IB. Fixing this and the init method as above got me going. Grrr...