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.
Related
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.
I have a tableviewapplication, wich when the user select one view it needs to parse some XML to display information.But sometimes the XML is not finished downloading and the user can press the button to select the other view,generating a crash.I think i need to cancel the connection or something to dont cause any conflitct with the new connection,but i dont know exactly how,it suppose to be in ViewWillDisappear correct?
Heres how i start the connection on ViewDidAppear:
NSMutableURLRequest * req = [[NSMutableURLRequest alloc]initWithURL:[NSURL URLWithString:#"http://Adress"]
cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:20.0f];
conn = [NSURLConnection connectionWithRequest:req delegate:self];
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
if(conn)
{
receivedData = [[NSMutableData alloc]init];
[DSBezelActivityView newActivityViewForView:self.view withLabel:#"Loading..."];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
if(conn) [conn cancel];
}
You can call NSURLConnection's cancel method and it will prevent your connections delegate from being called with any more data. You could do this in viewWillDisappear if that's when it makes sense given how your app works.
Absolutely you can cancel NSURLConnection.
But you should be careful in cancelling it too.
If you decide to cancel it in viewWillDisappear,
then
You should not do,
autorelease
and also you should not,
release it anywhere.
Here below the brief explaination:
Do cancel your NSURLConnection delegate in viewWillDisappear
[nsurlconnection cancel];
and also you should release it here not anywhere,
[nsurlconnection release];
If you release the connection in somewhere like after your xml response received then,
It will call the viewWillDisappear method anyway,
here you are cancelling it , then it will lead your app to crash.
"deallocated objects will not be cancelled"
.
And also another situation will occurs while cancelling,
If user comes and immediately navigates other view first time, your nsurlconnection will be cancelled in viewWillDisappear method.
Again the user comes to the view and escapes immediately before your nsurlconnection initialized or allocated, also your app will be crashed because,
"deallocated objects will not be cancelled".
So, check your connection != nil before you cancel it
and also don't forgot to do
nsurlconnection = nil;
in the same time.
So that you can avoid the immediate calls [nsurlconnection cancel] crashes.
SO Finally , in your viewWillDisappear method you have to do is,
Need to check nsurlconnection != nil
Need to cancel it
Need to allocate null to your nsurlconnection
Need to release it in the same method.
Sample code will be like the following,
- (void) viewWillDisappear:(BOOL)animated
{
if (nsurlconnection != nil)
{
[nsurlconnection cancel];
[nsurlconnection release];
nsurlconnection = nil;
}
}
Hope it's helpful... Happy coding ...
i ve got a view controller containing four buttons..clicking on each button takes you to new view controller containing web view.everything works fine except when the button is clicked ..it takes you to the web view if i m to navigate back the app quits...in debug mode i ve got dis exception EXC_BAD_ACCESS...below is the code...
-(IBAction)Button1
{
WebViewFaceBook *newEnterNameController4 = [[WebViewFaceBookalloc]initWithNibName:#"WebViewFaceBook" bundle:[NSBundle mainBundle]];
[[self navigationController] pushViewController:newEnterNameController4 animated:YES];
[newEnterNameController4 release];
}
- (void)viewDidLoad {
[super viewDidLoad];
//[UIApplication sharedApplication].networkActivityIndicatorVisible=YES;
urlAddress2 = #"http://www.facebook.com/livingwaterscf";
url2 = [NSURL URLWithString:urlAddress2];
requestObj2 = [NSURLRequest requestWithURL:url2];
[webViewFaceBook loadRequest:requestObj2];
}
Are you releasing the webView in dealloc? Are you using any delegate methods of the webview?
Checkout NSZombieEnabled for your active executable to see some more info on the bad access.
These assignment won't work without declaration of ivars/properties:
urlAddress2 = #"http://www.facebook.com/livingwaterscf";
url2 = [NSURL URLWithString:urlAddress2];
requestObj2 = [NSURLRequest requestWithURL:url2];
Can you please show us the definition of those in your header file?
Edit
Change your declaration of urlAddress2, url2 and requestObj2 to retained properties and set them with self.urlAddress2 = xxx, then you can release them in dealloc. The class methods as well as the #"http://www.facebook.com/livingwaterscf" return autoreleased instances. If you want to own them you have to retain those and only then you should release them.
If you don't want to own them, and in this case I don't think you need those anywhere else then starting the load of the webview's content, just don't release them in dealloc!
You try to access something that has been deallocated.
Enable NSZombie to find out where.
You may be release url2 in dealloc method in your WebViewFaceBook controller.
requestObj2, url2, urlAddress2 already autoreleased. You mustn't release them in dealloc
I have a program which works normally. Then I downloaded some code from http://github.com/matej/MBProgressHUD to show a progress meter when doing something.
This is the code that makes the progress meter pop up.
[HUD showWhileExecuting:#selector(myTask) onTarget:self withObject:nil animated:YES];
This will show a progress meter while the method myTask is running.
This is the code for the showWhileExecuting method.
- (void)showWhileExecuting:(SEL)method onTarget:(id)target withObject:(id)object animated:(BOOL)animated {
methodForExecution = method;
targetForExecution = [target retain];
objectForExecution = [object retain];
// Launch execution in new thread
taskInProgress = YES;
[NSThread detachNewThreadSelector:#selector(launchExecution) toTarget:self withObject:nil];
// Show HUD view
[self show:animated];
}
If I use this to call the function myTask then one of my class properties will change from an NSMutableString to an NSData object somewhere, and then later on it will change to an NSString. I don't see anywhere in the code that causes this to change, so it's probably some kind of bug. Is memory getting corrupted? What's causing this to happen?
Most likely it's a memory (retain/release issue). If you don't properly retain an object, it may get released out from under you. At that point, the memory will be reclaimed by the OS, which may decide to store something else there. Try turning on NSZombies, and double checking your retain/release/autoreleases.
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...