newly created UIViewController is not available in a storyboard - ios

I'm running into an issue with one of my view controllers and am hoping someone can help me out: my storyboard behaves as if the view controller does not exist, preventing me from making connections to the controller.
I've created a custom freeform view controller in a storyboard, it's purpose is to be displayed in a popover, allowing a user to edit a UITextLabel using the popover's UITextView.
I'm dynamically instantiating the view controller for the popover using the code below:
//create a popover with a text view under a label to be edited,
// allowing the user to edit the label with the popover
GLAppDelegate* appDelegate = (GLAppDelegate*)[[UIApplication sharedApplication] delegate];
UIViewController *mvc = (UIViewController *)appDelegate.window.rootViewController;
PopoverTextViewController* textViewController = [mvc.storyboard instantiateViewControllerWithIdentifier:#"popoverTextViewController"];
textViewController.textView.text = ((OutlinedLabel*)v.attributedView).text;
textViewController.label = (OutlinedLabel*)v.attributedView;
[self.popover dismissPopoverAnimated:YES];
self.popover = [[UIPopoverController alloc] initWithContentViewController:textViewController];
[self.popover presentPopoverFromRect:v.attributedView.frame inView:v permittedArrowDirections:UIPopoverArrowDirectionUp|UIPopoverArrowDirectionDown animated:YES];
It appears to me that the view controller I made is a typical view controller:
The problem that I'm running in is that autocomplete behaves as if there is no such view controller available in my app. Even if I manually paste it's name here, I cannot connect the textView property from the storyboard to the view controler.
When I test the code, it works - the label can be edited with the popover, but I cannot set the text within the popover, because I cannot link the text view to the view controller.
I appreciate your help!

I figured out the answer, it is a composite, 3 piece thing.
I did a "clean" on the project, then quit xCode and restarted it - this clears some weird bugs, and did work in this case. I was able to add the controller in storyboard
I forgot IBOutlet next to textview: #property(nonatomic,strong)IBOutlet UITextView* textView;
In case of popover, the textView property is nil, until viewDidLoad gets called after the popover is presented, so the code had to be reworked as follows:
//create a popover under the label with a text view, allowing the user to edit the label with the popover
GLAppDelegate* appDelegate = (GLAppDelegate*)[[UIApplication sharedApplication] delegate];
UIViewController *mvc = (UIViewController *)appDelegate.window.rootViewController;
PopoverTextViewController* textViewController = [mvc.storyboard instantiateViewControllerWithIdentifier:#"popoverTextViewController"];
[self.popover dismissPopoverAnimated:YES];
self.popover = [[UIPopoverController alloc] initWithContentViewController:textViewController];
//before this call, all views of the controller are not loaded
[self.popover presentPopoverFromRect:v.attributedView.frame inView:v permittedArrowDirections:UIPopoverArrowDirectionUp|UIPopoverArrowDirectionDown animated:YES];
//once popover is presented, the textView is created and is available
textViewController.textView.text = ((OutlinedLabel*)v.attributedView).text;
textViewController.label = (OutlinedLabel*)v.attributedView;
I hope someone finds this useful.

Related

Go to second viewcontroller in NavigationViewController

I have a UINavigationController which points to a UITableViewController (a list of items) where there is a segue from a cell to another UITableViewController (a screen to edit an item).
On first run of the application, I'd like to skip the first list and immediately go to the second screen, to edit a new item.
The problem is I need to pass the first UITableViewController, as I need to be able to go back to that one (or is there a way to set the controller the back button is pointing to?).
Things I've tried and failed:
Set a boolean shouldPresentNewItem on the UINavigationController and in the viewDidLoad if it is set to true, present the first UITableViewController, also setting a boolean so I can go to the edit screen.
Using self.navigationController!.popToViewController(arr[index] as UIViewController, animated: true) in the UINavigationControllers viewDidLoad. This gave an error as self.navigationController was nil. (I don't get why this happens)
How can this be done?
In navigation controller set some boolean indicating that you're going to show edit screen and in viewDidLoad just push edit view controller without animation:
- (void) viewDidLoad {
[super viewDidLoad];
if (self.presentEditScreen) {
self.presentEditScreen = NO;
EditViewController *e = [[DetailViewController alloc] init];
[self pushViewController:e animated:NO];
}
}
simplest way will be. just push from second view to first view
firstViewController *objFirstViewController = [[firstViewController alloc]initWithNibName:#"firstViewController" bundle:nil];
[self.navigationController pushViewController:objFirstViewController animated:No];

Change UIPopoverController on the fly

one UIPopoverviewController is currently visible....
its ViewController contains a button and clicking on the button changes the PopoverviewController's viewController to some other viewController.
Works great, viewController changed Successfully......
but PopoverViewController's contentsize is still same
lets change the contentSize manually
Step1 : View Controller changed
Step2 : popoverviewController.popovercontentSize = CGSizeMake(500,500);
:( Still No change in Size
NOTE: Both the View Controller loading successfully and if contentsize of popover is big enough to hold both then both viewController is Visible....
[UIViewController contentSizeForViewInPopover] is read only once - when the popover is shown. You can look at it as the initial value for the popover controller's size.
However, once the popover is shown, it won't ever be read again, even if you change the contentViewController. You have to use [UIPopoverController setPopoverContentSize:animated:] instead.
UIPopoverController* popover = [... already existing and visible popover ...];
UIViewController* newPopoverContents = [... new content for the popover ...];
[popover setPopoverContentSize:newPopoverContents.contentSizeForViewInPopover
animated:YES];
[popover setContentViewController:newPopoverContents
animated:YES];

Present Modal View Controller from inside Popover View

So in my universal app I have a section where a person can look at an existing list of notes from our system (retrieved through a simple web service) and then also create a new note if they want. So for the iphone it's pretty simple layout, a TableViewController for displaying the list with a "Add" button on the NavigationBar that presents the modalview for adding the new item. On the iPad though, the same layout has a lot of wasted space so I opted to go with the popOver method to show the list in a popOver and then let them add from there. My problem is that when the user clicks on the Add button within the PopOver view, the modal view comes up full screen instead of just coming up within the popover view. Here's the code I have so far:
-(void) AddButtonPressed:(id)sender {
NewNoteVC *newNote = [[[NewNoteVC alloc] initWithNibName:#"NewNoteVC" bundle:nil] autorelease];
newNote.defaultClientID = defaultClientID;
UINavigationController *navCon = [[[UINavigationController alloc] initWithRootViewController:newNote] autorelease];
if ([isPopOver isEqualToString:#"YES"]) {
[navCon setModalInPopover:YES];
[self.navigationController setModalInPopover:YES];
[self.navigationController presentModalViewController:navCon animated:YES];
}
else {
[self.navigationController presentModalViewController:navCon animated:YES];
}
}
The "isPopOver" string is just a placeholder sent from the previous screen that called this TableView (I know I can switch this to a boolean for better performance I just put this together real quick to try it out). I know I messed up somewhere, I just don't know what setting I need to get this working correctly.
You need to define the view controller's modalPresentationStyle to be "current context".
navCon.modalPresentationStyle = UIModalPresentationCurrentContext;
This will result in modal view controller filling the popover like the popover's root controller.
Try using the presentViewController:animated:completion: instead of presentModalViewController:animated: and set self.navigationController.definesPresentationContext = YES

IOS Switch view and storyboard not works

I have a problem with switching views. I'm using a simulator with xcode 4.2
Storyboard contains:
NavigationController (initial view controller)
UIViewController which has relationship with the navigation controller
UIViewController (paired with my custom class: ViewEntryImageController) which hasn't got any relationship. Contains a button, a bottom toolbar with some toolbar button.
User come into the UIViewController, where he can see a ScrollView and in ScrollView some images.
Images has a gesture:
UITapGestureRecognizer *recognizer=[[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(openEntryImage)];
[image addGestureRecognizer:recognizer];
[recognizer release];
The openEntryImage function:
(IBAction)openEntryImage
{
ViewEntryImageController *controller=[[ViewEntryImageController alloc]initWithNibName:nil bundle:nil];
controller.modalTransitionStyle=UIModalTransitionStyleCrossDissolve;
[self presentModalViewController:controller animated:YES];
[controller release];
}
When I try to tap the image, the openEntryImage works as well (the effect is correct), but I don't see my ViewEntryImageController view and my buttons, I'm only see a black window.
I try to put a NSLog line into the ViewEntryImageController viewDidLoad function, and it works, so what is the black window and where is my view controller?
When I try to use pushViewController, on the new view I found a navigation toolbar with a back button, but no other controls.
I tried another version, I created a UIViewController class, but now with a xib file. I used it instead of ViewEntryImageController and it works. Why?
I want to use this controller in storyboard too.
The ViewEntryImageController class by itself has no information about how to build the dialog. But you can instantiate your view controller on your own from the storyboard:
UIStoryboard *myStoryboard = [UIStoryboard storyboardWithName:#"StoryboardFileName" bundle:nil];
ViewEntryImageController *controller = (ViewEntryImageController *)[myStoryboard instantiateViewControllerWithIdentifier:#"ViewEntryImage"];
This assumes a storyboard name of StoryboardFileName and that the view entry image controller has an identifier of ViewEntryImage set in the view properties (Attributes inspector, section "View Controller").
Try it like this :
ViewEntryImageController *controller=[[ViewEntryImageController alloc]initWithNibName:#"ViewEntryImageController" bundle:nil];
If you don't use .nib names but rather use storyboards, it's a bit harder. Create a segue from the controller to the ViewEntryImageController controller by holding ctrl and dragging from one view to the other. Click this segue and give it an identifier.
Then use the [self performSegue:#"identifier"]; function to present the next view.

Popovers cannot be presented from a view which does not have a window

What does this error indicate:
"Popovers cannot be presented from a view which does not have a window."
the thing that saved my life:
if (self.view.window != nil)
[popoverController presentPopoverFromRect:CGRectMake(44, yCoord, 111, 111) inView:self.view permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
by adding if condition it doesn´t crash anymore. I don´t really get it because the presentPopoverFromRect function is ALWAYS called. There is no situation where window would be nil but anyway it did the trick.
edit: I have this code in viewDidAppear.
Nevertheless in most cases it's enough to move presentPopoverFromRect to viewDidAppear or didMoveToWindow but in my case for some reason the if condition was necessary.
the view you're adding the popover to has to already have been added to a window with the "addSubview:" method.
Try waiting until
- (void) didMoveToWindow
is called for the view and then load the popover
I got this problem.
I had a UITabBarController as the detail view, and I set the barButtonItem as the leftBarButtonItem on all three navigation controllers in the tab bar.
vcChart.navigationItem.leftBarButtonItem = barButtonItem;
vcAnalysis.navigationItem.leftBarButtonItem = barButtonItem;
vcTechnicals.navigationItem.leftBarButtonItem = barButtonItem;
Turns out only the last one added is valid, and the previous two would throw the exception when tapped on.
To fix it, I only set the leftBarButtonItem for the visible view controller, and just switched the barButtonItem to the visible view controller every time the user switched tabs.
Just encountered this issue. Turned out that the inView: parameter was using an IBOutlet that wasn't connected in IB. Thus, an attempt was made to launch the popover in nil. That doesn't work.
So, make sure you are using a valid view.
There are many ways to get to this error. Basically you need to wait to call the presentPopover command until your calling view is added to a window. I did it this way.
- (void)viewDidAppear:(BOOL)animated
{
[self methodThatDisplaysPopOver];
}
My presentPopoverFromRect call is inside my methodThatDisplaysPopOver function.
You could protect every presentPopover call like MobiMaciek suggests with this.
if (self.view.window != nil)
[popoverController presentPopoverFromRect:CGRectMake(10, 10, 100, 100) inView:self.view permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
However, I think it would be better to understand when self.view.window gets assigned and make sure that you present you popover after the view has a window.
I received the same error message when assigning the same UIBarButtonItem to multiple navigation items as did Lewis. My example was slightly more complicated as I was using a UISplitViewController.
In my RootViewController I have an array of arrays to accomplish multiple sections within my table. Each time that the user clicks a row in the table, a new "detail" view controller is placed in the right pane of my splitViewController. Prior to setting the leftBarButtonItem = nil, I would receive a segfault after 3-4 clicks of the "Menu" button with the same error as a111. I updated my code to actually retrieve the previous detail view controller and set the leftBarButtonItem item to nil.
allData is my NSMutableArray that contains several other NSMutableArrays as objects.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// Retrieve the new detail view controller
UIViewController *detailViewController = [[self.allData objectAtIndex:indexPath.section] objectAtIndex:indexPath.row];
// Add the detail view controller to a navigation controller and set the bar style
UINavigationController *detailNavigationController = [[UINavigationController alloc] initWithRootViewController:detailViewController];
detailNavigationController.navigationBar.barStyle = [[NSUserDefaults standardUserDefaults] integerForKey:#"UIBarStyle"];
// Retrieve previous detail view controller and remove the leftBarButtonItem
UINavigationController *previousDetailNavigationController = [splitViewController.viewControllers objectAtIndex:1];
UIViewController *previousDetailViewController = [[previousDetailNavigationController viewControllers] lastObject];
previousDetailViewController.navigationItem.leftBarButtonItem = nil;
// Update the split view controller's view controllers array.
NSArray *viewControllers = [[NSArray alloc] initWithObjects:self.navigationController, detailNavigationController, nil];
splitViewController.viewControllers = viewControllers;
[detailNavigationController release];
[viewControllers release];
// Dismiss the popover if it's present.
if (popoverController != nil) {
[popoverController dismissPopoverAnimated:YES];
}
// This sets the left bar to nil when in landscape and equal to "Menu" when in portrait.
// We need to remove rootPopoverButtonItem from the previous viewController...
detailViewController.navigationItem.leftBarButtonItem = rootPopoverButtonItem;
}
The error message was slightly deceiving at first but the answers above helped me out. I wonder why I could click the "Menu" button up to 3-4 different times before the segfault... I'll investigate further.
This error also occurred when the inView: Parameter is incorrect - to test try self.view
yes, you are right but still we can add subview from parent class in it. so it can be represented from a view which have a window:
[popoverController.contentViewController.view addSubview:mySubView];
I had the same error message as the OP, in a very similar situation to that reported by TPoschel, except I had a split view controller with an embedded tab bar controller in the detail pane, and a navigation controller within this. The bar button item is added as the navigation bar leftBarButtonItem.
Only on iOS5.0 (not 5.1) does it seem to require you invalidate the bar button item on the tab bar you are leaving by setting it to nil. Before then adding the bar button to the navigation bar on the tab you are going to.
If I don't do that, from debugging my own code, the window property of the bar button item stays set to nil, and causes the exception, on returning to a screen you'd previously been to. I'm guessing as a side effect of setting the leftBarButtonItem in the navigation item, it goes off and sets the frame. But it doesn't seem to bother unless the button is different from what is currently set there. Hence, the need to set it to nil when leaving a tab, even though it is technically the same button that's being passed around.
I would upvote TPoschel's answer, except SO won't let me.
I had a problem like this. Received this message when clicking a customized UIBarButton item that invoked a selector method with did performSeque.
The problem was my segue was still attached to the UIBarButton item. It should have been attached to the main view of of the view controller. Changed this and worked fine.
P.S., all this got started because I wanted to add and "info" button to my UIToolBar. This isn't one in the system provided list and should be.
There will be a view from which you asks to display your popover.The reason for this error is because you didn't made this view as a subview of the window.
[self.view addSubview:displayPopOverVC];
where displayPopOverVC is the view controller from which the popOver appears
i had the same problem, after adding PresentPopOver in viewDidAppear this was solved
- (void) viewDidAppear:(BOOL)animated{
CGRect popoverRect = screenBounds;
popoverRect.size.width = MIN(popoverRect.size.width,0) ;
popoverRect.origin.x = screenBounds.origin.x;
[popoverController
presentPopoverFromRect:popoverRect
inView:self.view
permittedArrowDirections:UIPopoverArrowDirectionAny
animated:YES];
}
this was happening as inView:self.view should be called after viewDidLoad as suggested by #hey68You and MobiMaciek..
I replaced
[actionSheet showFromBarButtonItem:self.navigationController.navigationItem.leftBarButtonItem animated:YES];
with
[actionSheet showInView:self.view];

Resources