I am working on an IOS app and have been stumped by this problem for about a week now and cannot find a solution. Any help you can offer would be greatly appreciated. Here's my set-up:
I have a tab bar controller.
I have a TableViewController which has a navigation bar with a navigation item "Add".
After you press the "Add" selector I am modally presenting another viewController that has a picker on it.
I am using Core Data.
When the second view controller is modally presented it comes up with a black screen with a navigation bar. If I access the second view controller from an unrelated screen modally it comes up fine without the navigation bar.
No error message is logged, not even that the object wasn't saved when you press the "save" on the navigation bar. However, pressing "save" will bring you back to the TableViewController and it looks like the entity was added.
Here is the code in my TableViewController:
- (void)add:(id)sender {
SecondViewController *addController = [[SecondViewController alloc] init];
addController.delegate = self;
Entity *newEntity = [NSEntityDescription insertNewObjectForEntityForName:#"Entity" inManagedObjectContext:self.managedObjectContext];
addController.entity = newEntity;
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:addController];
[self.navigationController presentModalViewController:navController animated:YES];
}
- (void)secondViewController:(SecondViewController *)secondViewController didAddEntity:(Entity *)entity {
if (entity) {
[self showEntity:entity animated:NO];
}
[self dismissModalViewControllerAnimated:YES];
}
- (void)showEntity:(Entity *)entity animated:(BOOL)animated {
EntityDetailTableViewController *detailViewController = [[EntityDetailTableViewController alloc] initWithStyle:UITableViewStyleGrouped];
detailViewController.entity = entity;
[self.navigationController pushViewController:detailViewController animated:animated];
}
Here is the code in my second View Controller:
- (void) save {
entity.attribute = attributeTextField.text;
NSError *error = nil;
if (![entity.managedObjectContext save:&error])
{
NSLog(#"Problem saving attribute: %#", [error localizedDescription]);
}
NSLog(#"saveAttribute");
[self.delegate secondViewController:self didAddEntity:entity];
}
Any suggestions on where to go from here would be really helpful.
After much frustration I found the answer. If you are using storyboard you cannot navigate to the next view controller by the standard code. I put the prepareForSegue statement in my TableViewController.m file and then hooked up the connection on storyboard and identified the segue.
Now, when you press the Add button it segues to the new view controller screen and it's not black.
Here's a link to a useful tutorial
My guess is the way you are initializing is not right:
SecondViewController *addController = [[SecondViewController alloc] init];
should be initWithNIB:
Related
I'm reading the Big Nerd Ranch book and I'm at the 10th chapter about the navigation controller.
In the main controller, there is a TableView ( https://github.com/bignerdranch/iOS3eSolutions/blob/master/11.%20Homepwner/Homepwner/Homepwner/ItemsViewController.m ) where there are two methods that interact with the detail view :
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[[self tableView] reloadData];
}
- (void)tableView:(UITableView *)aTableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
DetailViewController *detailViewController = [[DetailViewController alloc] init];
NSArray *items = [[BNRItemStore sharedStore] allItems];
BNRItem *selectedItem = [items objectAtIndex:[indexPath row]];
// Give detail view controller a pointer to the item object in row
[detailViewController setItem:selectedItem];
// Push it onto the top of the navigation controller's stack
[[self navigationController] pushViewController:detailViewController
animated:YES];
}
In the detail view controller (https://github.com/bignerdranch/iOS3eSolutions/blob/master/11.%20Homepwner/Homepwner/Homepwner/DetailViewController.m), there is a method that "saves" the BNRItem being changed :
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
// Clear first responder
[[self view] endEditing:YES];
// "Save" changes to item
[item setItemName:[nameField text]];
[item setSerialNumber:[serialNumberField text]];
[item setValueInDollars:[[valueField text] intValue]];
}
The code works well :
I understand how the main controller set the object to edit but I don't understand how the main view controller knows that the BNRItem has been changed and then set it back to the tableview ?
I was excepting the author to write a setter in the main controller (ItemsViewController.m ) that could be called by the detail view controller (DetailViewController.m) giving the new BNRItem.
But this part works "automatically".
Thank you.
As you are pointing to the same memory chunk in both controllers, changed made in the DetailViewController are obviously reported in ItemsViewController.m.
I am currently using the new iOS 5 Storyboard approach to creating my Tabbed Application with Monotouch. I have developed two of my tab views in Xcode with Storyboard and linked them appropriately to the Tab Bar Controller. I also want to develop (in Xcode) a third tab view that would be shared among two additional tabs. I want to reuse the same layout, but display different data depending on which tab is selected (think something like a "Popular" and a "Recent" that would have the same layout but different data).
To do this, I figured I could add the tab manually twice after the Storyboard-driven tabs are added. How do I do this with the Storyboard approach? I'm not sure where in the code to do this since the loading of the Storyboard seems pretty transparent (i.e. no code in AppDelegate that I see). Or, is there another (easier/better) way to share a view between two tabs using the Storyboard approach?
I don't know Monotouch, but here's how I did it in Objective-c. I didn't find anything about this topic, so if something is wrong, people please comment :) By the way, I'm using ARC, so I don't manually manage memory! What I needed to achieve was like you, having a tab bar, loading the same viewController, but loading different data for each tab.
AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
UITabBarController *root = (UITabBarController*)self.window.rootViewController;
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle: nil];
TeamViewController *home = [[mainStoryboard instantiateViewControllerWithIdentifier:#"Team"] initHome];
TeamViewController *visitor = [[mainStoryboard instantiateViewControllerWithIdentifier:#"Team"] initVisitor];
[root setViewControllers:[NSArray arrayWithObjects:home, visitor, nil] animated:NO];
UITabBar *tabs = root.tabBar;
UITabBarItem *homeTab = [tabs.items objectAtIndex:0];
UITabBarItem *visitorTab = [tabs.items objectAtIndex:1];
homeTab.title = #"Home team";
visitorTab.title = #"Visitor team";
return YES;
}
You can see I call initHome and initVisitor when I load my two TeamViewController, here is the code about it.
TeamViewController.h
#interface TeamViewController : UIViewController
{
enum
{
HOME,
VISITOR
};
int team;
}
TeamViewController.m
- (id)initHome
{
team = HOME;
return self;
}
- (id)initVisitor
{
team = VISITOR;
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
if(team == HOME)
{
label.text = #"home data";
}
else if(team == VISITOR)
{
label.text = #"visitor data";
}
}
I don't know how well you can translate that to your project, but I hope you get the big picture of it :)
If you need to read a bit about how to access the first view controller using the storyboard: http://developer.apple.com/library/ios/#releasenotes/Miscellaneous/RN-AdoptingStoryboards/_index.html#//apple_ref/doc/uid/TP40011297
There is a section called "Accessing the First View Controller"
I have an app which adds a webview as a subview of the main UIViewController. I want to intercept the links clicked in this webview and open them in a new UIViewController (as modal view or navigationController).
For this new UIViewController, i am using https://github.com/samvermette/SVWebViewController which is an inline browser class and works pretty well.
I am able to intercept clicks from that webview just fine in webView:shouldStartLoadWithRequest:navigationType. But my problem is that it is not able to open the new UIViewController (SVWebViewController). Following is the code to intercept clicks in the webView and open it :
- (BOOL) webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)inRequest navigationType:(UIWebViewNavigationType)inType {
if(inType == UIWebViewNavigationTypeLinkClicked) {
NSURL *url = [inRequest URL];
NSString *fname = [url absoluteString];
SVWebViewController *webViewController = [[SVWebViewController alloc] initWithAddress:fname];
[self presentModalViewController:webViewController animated:YES];
[webViewController release];
return NO;
}
return YES;
}
There is no issue in SVWebViewController, it works fine when i call it from the main UIView but not when i use it to open clicks from the webView.
Thanks for your help!!
I followed this tutorial http://bytedissident.theconspiracy5.com/2010/11/24/uiwebview-tutorial/ and when I run the simulation in Xcode, all that is displayed is a blank white screen. I'm wondering what could be wrong. Is there some sort of code connection to the internet that i'm missing? I really don't know what could be wrong.
WebPageViewController.m
#import "WebPageViewController.h"
#implementation WebPageViewController
#synthesize wView;
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
//a URL string
NSString *urlAddress = #"http://www.nd.edu";
//create URL object from string
NSURL *url = [NSURL URLWithString:urlAddress];
//URL Request Object created from your URL object
NSURLRequest *requestObj = [NSURLRequest requestWithURL:url];
//Load the request in the UIWebView
[wView loadRequest:requestObj];
//scale page to the device - can also be done in IB if preferred.
//wView.scalesPageToFit = YES;
}
Did you connect the .xib to the WebPageViewController class you created? You can check by selecting the .xib in the editor, and use identity inspector on 'File's Owner' in the Class field under Custom Class
My application is in landscape mod.When i call MFMailComposeViewController through Present model view, it comes in landscape mod.I rotate device and MFMailComposeViewController view goes to portrait mod i want to restrict this rotation it should always be in landscape mod only.Is there any way to do it..
Subclass the MFMailComposeViewController class, so that you can override its shouldAutorotateToInterfaceOrientation to display it however you like:
#interface MailCompose : MFMailComposeViewController {
}
#end
#implementation MailCompose
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationLandscapeLeft);
}
#end
Specify the new class in place of MFMailComposeViewController:
MailCompose *controller = [[MailCompose alloc] init];
controller.mailComposeDelegate = self;
[controller setSubject:#"In app email..."];
[controller setMessageBody:#"...email body." isHTML:NO];
[self presentModalViewController:controller animated:YES];
[controller release];
I found that a simple category for MFMailComposeViewController also worked. Since I like my app to rotate to any angle, I created & linked in MFMailComposeViewController+Rotate.h:
#import <Foundation/Foundation.h>
#import <MessageUI/MFMailComposeViewController.h>
#interface MFMailComposeViewController (Rotate)
#end
and MFMailComposeViewController+Rotate.m
#import "MFMailComposeViewController+Rotate.h"
#implementation MFMailComposeViewController (Rotate)
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return YES;
}
- (NSUInteger)supportedInterfaceOrientations {
// return the desired orientation mask from http://developer.apple.com/library/ios/#documentation/UIKit/Reference/UIApplication_Class/Reference/Reference.html
return /*mask*/;
}
#end
For my base line testing purposes (iOS 3.1.3), I don't seem to need to put it into the root view controller.
It is worth noting that BEFORE I did this, after my app would load MFMailComposeViewController, it would then stop rotating to any other orientation, even after MFMailComposeViewController was dismissed! Now my app remains freely rotatable.
Henry
This worked for me, perfectly, with one minor change:
MailCompose *controller = [[MailCompose alloc]
initWithRootViewController:self.navigationController];
...
And I was convinced that I had to call the base-class initWithRootViewController method. Otherwise, how would the MFMailComposeViewController know about it? But it turns out the example above that simply calls [[MailCompose alloc] init] is enough. The underlying MFMailComposeViewController "just knows" how to display itself.
I love happy surprises like this. I posted this in case it is equally illuminating for anyone else.
Create a new controller and inherit it from MFMailComposeViewController.In this controller just write one function shouldautorotate thing. Create instance of this.Now it will be working fine.