pushViewController lead to black screen, NO STORYBOARD - ios

I see all the other solutions and nothing works for me. When I initiate the application, it works fine, but when I click a table item and push a ViewController, the screen goes black, and keeps black forever. Here is my code:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:NO];
ToDoItemViewController *itemViewController = [[ToDoItemViewController alloc] initWithNibName:#"ToDoItemViewController" bundle:[NSBundle mainBundle]];
ToDoItem *itemSelected = [[self toDoItems] objectAtIndex:indexPath.row];
itemViewController.toDoItem = itemSelected;
itemViewController.delegate = self;
[self.navigationController pushViewController:itemViewController animated:YES];
}
The name of the Nib is ok, and the ToDoItemViewController:
- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
}
return self;
}
Thanks in advance,
Remember, I DON'T USE STORYBOARDS and I want to keep that
EDIT
Here is how I launch my first ViewController
ListadoViewController *listadoViewController = [[ListadoViewController alloc] initWithNibName:#"ListadoViewController" bundle:nil];
CustomNavigationController *navCtrl = [[CustomNavigationController alloc] initWithRootViewController:listadoViewController];
self.window.rootViewController = navCtrl;

I resolved it. The problem was that I implement the method "loadView", but I didn't know that that method is implemented by iOS, so I was not calling the super and it wasn't drawing anything.
Thanks all for your responses.

Related

Application tried to push a nil view controller on target

I am creating an app without storyboards and I am having trouble moving from when a user clicks on a table view cell to the detail view of that cell.
in the class where I create and handle the table view I have the following code:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
PersonDetailViewController *detailViewController;
Person *person = [self.playerArray objectAtIndex:indexPath.row];
detailViewController.person = person;
[[self navigationController] pushViewController:detailViewController animated:YES];
}
So I am trying to push a detail view controller on to the screen and then display the user info on that detail screen. I have tried to find a solution to this but, most of the answers I have come across use storyboards, and I am not using storyboards.
in my PersonDetailViewController.m class I have the following code:
#import "PersonDetailViewController.h"
#interface PersonDetailViewController ()
#end
#implementation PersonDetailViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.personInfo = [[UITextField alloc] initWithFrame:CGRectMake(45, 30, 200, 40)];
_personInfo.backgroundColor = [UIColor whiteColor];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
#end
I am not sure if this may be a cause for the issue but in my delegate I have the following:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.window.backgroundColor = [UIColor whiteColor];
self.tableViewController = [[TableViewController alloc]init];
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:self.tableViewController];
self.window.rootViewController = nav;
[self.window makeKeyAndVisible];
return YES;
}
I was thinking that maybe it has something to do with creating the navigation controller but I was playing around with it and I do not think it does.
You missed the initialization of the view controller in the tableView:didSelectRowAtIndexPath: method
PersonDetailViewController *detailViewController = [[PersonDetailViewController alloc] init]; // or initWith...

Difference between [UINavigationController setView] and [UINavigationController setViewControllers]

I have a method, which is supposed to init a navigation controller and load a view controller for a side menu. This all happens within a view controller that's not attached to any other navigation controllers.
- (void)showLeftNC
{
if (leftNavCon == nil)
{
leftNavCon = [[UINavigationController alloc] init];
}
[leftNavCon setViewControllers:#[lmvc] animated:NO];
//[leftNavCon setView:lmvc.view];
[leftNavCon.view setFrame:lmvc.view.frame];
[self.view addSubview:leftNavCon.view];
[self showCenterViewWithShadow:YES withOffset:-2];
[self.view sendSubviewToBack:leftNavCon.view];
}
leftNavCon is the navigation controller
lmvc is the primary view controller
It doesn't work in this way, neither when I call initWithRootViewController:lmvc
It only has worked when I used the commented [leftNavCon setView:lmvc.view]. But even then I couldn't get the navigation controller to push any another view controllers yet.
Help please.
never mind, i worked out something, I used lmvc as a containing view, initialised the navigation controller and all the view controllers i needed inside it
in the lmvc initWithNibName
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
if (testViewController == nil)
{
testViewController = [[UIViewController alloc] init];
}
if (navCon == nil)
{
navCon = [[UINavigationController alloc] initWithRootViewController: testViewController];
}
view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 300, 748)];
[self setView:navCon.view];
[testViewController.view addSubview:table];
[testViewController.view addSubview:button];
[testViewController.view addSubview:anyControlYouNeed];
}
and then later on
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (tableTwo == nil)
{
tabl = [[UITableView alloc] initWithFrame:table.frame];
}
if (testViewControllerTwo == nil)
{
testViewControllerTwo = [[UIViewController alloc] init];
}
tableTwo.delegate = self;
tableTwo.dataSource = self;
[testViewControllerTwo setView:tableTwo];
[navCon pushViewController: testViewControllerTwo animated:YES];
}
Works like a charm

iOS Passing data between views

i need to pass data between to Views. I really can't figure out why is not working. Variable selectedRow in SecondViewController is always empty.
FirstViewController.m
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self.tableView deselectRowAtIndexPath:indexPath animated:YES];
SecondViewController *newView = [[SecondViewController alloc] init];
newView.selectedRow = [tablelist objectAtIndex:indexPath.row];
newView.title = [self.tableView cellForRowAtIndexPath:indexPath].textLabel.text;
[self.navigationController pushViewController:newView animated:YES];
}
SecondViewController.h
#interface SecondViewController : UIViewController
{
NSString *title,*selectedRow;
}
#property(nonatomic,retain) NSString *title;
#property (nonatomic,retain) NSString *selectedRow;
#end
SecondViewController.m
#synthesize title,selectedRow;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
textView = [[UITextView alloc]initWithFrame:CGRectMake(0, 64, 320, 370)];
textView.text = selectedRow;
textView.editable = FALSE;
[self.view addSubview:textView.text];
}
return self; }
I'm struggling for hours. I really cant figure why.
Any help?
Thank you
The problem is that you are looking at the selectedRow value before you set the property. You can't set the selectedRow property until after the call to init completes.
Since your use of the property is to setup the view controller's view, you should move that code to viewDidLoad where it belongs. As a rule, you should not access self.view in the init method of a view controller.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
textView = [[UITextView alloc]initWithFrame:CGRectMake(0, 64, 320, 370)];
textView.text = selectedRow;
textView.editable = FALSE;
[self.view addSubview:textView.text];
}
I used savestrings to pass data to the next viewcontroller. The only thing you need to do is import the viewcontroller from where the data comes in the viewcontroller.
You can use this in the first viewcontroller
//1e savestring
NSString *saveString1 = emailfield.text;
NSUserDefaults *defaults1 = [NSUserDefaults standardUserDefaults];
[defaults1 setObject:saveString1 forKey:#"saveString1"];
[defaults1 synchronize];
ANd this in the viewcontroller where you need to load data
//First load string
NSUserDefaults *defaults1 = [NSUserDefaults standardUserDefaults];
NSString *loadString1 = [defaults1 objectForKey:#"saveString1"];
[emailfield setText:loadString1];
if you are using storyboard to get a viewcontroller ,you can try this.
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UIStoryboard *storyboard = [ UIStoryboard storyboardWithName:#"Main" bundle:nil ];
SecondViewController *vc = [storyboard instantiateViewControllerWithIdentifier:#"test" ];
vc.title = #"something";
[self.navigationController pushViewController:detailView animated:YES];
}

UITableView is shifting down ~1inch unintentionally when using using sidebar menu

I'm having a weird bug in my app that uses a sidebar menu with a UITableView to list buttons to navigate. When I start my app, everything looks fine and is in the correct place.
Once I make a selection to the respective viewController, and navigate back to sidebar menu theUITableView` is shifted down about 1 inch.
If I press the sidebar menu button to close it, the menu resets and everything works and looks normal. This bug only happens once, once I select an row, navigate back to it, close it, the UITableView will be in the correct position until the user hard restarts the app. Any idea whats going on?
Here is my code for the sidebar menu:
#import "SideBarViewController.h"
#interface SideBarViewController ()
#end
#implementation SideBarViewController
#synthesize controllerArray, sidebarButton;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
controllerArray = [NSArray arrayWithObjects:#"Search For Games", #"Login", #"Library", nil];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [controllerArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"SimpleTableItem";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
cell.textLabel.text = [controllerArray objectAtIndex:indexPath.row];
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UIViewController *selection;
if (indexPath.row == 0) {
selection = [self.storyboard instantiateViewControllerWithIdentifier:#"SearchController"];
[self.navigationController pushViewController:selection animated:YES];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
else if (indexPath.row == 1) {
selection = [self.storyboard instantiateViewControllerWithIdentifier:#"LoginController"];
[self.navigationController pushViewController:selection animated:YES];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
else if (indexPath.row == 2) {
selection = [self.storyboard instantiateViewControllerWithIdentifier:#"LibraryController"];
[self.navigationController pushViewController:selection animated:YES];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
}
I followed the tutorial on the "Ray Wenderlich" website for sidebar code.
Also, I've tested other objects, such as buttons and labels and they do not move, its only the UITableView that shifts.
Thanks!
I found the solution! It had to do with the setting for the Navigation controller. Credit due here.
Container View getting pushed down as if it had a UINavigationBar?
You need to check and see if "Translucent" is checked under the Navigation Bar settings.
Try adding self.tableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0); to viewDidLoad. This could be a solution if your app is adding insets automatically.
Try setting self.automaticallyAdjustsScrollViewInsets = NO in your view controller.
Try setting the edgesForExtendedLayout to UIRectEdgeNone.
Hope it helps.

UINavigationController State Restoration (without Storyboards)

I've been toying around with state restoration. In the code below, the scroll position of the UITableViewController gets restored, however, if I were to tap through into the detail view (pushing an instance of MyViewController onto the navigation stack), when the app restarts, it always returns to the first view controller in the navigation stack (i.e. MyTableViewController). Would somebody be able to help me restore to the correct view controller (i.e. MyOtherViewController)?
AppDelegate.m
- (BOOL)launchWithOptions:(NSDictionary *)launchOptions
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
MyTableViewController *table = [[MyTableViewController alloc] initWithStyle:UITableViewStylePlain];
table.depth = 0;
UINavigationController *navCon = [[UINavigationController alloc] initWithRootViewController:table];
navCon.restorationIdentifier = #"navigationController";
self.window.rootViewController = navCon;
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
});
return YES;
}
- (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
return [self launchWithOptions:launchOptions];
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
return [self launchWithOptions:launchOptions];
}
MyTableViewController.m
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if(self)
{
self.restorationIdentifier = #"master";
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.title = #"Master";
self.tableView.restorationIdentifier = #"masterView";
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 5;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 10;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
return [NSString stringWithFormat:#"Section %d", section];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(!cell)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.textLabel.text = [NSString stringWithFormat:#"%d", indexPath.row];
return cell;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
MyOtherViewController *vc = [[MyOtherViewController alloc] initWithNibName:nil bundle:nil];
[self.navigationController pushViewController:vc animated:YES];
}
MyOtherViewController.m
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
self.restorationIdentifier = #"detail";
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.title = #"Detail";
self.view.backgroundColor = [UIColor redColor];
self.view.restorationIdentifier = #"detailView";
}
Because you are creating your detail view controller in code, and not instantiating it from a Storyboard, you need to implement a restoration class, so the system restoration process knows how to create the detail view controller.
A restoration class is really just a factory which knows how to create a specific view controller from a restoration path. You don't actually have to create a separate class for this, we can just handle it in MyOtherViewController:
in MyOtherViewController.h, implement the protocol: UIViewControllerRestoration
Then when you set the restorationID in MyOtherViewController.m, also set the restoration class:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
self.restorationIdentifier = #"detail";
self.restorationClass = [self class]; //SET THE RESTORATION CLASS
}
return self;
}
You then need to implement this method in the restoration class (MyOtherViewController.m)
+(UIViewController *) viewControllerWithRestorationIdentifierPath:(NSArray *)identifierComponents coder:(NSCoder *)coder
{
//At a minimum, just create an instance of the correct class.
return [[MyOtherViewController alloc] initWithNibName:nil bundle:nil];
}
That gets you as far as the restoration subsystem being able to create and push the Detail View controller onto the Navigation Stack. (What you initially asked.)
Extending the Example to handle state:
In a real app, you'd need to both save the state and handle restoring it... I added the following property definition to MyOtherViewController to simulate this:
#property (nonatomic, strong) NSString *selectedRecordId;
And I also modified MyOtherViewContoller's viewDidLoad method to set the Detail title to whatever record Id the user selected:
- (void)viewDidLoad
{
[super viewDidLoad];
// self.title = #"Detail";
self.title = self.selectedRecordId;
self.view.backgroundColor = [UIColor redColor];
self.view.restorationIdentifier = #"detailView";
}
To make the example work, I set selectedRecordId when initially pushing the Detail View from MyTableViewController:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
MyOtherViewController *vc = [[MyOtherViewController alloc] initWithNibName:nil bundle:nil];
vc.selectedRecordId = [NSString stringWithFormat:#"Section:%d, Row:%d", indexPath.section, indexPath.row];
[self.navigationController pushViewController:vc animated:YES];
}
The other missing piece are the methods in MyOtherViewController, your detail view, to save the state of Detail controller.
-(void)encodeRestorableStateWithCoder:(NSCoder *)coder
{
[coder encodeObject:self.selectedRecordId forKey:#"selectedRecordId"];
[super encodeRestorableStateWithCoder:coder];
}
-(void)decodeRestorableStateWithCoder:(NSCoder *)coder
{
self.selectedRecordId = [coder decodeObjectForKey:#"selectedRecordId"];
[super decodeRestorableStateWithCoder:coder];
}
Now this actually doesn't quite work yet. This is because the "ViewDidLoad" method is called on restoration before the decoreRestorablStateWithCoder method is. Hence the title doesn't get set before the view is displayed. To fix this, we handle either set the title for the Detail view controller in viewWillAppear: , or we can modify the viewControllerWithRestorationIdentifierPath method to restore the state when it creates the class like this:
+(UIViewController *) viewControllerWithRestorationIdentifierPath:(NSArray *)identifierComponents coder:(NSCoder *)coder
{
MyOtherViewController *controller = [[self alloc] initWithNibName:nil bundle:nil];
controller.selectedRecordId = [coder decodeObjectForKey:#"selectedRecordId"];
return controller;
}
That's it.
A few other notes...
i presume you did the following in your App Delegate even though i didn't see the code?
-(BOOL) application:(UIApplication *)application shouldSaveApplicationState:(NSCoder *)coder
{
return YES;
}
- (BOOL) application:(UIApplication *)application shouldRestoreApplicationState:(NSCoder *)coder
{
return YES;
}
I saw a bit of flakiness when running the demo code in the simulator with it correctly preserving the Scroll offset. It seemed to work occasionally for me, but not all the time. I suspect this may be because really restoration of MyTableViewController should also use a restorationClass approach, since it's instantiated in code. However I haven't tried that out yet.
My testing method, was to put the app in the background by returning to springboard (required for the app state to be saved.) , then relaunching the app from within XCode to simulate a clean start.
the only problem with your code is navigation controller
these two lines
UINavigationController *navCon = [[UINavigationController alloc] initWithRootViewController:table];
navCon.restorationIdentifier = #"navigationController";
i dont know why navigation controller never get its restoration class. i had the same problem. i found some alternative solution to create a navigation controller stand alone in storyboard and use that.
here is code
UIStoryboard* storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard"
bundle:nil];
UINavigationController* navigationController = [storyboard
instantiateViewControllerWithIdentifier:
#"UINavigationController"];
navigationController.viewControllers = #[myController];
it will work fine .
just follow this http://petr-pavlik.squarespace.com/blog/2013/6/16/stare-restoration-without-storyboard
Since you are doing this in code and not via Storyboard, you will need to provide not only a restorationIdentifier but also a restorationClass to you detail view controller.
You could leave it unassigned in which case -(UIViewController *)application:(UIApplication *)application viewControllerWithRestorationIdentifierPath:(NSArray *)identifierComponents coder:(NSCoder *)coder gets called on the application delegate to make the object (view controller with a restorationIdentifier but no restorationClass).
Try the following (please note the UIViewControllerRestoration protocol):
#interface MyViewController ()<UIViewControllerRestoration>
#end
#implementation
- (id)init
{
self = [super init];
if (self) {
// Custom initialization
}
if( [self respondsToSelector:#selector(restorationIdentifier)] ){
self.restorationIdentifier = #"DetailViewController";
self.restorationClass = [self class];
}
return self;
}
#pragma mark - State restoration
+ (UIViewController *)viewControllerWithRestorationIdentifierPath:(NSArray *)identifierComponents coder:(NSCoder *)coder
{
UIViewController *viewController = [[self alloc] init];
return viewController;
}
#end
Also note that this is a very simple example, usually you might have a lot more interesting things going on in -viewControllerWithRestorationIdentifierPath:coder:

Resources