Crash when Adding a WebView to a Multiview Tab Bar App - uiviewcontroller

I am new to this and working thru a "teach yourself book". I have two questions. How to trouble-shoot this in the future and how to get the darn thing to work now.
I have a simple three Tab Bar app that points to three UIViewController. The three views work fine until I add a Webview to one of the XIBs. As soon as I bring up the view with the WebView included in the simulator, I am kicked out of the App.
The Debugger console says"'NSUnknownKeyException', reason: '[ setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key bannerView.'" I don't know what that means.
.h file code....
#interface ConvNavController : UIViewController {
IBOutlet UIWebView *bannerView;
}
-(IBAction)loadbannerView:(id)sender;
#property (nonatomic, retain)IBOutlet UIWebView *bannerView;
=========
.m file code
-(IBAction)loadbannerView:(id)sender{
NSURL *bannerURL;
NSString *bannerURLString;
bannerURLString=[[NSString alloc] initWithString:#"http://www.tak2000.com/banner_test.html"];
bannerURL =[[NSURL alloc] initWithString:bannerURLString];
[bannerView loadRequest:[NSURLRequest requestWithURL:bannerURL]];
[bannerURL release];
[bannerURLString release];
}
I used a simple button connected to loadbannerView.
Webview code worked great in a simple one view example. Why is it dying when I use it in multi UIViewController app? BTW: I used the "Windows Based App" template as a starting point. I also ensured the Class Identity was UIWebView.
Thanks in advance...

bannerView is a property, so it should be
[self.bannerView loadRequest ....]
and make sure in interface builder that you've connected your UIWebView to the bannerView outlet.

Related

MFMessageComposeViewController issues in iOS8

I've run into a strange bug with MFMessageComposeViewController in iOS8, that is only reproducible within my own app. It's affecting the app right now in the App Store, built with the iOS7 SDK running on iOS8, as well with the iOS8 SDK in my own test devices (iPhone and iPad)
The issue is that when I bring up the MFMessageComposeViewController, it shows me the controller without a text field or a Send button anymore. I haven't changed my code between iOS7 and iOS8, so not sure why this is happening. The code itself is very simple:
MFMessageComposeViewController *picker = [[MFMessageComposeViewController alloc] init];
picker.messageComposeDelegate = self;
[picker setRecipients: #[#"5551112222"]];
[picker setBody: #"Test"];
[self presentViewController:picker animated:YES completion: ^{
NSLog(#"MFMessageComposeViewController completion handler");
}];
This is what it looks like:
Any ideas for what I can try for a work-around? I've tried setting the textField and recipients in the completion handler; tried calling becomeFirstResponder on the top-most view controller; no luck. Again, this was/is working perfectly fine in iOS7.
EDIT:
So I found Apple's own sample code for MFMessageComposeViewController from this link: https://developer.apple.com/library/ios/samplecode/MessageComposer/Listings/MessageComposerViewController_m.html
When I build and run this app, the MFMessageComposeViewController shows up perfectly, and pre-filling the phone number and text fields works as well. But when I copy their files into my app, make their storyboard my main storyboard, press the "Compose SMS" button and I see the same exact problem!
What is going on here? Very confused. Could it be some configuration in my own app that is preventing the message composer from displaying correctly?
Finally, after tearing down most of my app, I was able to figure out the issue. Turns out, I was overriding a UIViewController system method in a category (instead of sub-classing):
#implementation UIViewController (UIViewController_Additions)
-(BOOL)canBecomeFirstResponder {
return YES;
}
This has been working fine till iOS7, but something must have changed internally in iOS8 and `MFMessageComposeViewController. A case of the "4-year-old-hack coming to bite you in the ass"
This practice is discouraged by Apple as well, according to this link (though I couldn't find the original Apple source): https://stackoverflow.com/a/14259595/145552

How to setup a UIBarButtonItem to trigger an action in ios

I'm trying to work out how I can get my UIBarButtonItem named "home" to return back to my first initial ViewController.
I have implemented my button within the viewDidLoad of my ViewControllerSecond:
#property (nonatomic, weak) UIBarButtonItem *homeProperty;
// Create a home button
UIBarButtonItem *homeButton = [[UIBarButtonItem alloc] initWithTitle:#"Home" style:UIBarButtonItemStylePlain target:self action:#selector(homeProperty)];
[self.navigationItem setLeftBarButtonItem:homeButton animated:NO];
Do I need to create an IBAction method for this? Also, is the UIBarButtonItem implemented in the correct method viewDidLoad
So to summarise I need to be able to go back to the ViewController from the ViewControllerSecond but I can't figure out how to do this.
Many thanks
How are you adding the second view controller to the first? Are you calling pushViewController or presentModalViewController? If you're using a UINavigationController, calling pushViewController should automatically create the back button for you on the navigation bar. Create a new project in XCode using the Master-Detail Application too see an example of how UINavigationController should work.

Passing data between two views with Xcode 4.6

I am studying Object-C and I am writing a test app to learn.
This is an easy app, where in the first View i press a button, go in the second View (I used a curl animation)fill a text field and then press a button, pass the content of the field in the first view.
So I created the 2 Views, placed a button and a Label in the first View and linked the button from the first View to the second View using the right mouse click and drag a line with action Modal.
In the second View, I wrote the following code:
ViewController2.h
#property (weak, nonatomic) IBOutlet UITextField *firstTextField;
#property (strong, nonatomic) NSString *stringFromVC2;
- (IBAction)passTextToVC2Button:(id)sender;
ViewController2.m
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.firstTextField.delegate = self;
}
- (IBAction)passTextToVC2Button:(id)sender {
ViewController *VC2 = [self.storyboard instantiateViewControllerWithIdentifier:#"wb_ViewController"];
VC2.stringFromTextField1 = self.firstTextField.text;
[self presentViewController:VC2 animated:YES completion:nil];
}
The app works, but when I press the button from ViewController2, and go back to ViewController, it doesn't animate the Curl animation, just it appears from the bottom of the page a new window (the ViewController) under the ViewController opened with the Curl animation.
I also tried to use:
[self dismissViewControllerAnimated:YES completion:nil];
instead of:
[self presentViewController:VC2 animated:YES completion:nil];
in this case, it closes the second view but the Label in the first View isn't display with the text I inserted in the second View.
As I told you, I am studying so I am a beginner, please be patient.
The way to do this is to define a delegate protocol that your first view controller conforms to, and your second view controller can send a message to to pass back the value.
I've had to answer this question a few times so I created an very simple example project to show exactly what I mean. Download it and see how to pass data back down the controller stack.
Update
I've changed the sample to an new project for iOS6 with ARC and Storyboards.

UITabbarController dismiss modal UINavigationController

I got a very interesting problem here. My iPhone app has an UITabbarController as rootViewController in the AppDelegate.
If the app is opened the first time, it must be configured basically. For this purpose I create an UINavigationController and tell the tabbarController to present it modally:
firstRun = [[firstRunViewController alloc] init];
navCtrl = [[UINavigationController alloc] initWithRootViewController:firstRun];
[[self tabBarController] presentModalViewController:navCtrl animated:NO];
When the configuration is done, I'd like to get rid of the firstRunViewController. I'm using this technique very often, using -dismissModalViewControllerAnimated:.
But in this constellation this doesn't work. It doesn't matter from what controller I'm calling the dismiss.
I tried it via the tabbarController, the rootViewController, the currently active viewController, of cause self and several other controllers.
EVERY TIME I call -dismissModalViewControllerAnimated: I get this exception:
'UIViewControllerHierarchyInconsistency', reason: 'presentedViewController for controller is itself on dismiss for: <UINavigationController:…
Can anybody help? Thanks in advance, with kind regards, Julian
EDIT
In my AppDelegate I'm using a UITabbarController as rootViewController for the main window:
self.window.rootViewController = self.tabBarController;
[self.window makeKeyAndVisible];
Then I'm creating an UINavigationController and tell the UITabbarController to present the modalViewController:
UINavigationController *navCtrl = [[UINavigationController alloc] initWithRootViewController:firstRun];
[[self tabBarController] presentModalViewController:navCtrl animated:NO];
When I now call -dismissModalViewControllerAnimated: on the firstViewController I'm getting the error from above.
In my opinion you are abusing UITabbarController. This class, even though a subclass of UIViewController, does not really use much of the UIViewController infrastructure.
What you want is a slight extension of what you have now. Create a new UIViewController subclass in your appDelegate, and add it as the single object to an array, and set the tabBar's viewControllers to this array. Set your subclass' hidesBottomBarWhenPushed to YES so it hides the tab bar when it becomes visible.
Now your app will launch and your UIViewController subclass will become the frontmost view. You can make this view the one you wanted to present modally, or you can present that view from your subclass using some kind of animation. Oh, and if you use the launch view as the background image for your subclass, you can really make this a smooth transition - I do this now.
When your modal view is done, then you can instantiate whatever views you want to then display, and set the UITabBarController to use those views with tabBarController.viewControllers (or the animated version). Poof, you UIViewController will get replaces (and under ARC just disappear).
I don't have a chance to test my hypothesis, but I suspect that this issue could depend on the fact that you are presenting the modal view too early, whereby too early means before the main window has had the chance to set up the tab bar controller. So, I would suggest this changes:
create a method to instantiate your navigation controller:
- (void)initializeAndPresentNavigationController {
UINavigationController *navCtrl = [[UINavigationController alloc] initWithRootViewController:firstRun];
[[self tabBarController] presentModalViewController:navCtrl animated:NO];
}
instead of presenting the navigation controller directly from appDidFinishLaunching, call the above method asynchronously:
[self performSelector:#selector(initializeAndPresentNavigationController) withObject:nil afterDelay:0.0];
Here the trick of calling the method as I do in 2 is that the call to initializeAndPresentNavigationController will be simply pushed on the main loop, and executed after your app has had the possibility to build its initial UI.
Hope it works for you.
I finally found the answer myself!
I just couldn't see the wood for the trees! I'm quite happy right now! :)
I did really silly things: In the last viewController of the setup viewControllers I had to change the tabars viewControllers corresponding to whether the user is administrator or not. So I did:
appDelegate.tabBarController.viewControllers = [NSArray arrayWithObjects:appDelegate.readState,
appDelegate.navCtrl,
appDelegate.settings, nil];
You can see that I was adding the AppDelegate's "navCtrl" to the tabbar's viewControllers. So I was trying to dismiss a viewController I just added to the parentViewControllers (UITabbarController) sub-controllers.
Dismissing something I want to present just in the same moment is NOT advisable! :))

<select> tag doesn't work in UIWebView on iOS4

I'm new to iOS programming, so please allow me to ask stupid questions if it is :)
I have a program, using UIWebView to load HTML page and display to the end users.
The page is quite simple,
<select>
<option>A</option>
<option>B</option>
<option>C</option>
<option>D</option>
</select>
WebView controller init:
WebViewController *webVC = [[WebViewController alloc] initWithNibName:#"WebViewController" bundle:nil];
Load the HTML page in this way:
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://*****/app/"]]];
When program started, the end user will see a drop down menu, if click the menu, end user will see a list of options, then choose one of then.
The problem is, it works fine in iOS3.2, but after I upgrade the SDK to iOS4, it doesn't work, nothing happen when click the drop down menu.
Can anyone help me?
Is there anything wrong with my UIWebView?
Thanks a lot.
Load the HTML page in this way:
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://*****/app/"]]];
I ran into the same Problem.
In my case it was a Category on UIView I recently defined to dismiss the keyboard. Every time the user touches a view I call endEditing:YES on the super view and resign the first responder state of the superview and all of its subviews.
This worked fine until I the first time I had a html select/option in a UIWebView. I was not able to select the entries. I was a litte confused because with a UIPickerView in my native code it wasn't a problem either.
The Problem was, that I was touching a UIPickerTableViewWrapperCell which is a UITableViewCell and this is -- a UIView! By resigning the first responder of the UIPickerTableViewWrapperCell functionality of the PickerView was broken.
The solution was to get the superview of the view and check the classes and make exceptions:
#import "UIView+KeyboardDismisser.h"
#implementation UIView (KeyboardDismisser)
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
if(([[self superview] superclass] == [UITableViewCell class]) ||([[self superview] superclass] == [UITableView class]) )
{
[super touchesBegan:touches withEvent:event];
}
else
{
[[self superview] endEditing:YES];
}
}
#end
So watch out for such global hooks on central elements like UIView and make exceptions.