Push View Controller, Black Screen - ios

I'm pushing to a new view controller and passing some data to it. When I run the application I can press the button and push to a new view but the screen is completely black. Any help is appreciated.
- (IBAction)button:(id)sender {
NSString *firstField = self.field.text;
NSString *secondField = self.field2.text;
self.resultsArray = [[NSArray alloc] initWithObjects:firstField, secondField, nil];
NSUInteger randomResult = arc4random_uniform(self.resultsArray.count);
self.label.text = [self.resultsArray objectAtIndex:randomResult];
ImagesViewController *ivc = [[ImagesViewController alloc] init];
ivc.label = self.label.text;
[self.navigationController pushViewController:ivc animated:YES];
}

When you're using a storyboard, and you want to push a view controller in code (rather than with a segue), you need to give the controller an identifier, and create it like this:
ImagesViewController *ivc = [self.storyboard instantiateViewControllerWithIdentifier:#"MyIdentifier"];
ivc.label = self.label.text;
[self.navigationController pushViewController:ivc animated:YES];

The view controller you are pushing is not having any frame dimension set.It is always recommended to call designated init for objects. For view controllers, designated init method is
- (id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)nibBundle
if you have a xib assign it like
ImagesViewController *ivc = [[ImagesViewController alloc] initWithNibName:<your xib> bundle:[NSBundle mainbundle];
if you are using custom view, assign a frame dimension and add it as subview

Xcode 7.3 and Swift 2.2
In my case, I had made changes in the storyboard and made it a TabBarController and accordingly changed the class of the controller from UIViewController to UITabBarController. After some tweaking, this change wasn't favourable and I un did all the changes and got a black screen then because I had forgotten to change the class of the controller. I changed it back to UIViewController and it started working again.
So check if you have made the same mistake. The black screen came because the storyboard had a class(UIView/UITabBar/UITableView Controller) but that wasnt the same in code.

This can also happen if you have somehow got an incorrect connection between one of the subviews in the storyboard to the controller's view. Check the Referencing Outlets are correct in each of your subviews.

I got a good one:
Make sure you are implementing the right Super class, delegate, etc.. in the top part of the viewController you are trying to present. i.e.
I wasn't using/implementing UINavigationController at all
class TMDetailBlogViewController: UINavigationController {
//code goes here
}
After
class TMDetailBlogViewController: UIViewController {
//code goes here
}

Typically, you transition to another view controller by calling:
initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
on your custom UIViewController.
If you're not using a xib file, then what you're doing may be fine. Are you dynamically creating your UI elements within the constructor of your ImagesViewController?

I was trying without using storyboard, and its just that the default screen it uses is in black color. I changed the background color to white and it worked.
Pushed the controller this way-
NextController *nextController = [[NextController alloc]init];
[self.navigationController pushViewController:nextController animated:YES];
In NextController-
(void)viewDidLoad{
[self.view setBackgroundColor:[UIColor whiteColor]];
}

Related

iOS - Is it still possible to dynamically add items to UITabBarController in this age of adaptive layout?

I have an app that communicates with an outside entities. I need to either show or hide an item on the tab bar if that entity has a switch flipped on or off.
It has to be dynamic in case the user changes from entity A to entity B and those have different settings. Tab bar item needs to show/hide if they switch and settings differ.
I used to add an item to a UITabBarController like this:
UIViewController *vc1 = [[MyViewController1 alloc] init];
[self.tabBarController addChildViewController:vc1];
UIViewController *vc2 = [[MyViewController2 alloc] init];
[self.tabBarController addChildViewController:vc2];
And I could remove items from a tab bar like this:
NSMutableArray *tbViewControllers = [NSMutableArray arrayWithArray:[self.tabBarController viewControllers]];
[tbViewControllers removeObjectAtIndex:4];
[tbViewControllers removeObjectAtIndex:4];
[self.tabBarController setViewControllers:tbViewControllers];
In my ViewController Code I had something like this:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
//get the tab bar item
UITabBarItem *tbi = [self tabBarItem];
//give it a label
[tbi setTitle:#"Tab Item"];
//create a UIImage from a file
UIImage *i = [UIImage imageNamed:#"image.png"];
//put that image on the tab bar item
[tbi setImage:i];
}
return self;
}
Now, with the advent of adaptive app layout and segues it seems that adding an item dynamically does not work. At least for me.
I get a black screen instead of the view I expect to see when doing the above. The UIView in question is basically a UIWebView with a couple custom buttons above it.
My app is fully adaptive layout compatible with UIStackViews and whatnot.
All the posts I see here referencing adding or removing items from UITabBars are all several years old, before modern adaptive layout.
Is it still possible to add/remove tab items from the tab bar anymore? Is it advisable to do so or is this now bad practice?
Any other ideas to accomplish this same goal of having an item on a tab bar or not depending on an outside setting?
Cheers,
TJ
I found my own solution and am sharing it to help others.
The trick was how the UIViewController was created.
The new way to do this is to create the view controller by instantiating from the storyboard.
I found the idea from this question.
Creating and adding to the TabView is done like this:
// Get a reference to the Tab View Controllers array
NSMutableArray *tbViewControllers = [NSMutableArray arrayWithArray:[self.tabBarController viewControllers]];
// Get a reference to the storyboard
UIStoryboard *sb = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:[NSBundle mainBundle]];
// Instantiate a new instance of the ViewController
UIViewController *vc1 = [sb instantiateViewControllerWithIdentifier:#"MyVC"];
// Add the new view controller to the array at the desired location
[tbViewControllers insertObject:vc1 atIndex:tbViewControllers.count-1];
// Set the tab bar controllers to the newly augmented array
[self.tabBarController setViewControllers:tbViewControllers];
That's it. The view controller works as I expect it to. No more black screen.
Hope this helps someone else.

Toggle edit mode in another ViewController

I have a ViewController (with a container view) embedded in a Navigation controller. The container contains a pageViewController with one of the 'pages' being a TableViewController (with UITableView outlet: 'aTableView'). I want to trigger the edit mode in the tableViewController when tapping a custom editButton in the navigation bar. When I create a custom editutton in the tableViewController the edit mode works as expected, but when I use the custom editButton in the navigation bar the setEditing bool value remains zero even when I setEditing to YES in the editButton selector. Here's the code:
ViewController.m
-(void)viewDidLoad {
self.editBtn = [UIButton buttonWithType:UIButtonTypeCustom];
[self.editBtn setFrame:CGRectMake(0, 0, 40, 22)];
[self.editBtn addTarget:self action:#selector(goToToggleEdit:) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *editButton=[[UIBarButtonItem alloc]initWithCustomView:self.editBtn];
self.navigationItem.rightBarButtonItem = editButton;
}
-(void)goToToggleEdit:(id)sender
{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
TableViewController *tvc = [storyboard instantiateViewControllerWithIdentifier:#"aTableViewController"];
if(something==foo){
[tvc toggleEdit];
}
}
aTableViewController.h
#interface aTableViewController : UITableViewController <UITextFieldDelegate> {
IBOutlet UITableView *aTableView;
}
-(void) toggleEdit ;
#end
aTableViewController.m
-(void)toggleEdit {
[aTableView setEditing:YES animated:YES];
NSLog(aTableView.editing ? #"Yes" : #"No"); // --> logss 'No'.
if (aTableView.editing){
//do something
}
else {
//do something else
}
}
How can I efficiently trigger the edit mode in the tableViewController this way?
Edit
#Bagrat Kirakosian pointed out to me that my view hierarchy (Navigation Controller > View Controller (with containter) > Page View Controller (in container) > Table View Controller) might be the problem. I just want to create a Navigation Bar (with an edit button) that is fixed, therefore I can't embed the Table View Controller directly in a Navigation Controller.
Thanks.
UPDATE: Solution
I have accepted #sebastien's solution although both #sebastien's and #Bagrat's solution work great. #Bagrat's answer includes direct access to the Table View Controllers, while #sebastien's solution calls edit mode in the pageViewController. I think, considering the tricky hierarchy, the latter is a bit more secure.
Here is the code for my View Controller that totally work fine. be sure you configure your bar button in the right method of View Controller lifecycle. Also be sure that your #selector is properly implemented in your code.
In the same View Controller put these two blocks of code
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
UIBarButtonItem *rightBarButton = [[UIBarButtonItem alloc] initWithImage:[[UIImage imageNamed:#"edit_icon.png" ] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] style:UIBarButtonItemStylePlain target:self action:#selector(edit:)];
[rightBarButton setTintColor:[UIColor whiteColor]];
self.navigationItem.rightBarButtonItem = rightBarButton;
}
Afterwards you need also to put your edit selector
-(void)edit:(UIButton *)sender {
// Toggle edit by inverting current edit state
// Also in this block change your right bar button text or image
[self.tableView setEditing:!self.tableView.editing animated:YES];
}
UPDATE 1
After your comment we got to whole another question. You problem is not in the part where you try to call toggle edit. Your problem is the wrong hierarchy of controllers (Navigation Controller > View Controller > Page View Controller > Table View Controller). This might cause a problem. Try to change your controllers like this;
UINavigationController > UIPageViewController > UIViewController(s)
Also it's a good practice to have a UITableView in UIViewController rather than using really dead UITableViewController. Don't forget to connect your tableView IBOutlet (by the way you didn't need it in UITableViewController), also connect datasource and delegate to Files owner. In your MyTableViewVC.h file add this line
#interface MyTableViewVC : UIViewController <UITableViewDataSource, UITableViewDelegate>
After that all your calls will work fine.
UPDATE 2
After analyzing your entire structure I found a mistake that you do every time on the button click.
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
tvc = [[TodolistTableViewController alloc] init];
When you call storyboard every time it's ok but when you do [[TodolistTableViewController alloc] init] you are RE-MAKING the same table view controller every time but not even adding it to your main view. As I told you, your tricky hierarchy might cause difficulties but it has a solution.
In your PageViewController.m make tv1 and tv2 properties in .h file, like so.
#property (strong, nonatomic) UITableViewController *tv1;
#property (strong, nonatomic) UITableViewController *tv2;
Then in the view controller file do this
-(void)toggleEdit:(id)sender
{
PageViewController *current = (PageViewController *)[[self childViewControllers] firstObject];
if ([current isKindOfClass:[PageViewController class]])
{
[((TodolistTableViewController *)[current tv1]) toggleEdit];
}
}
Answer includes all security checks and direct access to your table view controllers, because you might need to change other properties/call functions later.
Now in -(void)toggleEdit:(id)sender you don't re-create your views every time but you catch the ones you already have in your current View Controller.
Good Luck!
Ok, your issue here is that you are trying to access an embedded controller in a wrong way.
You are actually managing 2 differents PageViewController:
The one you generated through your storyboard
The other one you are initiating in your code further
That's why you can't reach the expected result.
First of all, add a new method to your PageViewController:
PageViewController.h:
- (void)editTableAtIndex:(int)index;
PageViewController.m:
- (void)editTableAtIndex:(int)index {
[[self viewControllerAtIndex:index] setEditing:YES];
}
Now, in your main ViewController, access the PageViewController by using childViewControllers:
-(void)toggleEdit:(id)sender
{
PageViewController *pvc = self.childViewControllers[0];
[pvc editTableAtIndex:0];
}
It should be editing your TodoListTableView:
(Please notice that I used [pvc editTableAtIndex:0];, instead you should be calling something like [pvc editTableAtIndex:_PageViewController_current_index_];)

UILabel is always nil

I have the following problem.
This is my Code:
GTSearchViewController* vc = [[GTSearchViewController alloc] initWithNibName:#"GTSearchViewController"
bundle:nil];
vc.headlineLabel.text = [[self.categorieArray objectAtIndex:indexPath.row] valueForKey:#"categoryName"];
[AppDelegate().centerViewController pushViewController:vc
animated:YES];
As you can see, I try to push a New ViewController with a xib File and want to set a String in my headlineLabel from my Array self.categorieArray. But when the SearchController gets pushed, everything works perfect, but my headlineLabel is always nil.
I don't understand why, I thought I donĀ“t need to call "alloc-init" in the SearchController because everything is build with Interface Builder?
Your problem is changing UI before it actually is loaded.
You should set label's text in ViewDidLoad of your view controller (it is called after the view is loaded).
Make NSString property in your SearchViewController class and set it right after initialization.
vc.headlineText = [[self.categorieArray objectAtIndex:indexPath.row] valueForKey:#"categoryName"];
Then in SearchViewController you should override viewDidLoad method:
- (void) viewDidLoad{
[super viewDidLoad];
self.headlineLabel.text = self.headlineText;
}
P.S. Of course I assume that you've set headlineLabel outlet correctly (from Interface Builder).

iOS SplitView Controller, Programatically Change View With Multiple Storyboards

Hopefully someone can help.
I've got an app that uses the UISplitViewController however I've now had to start using multiple storyboards because i've got a large amount of views and Xcode was starting to run really slow. I've moved moved the UIViewControllers to multiple storyboards.
The Master View is built from static cells, so when the user selects the cell I normally change the view by pushing a segue.
I'm now wondering how to programmatically change the detail view of a UISplitViewController?
Thanks
Subclass UISplitViewController and set your root splitViewController to that class. Then add this method to your UISplitViewController subclass:
-(void)setDetailControllerTo:(UIViewController *)detailController withNavControllerTitle:(NSString *)title {
[detailController view]; // this line forces the viewDidLoad method to be called
if (title) {
UINavigationController *navController = [[UINavigationController alloc] init];
[navController pushViewController:detailController animated:YES];
detailController.title = title;
NSArray *viewControllers=#[self.mainController.viewControllers[0],navController];
self.mainController.viewControllers = viewControllers;
} else {
NSArray *viewControllers=#[self.mainController.viewControllers[0],detailController];
self.mainController.viewControllers = viewControllers;
}
}
To call this method do something like this from the master view controller:
FixedSplitViewController *splitController = (FixedSplitViewController*) self.splitViewController;
CurrentEventViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:#"CurrentEventViewController"];
// add any setup code here
[splitController setDetailControllerTo:controller withNavControllerTitle:#"Current Event"];
A lot of my projects require the splitviewcontroller to always show the master view so I use this subclass to keep the master view from hiding on portrait rotation.

Share a view between UIViewControllers? Second viewController "steals" view from first?

I am experiencing this behavior: I have a UIViewController UIView which I want to share between 2 or more UIViewControllers.
First I instance the shared UIViewController in AppDelegate with:
SharedViewController *sharedViewController = [[SharedViewController alloc] init];
Then, when I am instancing the new UIViewController I add the shared view controller view:
ViewController1 *viewController1 = [[ViewController1 alloc] init];
and inside it I add the shared view controller view:
- (void)viewDidLoad
{
[super viewDidLoad];
[self.view addSubview:sharedViewController.view];
}
This works fine, as long as a second view controller - i.e. viewController2 - does the same thing, then viewController2 gets the view and viewController1 gets nothing!
I applied a workaround, placing this in viewWillAppear and it seems to work, but I am afraid I am adding the same view one onto another multiple times, isn't there a better way to do this?
-(void)viewWillAppear {
[self.view addSubview:sharedViewController.view];
}
-(void)viewWillDisappear {
[sharedViewController.view removeFromSuperview];
}
This should work.
But are you sure it has to be a shared UIViewController, if you only use the view? Why not just a shared UIView?

Resources