iPhone - webViewDidFinishLoad not called - iphone

I have a simple View into IB that contains just a UIWebView and a UIButton.
The webView is retained, connected, not nil, the delegate property os also connected, the Controller is UIWebViewDelegate compliant and set in the .h.
in ViewDidLoad, I use [self.webView loadHTMLString:htmlContent baseURL:nil];
The content loads, but webViewDidFinishLoad is never triggered, neither didFailLoadWithError, neither webViewDidStartLoad.
How can I know when my content has finished loading, as it take a short time, but still a time to load (and I need to do things during that time on display, for an example not showing the button) ?
#interface MyController : UIViewController <UIWebViewDelegate> {
UIWebView* webView;
}
#property (nonatomic, retain) IBOutlet UIWebView* webView;
#end
#implementation MyController
#synthesize webView;
- (void)viewDidLoad
{
[super viewDidLoad];
constructing the htmlString
id a = self.webView.delegate; // for debug
[self.webView loadHTMLString:htmlContent baseURL:nil];
}
#end
EDIT :
I've deleted the whole XIB and built it from scrathc : no more problem. IB sucks sometimes.

You need to implement the UIWebViewDelegate protocol in your class and set the delegate property of self.webView = self. You will need to implement non-optional delegate methods to the class, plus the webViewDidFinishLoad, didFailLoadWithError and webViewDidStartLoad methods.

I've deleted the whole XIB and built it again from scratch : no more problem. IB sucks sometimes.

Just a sort of stab in the dark. As far as your code above is concerned, you still haven't set the responding object to the webView delegate, you have set a pointer to the webView delegate object but when the webView goes to respond to the delegate it will still be nil.
You should probably have: self.webView.delegate = a; but even then I don't know if that will work because I don't know what a is, is it the object that will respond to the delegate call backs?

You have to implement the UIWebViewDelegate protocol in your class and set self.webView.delegate=self;

Related

Message Passing with UIView as delegate

I have written a third party framework that displays a UIView on top of the existing view of the calling app, i.e., the app calls the framework/SDK and the SDK shows a UIView on top of the view that is currently on screen.
This is done by the use of delegates. The app sets the current view on screen as the delegate to the framework. The framework then uses this delegates and adds its own UIView as a subview using the code:
[[self delegate] addSubview:myVc.view];
where myVc is the ViewController in the framework.
Now I need to pass a method back to the calling app saying the view was shown on screen. Since, the delegate is a UIView, how do I pass a message to the calling class?
The reason why I have asked for a UIView delegate is because my UIView takes only a part of screen and I need the other part of the screen to show the remaining part of the app and be active. When I used ViewController as a delegate, it resulted in the other part of the screen being black instead of transparent.
So my question is how do I pass a message to the calling app, which calls the SDK and sets its view as a delegate. Thanks
You can post a notification that the caller listens for or you can accept a block as a parameter from the caller and execute that when the view is shown.
If I understood your question correctly, then you simply need to define protocol :
.h
#protocol YourFrameWorkViewDelegate <NSObject>
- (void)yourFrameWorkViewDidAppear;
#end
#interface YouFrameWorkView : UIView
#property (weak, nonatomic) id <YourFrameWorkViewDelegate> delegate;
#end
.m
#implementation YouFrameWorkView
- (void)didMoveToWindow
{
if ([self.delegate respondsToSelector:#selector(yourFrameWorkViewDidAppear)]) {
[self.delegate yourFrameWorkViewDidAppear];
}
}
#end
or you could call delegate from your VC like
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
if ([self.view.delegate respondsToSelector:#selector(yourFrameWorkViewDidAppear)]) {
[self.view.delegate yourFrameWorkViewDidAppear];
}
Of course any app that wants to use you frame work needs to implement that protocol. This would probably be rootVCs view would have to be subclass and implement your protocol. This is standard practice. Hope it helped.
Follow up after your comment:
Masure that view implements your protocol
.h
#interface ViewThatUsesYourFrameWork : UIView <YourFrameWorkViewDelegate>
#end
.m
#implementation ViewThatUsesYourFrameWork
- (void)yourFrameWorkViewDidAppear
{
}
#end
and also confirm that delegate is indeed set.
before you call respondsToSelector
if(!self.delegate)NSLog(#"Delegate is not set")

IBOutlet UITextView is nil after calling another class initWithNibName and back to the class using method

My problem is that in ProductNote class UIButton Action I did initWithNibName Notes Class to show the popOver with a UITableView in Notes Class. I am fetching data from sqlite and then load it to UITableView in tableViewDidSelectRowAtindexPath:. I got the selectedNote and creates object of ProductNote Class to call selectedNote instance method that only set IBOutlet's textview.text but its nil. Thats my problem, Below is the code please help me to knowing why i face this type of issue. I am using Xcode 4.3.3 and not using ARC. Manually I defined dealloc method on every ViewController
//**ProductNote.h Class****************************
#import <UIKit/UIKit.h>
#class Notes;
#interface ProductNote : UIViewController<UIPopoverControllerDelegate>
{
UIPopoverController *popOverController;
UITextView *txtmesssagenotes;
Notes *objNotes;
}
#property (retain, nonatomic) IBOutlet UITextView *txtmesssagenotes; //It is Connected to ProductNote.xib
#property (retain,nonatomic) UIPopoverController *popOverController;
#property (retain,nonatomic) Notes *objNotes;
-(IBAction)presentPopOver:(UIButton*)sender;
-(void)selectedNote:(NSString*)note;
#end
//ProductNote.m Class
#implementation ProductNote
#synthesize txtmesssagenotes,popOverController,objNotes;
-(IBAction)presentPopOver:(UIButton*)sender
{
self.objNotes=[[Notes alloc]initWithNibName:#"Notes"bundle:nil];
UIPopoverController *popOver=[[[UIPopoverController alloc]initWithContentViewController:objNotes]autorelease];
self.popOverController=popOver;
self.popOverController.delegate=self;
self.popOverController.popoverContentSize=objNotes.view.frame.size;
CGRect rect=[self.view convertRect:objNotes.view.frame fromView:self.view];
rect.origin.y+=110;
rect.origin.x+=23;
[self.popOverController presentPopoverFromRect:rect inView:self.view permittedArrowDirections:0 animated:YES];
//Then I get popOver with tableview
}
-(void)selectedNote:(NSString*)note
{
self.txtmesssagenotes.text=note;
//Here I am getting txtmesssagenotes=0X0 or nil. Using self or without self Please tell me the reason.
}
- (void)dealloc {
[txtmesssagenotes release];
[popOverController release];
[objNotes release];
[super dealloc];
}
#end
#interface Notes : UITableViewController
{
NSMutableArray *arrNotes;
NSString *selectedNote;
UITableView *tblNotes;
}
#property(nonatomic,retain)NSMutableArray *arrNotes;
#property(nonatomic,retain)NSString *selectedNote;
#property(nonatomic,retain)IBOutlet UITableView *tblNotes;
#end
//Actually I skip the other methods that makes larger program to read . other methods only used to fetch data from sqlite and fill up the arrNotes that is used to fill all rows in the tableview.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
self.selectedNote=[self.arrNotes objectAtIndex:indexPath.row];
//Here self.arrNotes valid object and contains the data, and assigns NSString object to self.selectedNote
ProductNote *productNote=[[ProductNote alloc]init];
[productNote selectedNote:self.selectedNote]; //after calling selectedNote i goto to selectedNote implementation or definition above.
[productNote release];
}
-(void)dealloc
{
[arrNotes release];
[selectedNote release];
[tblNotes release];
[super dealloc];
}
It is because just as you stated that txtmesssagenotes was created using IB. And you never presented your ProductNote UIViewController instant productNote. So the txtmesssagenotes was never allocated and initialized properly.
Are you calling selectedNote: before your view has loaded?
Just because you created a view controller with a xib doesn't mean that it loads all your subviews immediately.
The xib is parsed and all your views are created the first time that the view controller's view property is asked for - this is usually just before it appears for the first time.
Until then, all the IBOutlet connections will be nil.
You need to store the text for your note as an NSString property of you view controller. Then, inside either viewDidLoad you need to call self.txtmesssagenotes.text=self.note; - viewDidLoad is automatically called just after your view is loaded so you are guaranteed to have all your IBOutlets set by then.
You shouldn't rely on your view objects to store the state of your app (in this case, the text of the note). If a low memory warning is received while your view controller isn't visible then all your view objects will be deleted - they will only be recreated when your view controller becomes visible again - if you are storing your note string inside a UITextView then it might no be there the next time you ask for it :) You should always store data in a property of your view controller (or somewhere else you control) and create your views using it.

Common views in viewControllers - Code re-usability

I have few common views in most of my viewControllers. What I noticed is that I can reuse single code for all viewControllers which is absolutely wise. For this I decided to create a class Utils which has static methods like
+(void)createCommonViews:(float)yAxis:(NSString*)text;
In my case common views are three labels and two images.
Problem : I am not able to add these views from Utils. I am wondering how can I send self as a parameter so that I may add the views from Utils. It may be wrong to add views outside the viewController. In that case what can be the solution? Taking all these views in a UIView, setting return type of Utils method as UIView and then adding UIView to viewController (after calling method from viewController) might solve my problem. But what I am looking for is some other solution.
+(void) createCommonViews:(float)yAxis withText:(NSString*) text toTarget:(UIViewController*) target
{
//create views
[target addSuview:view];
}
But I think returning a Uiview and then adding it in the UIViewController afterwards, is a far better solution.
The method you're attempting is to have your view object as a singleton. This is uncommon at best, at worst a crash waiting to happen. Better design is for each of your view controller classes to have its own instance of your custom view, like so:
#interface MyCommonView : UIView
// ...
#end
#interface MyViewController_A : UIViewController {
MyCommonView *commonView;
}
#property (strong, nonatomic) IBOutlet MyCommonView *commonView;
#end
// Meanwhile somewhere else...
#interface MyViewController_B : UIViewController {
MyCommonView *commonView;
}
#property (strong, nonatomic) IBOutlet MyCommonView *commonView;
#end
Create a viewController that acts as a parent view for all your common stuff, call it CommonViewController then implement this in all the viewcontrollers you want it to appear
-(void) viewDidLoad
{
[self.view addSubView:[[CommonViewController alloc] initWithRect:..];
}
Or alternatively using xib files

How to hide buttons in iOS when webview has finished loading

I am not sure why is this set of codes not working to hide iphone buttons as soon as the webview has loaded?
GoogleMap_BetaViewController.h
#interface GoogleMap_BetaViewController : UIViewController <UIWebViewDelegate> {
IBOutlet UIWebView *webView;
UIButton *retrieveReminder;
}
#property (nonatomic, retain) UIWebView *webView;
#property (nonatomic, retain) IBOutlet UIButton *retrieveReminder;
- (IBAction) RetrieveReminder:(id)sender;
#end
testController.m
#implementation GoogleMap_BetaViewController
#synthesize webView,retrieveReminder;
-(void)webViewDidFinishLoad:(UIWebView *)webView
{
[retrieveReminder setHidden:YES];
}
Jonathan, have you connect UIWebViewDelegate properly ? Have you check that WebViwDidFinishLoad get called everytime.
As commented in response above, make sure that you are going from Files Owner to the Button and not the Button to Files Owner (which will show you IBActions). Also, once you get the right variable hooked up, make sure you are using self.retrieveReminder so that you are accessing the variable through the getters/setters which is what the IBOutlet is hooked up to.
Based on our discussion in the comments, I guess you are linking it wrongly. Take a look at this video for a visual tutorial on linking IBOutlets. http://www.youtube.com/watch?v=-EpTGOcC0Jw
You need to set the webFiview delegate to self and then use its delegate method:
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
button.hidden = YES;
}
Have you tried to set the delegate of the webview in the IB? That is a must, as you are using its delegate method.

Objects in nib file not associating with IBOutlet objects in code

OK I'm pulling my hair on on this, it makes no sense so it must either be a bug, or some extremely stupid mistake I'm making.
Here's the situation: I have a UIViewController with a xib file. It has a UIView hooked up to the view property, a UIImageView hooked up to a property called imageView, and a UISegmentedControl hooked up to segmentControl.
Yet in my code, I'm unable to assign an image to the image view. When I NSLog the object, I'm getting the address of 0x0, so it's not associating at all. I have the bindings set up in Interface builder, I've restarted XCode and clean and built the project. Nothing is working and I've wasted a stupid amount of time trying to figure this out at this point. I've also NSLoged the segmentControl object and am getting 0x0 as well. So nothing from the XIB is hooking up with the code, but the XIB itself is loading because the objects are displayed on the screen.
Does anyone have any ideas offhand of what I could be missing? This is such a simple thing, it's incredibly frustrating that it's refusing to work all of a sudden.
Here's the code below, in this case I'm accessing the objects in the setter for projectId, but I also tried accessing the imageView from another class and it didn't work either (and yes I had a #property declaration and synthesize for imageView when I tried).
DiagramViewController.h:
#import <UIKit/UIKit.h>
#interface DiagramViewController : UIViewController
{
NSUInteger projectId;
IBOutlet UIImageView *imageView;
IBOutlet UISegmentedControl *segmentControl;
}
#property NSUInteger projectId;
#end
DiagramViewController.m:
#import "DiagramViewController.h"
#implementation DiagramViewController
#synthesize projectId;
-(void)setProjectId:(NSUInteger)projId
{
NSLog(#"imageView: %#", imageView);
NSLog(#"segmentControl: %#", segmentControl);
projectId = projId;
NSString *filePath = [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:#"%i_schem", projectId] ofType:#"png" inDirectory:#"project-details/images/diagrams"];
NSData *imageData = [NSData dataWithContentsOfFile:filePath];
imageView.image = [UIImage imageWithData:imageData];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Overriden to allow any orientation.
return YES;
}
- (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;
}
- (void)dealloc {
[super dealloc];
}
#end
And here's an image of the Interface Builder hookups:
You need to make sure you're doing this in the -viewDidLoad method, otherwise the nib file hasn't actually unarchived the objects and thus they will be set to nil. In particular, you can't access items from the nib within an -init method.
Without seeing your code however, it's hard to say if this is the case for you.
EDIT: Ok, thanks for posting code. When does -setProjectId: get invoked? Are you sure the nib has finished loading at this point? You have no viewDidLoad method in your view controller so it appears you never check for this at any time.
See: http://developer.apple.com/library/ios/#documentation/uikit/reference/UIViewController_Class/Reference/Reference.html
viewDidLoad
Called after the controller’s view is loaded into memory.
(void)viewDidLoad
Discussion
This method is called after the view controller has loaded its associated views into memory. This method is called regardless of whether the views were stored in a nib file or created programmatically in the loadView method. This method is most commonly used to perform additional initialization steps on views that are loaded from nib files.
Sounds like something went wrong when you wired up the IBOutlets.
In IB right click on the UISegmentedControl and post a screenshot so that we can see what you have there. If you see anything 'yellow' then you may have found your problem.