App crash when view controller with content is pushed - objective-c

UITabBarViewController & UINavigationController & UITableView
My app crashes when I try to push a detail view controller when selecting a cell.
If I empty the detail view controller I am trying to push, it works, but when I add UITextFields and action buttons to the view, the app crashes.
Here is my code:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSUInteger row = [indexPath row];
if(self.addSimpleTrainingVC == nil)
{
AddDetailVC *tempVC = [[AddDetailVC alloc] initWithNibName:#"addDetailVC" bundle:nil];
self.addDetailVC = tempVC;
[tempVC release];
}
addDetailVC.title = [NSString stringWithFormat:#"%#",[myArray objectAtIndex:row]];
[self.navigationController pushViewController:self.addDetailVC animated:YES];
addDetailVC.title = [NSString stringWithFormat:#"%#",[myArray objectAtIndex:row]];
// myAppDelegate *delegate = [[UIApplication sharedApplication] delegate];
// [delegate.myNavBarController pushViewController:addDetailVC animated:YES];
// self.addDetailVC.view.hidden =NO;
// [delegate.myNavBarController pushViewController:addDetailVC animated:YES];
}

If the view is being loaded OK when there are no UI elements, then most probably there must be something wrong at the interface builder side of things. Probably, an outlet/IBAction was defined and it can no longer be found.
The best thing to do is to open the 'Console' application (comes default in a Mac). Then, run your simulator and let the application crash. The Console will let you know what went wrong and will probably provide the source of the error. You might be seeing something like this:
11-08-04 1:02:06 AM StackOverFlow[10840] ** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[UIViewController _loadViewFromNibNamed:bundle:] loaded the "Detail" nib but the view outlet was not set.'*

Related

slide out menu move to another view controller

I followed this great tutorial on a slide out menu using UIKit Dynamics, Slide Out Menu. The code has been slightly modified to reduce duplication of code. I'm handling the touch event in the MenuComponent Class. Now, I'm trying to move to another view controller when the item is selected. The menu is created in code so I can't use segue's.
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
[[tableView cellForRowAtIndexPath:indexPath] setSelected:NO];
[self toggleMenu];
self.isMenuShown = NO;
if(indexPath.row == 0){
//move to the testViewController
}
How do you remove the current view and present a new one? My hierarchy is a navigation controller then my testViewController.
Edit: I did find this code which I tried, but my problem is the when the menu is present and I try to present the view I get an error:
testViewController *test = (testViewController*)[storyboard instantiateViewControllerWithIdentifier:#"testViewController"];
[self presentViewController:test animated:YES completion:nil];
Warning: Attempt to present <testViewController: 0x7c095470> on <MenuComponent: 0x7ae4ce50> whose view is not in the window hierarchy!
I was able to figure it out by creating a delegate for the MenuComponent and then pass the view like so:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UIViewController * test = [storyboard instantiateViewControllerWithIdentifier:#"test"] ;
[delegate didCallViewController:test];

Displaying a subView in didReceiveRemoteNotification?

What Im trying to do is displaying my subView in didReceiveRemoteNotification when the app receives a notification and is running. How can I do this?
My code right now in didReceiveRemoteNotification:
UIApplicationState state = [application applicationState];
if (state == UIApplicationStateActive)
{
AcceptAlertViewCreator *acceptAlertViewCreator = [[AcceptAlertViewCreator alloc] init];
//Here I try to get the current viewController running...
UIViewController *viewController = [[[[UIApplication sharedApplication] keyWindow] subviews] lastObject];
//This line gives me the "Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIView view]: unrecognized selector sent to instance 0x17816b7c0" error
[viewController.view addSubview:[acceptAlertViewCreator createAlertViewWithViewController:viewController andText:[[userInfo objectForKey:#"aps"] objectForKey:#"message"]]];
}
else
{
//other things
}
My AcceptAlertViewCreator returns a UIView and gets a viewController for the viewController to be displayed in and NSString for message. My AcceptAlertViewCreator also has a UIViewAnimation when it is played.
My AcceptAlertViewCreator works great when added to a normal ViewController subView.
Anyone knows how I can accomplish this? Id doesn't have to be adding a subView. It could be a workaround in some ways, or please give me some pointers. Thanks
Instead of getting the viewController from sharedApplication just get the rootViewController of you window
You didReceiveRemoteNotification method should look like this:
UIApplicationState state = [application applicationState];
if (state == UIApplicationStateActive)
{
AcceptAlertViewCreator *acceptAlertViewCreator = [[AcceptAlertViewCreator alloc] init];
[self.window.rootViewController.view addSubview:[acceptAlertViewCreator createAlertViewWithViewController:self.window.rootViewController andText:[NSString stringWithFormat:#"%#", [[userInfo objectForKey:#"aps"] objectForKey:#"message"]]]];
}
else
{
//other things
}
So you are having your AppDelegate display a window when an alert comes in.
I would not add it as a subview, I would just present the view controller instead. I assume you want some action to be taken when this notice comes in.
You could also use NSNotificationCenter to send a notification to your app when the push notification comes in. You trigger the NSNotification from didReceiveRemoteNotification and your app views would need to listen for this notifications. The downside is each view would need to listen for this notification.

unable to create a back button when navigate from a table view to another

this is a newbie question.i ve created a grouped tableview .on clicking the tableview cell it navigates to a new view.but i m unable to create a back button.I even added a navigation bar in the second view of the nib file.but its of no effect..could you guys help me out..below is the screenshot and code of the first view
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// Navigation logic may go here. Create and push another view controller.
if (indexPath.row==0) {
self.dvController1 = [[FirstView alloc] initWithNibName:#"FirstView" bundle:[NSBundle mainBundle]];
[self.navigationController pushViewController:dvController1 animated:YES];
}
if (indexPath.row==1) {
self.dvController2 = [[Tab4 alloc] initWithNibName:#"Tab4" bundle:[NSBundle mainBundle]];
[self.navigationController pushViewController:dvController2 animated:YES];
}
}
In the presented controller add a button with an IBAction in it:
- (IBAction)back:(id)sender {
[self.navigationController popViewControllerAnimated:YES];
}
And make sure that you have a navigationController indeed (meaning that your application needs to be navigation oriented, meaning that you need to instantiate the navigationController property in the application delegate)
In your second view .put this code in viewDidLoad method
self.navigationItem.leftBarButtonItem.title = #"Back";
just hide the bar in the viewWillAppear method & unhide the bar in viewWillDisAppear methods of the tableViewController class. By using
self.navigationController.navigationBarHidden = YES/NO;

How to update DetailView using MasterDetail Application Template

I'm new to using the split view for creating iPad applications. When I first create the project just using the standard MasterDetail Application template (Xcode 4.2), it creates a MasterViewController and a DetailViewController. The template has the following method that is called when a row is selected from the popover table (master detail view controller):
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
if (!self.detailViewController)
{
self.detailViewController = [[DetailViewController alloc] initWithNibName:#"DetailViewController" bundle:nil];
}
[self.navigationController pushViewController:self.detailViewController animated:YES];
Now I understand when you are using a regular navigation controller if you are programing for an iPhone you just do this type of thing to push on another view controller on to the stack. However, with this template, it just pushes the detail view onto the popover rather than updating what is already present. I'm confused as what I need to update to select something from the pop over (master detail view), and then have the detailView update.
Update:
To try and test out the "detailItem" that is already setup for you in the DetailViewController, I commented out the pushViewController and added the following:
//[self.navigationController pushViewController:self.detailViewController animated:YES];
self.detailViewController.detailItem = #"Test";
// setter in detailViewController
- (void)setDetailItem:(id)newDetailItem
{
if (_detailItem != newDetailItem) {
_detailItem = newDetailItem;
// Update the view.
[self configureView];
}
if (self.masterPopoverController != nil) {
[self.masterPopoverController dismissPopoverAnimated:YES];
}
}
- (void)configureView
{
// Update the user interface for the detail item.
// detailDescriptionLabel.text is a IBOutlet to the label on the detailView
if (self.detailItem) {
self.detailDescriptionLabel.text = [self.detailItem description];
}
}
According to this code, the text of the label on the detailViewController should be updated. However, when I do click on the item in the master view controller table, nothing happens.
There are a couple different ways you could do it. First off, like you said, remove the pushViewController call (I don't know why Apple's template does this... maybe just to show you you can?).
Next, let your MasterViewController know about the DetailViewController that is already displayed. I usually set master.detailViewController = detailViewController in the appDelegate.
Remember, the DetailViewController is already being displayed, so you won't always need to realloc it (unless you are replacing it with some other view)
First Option
Use delegate calls to set the information. Declare a protocol to pass information to the detailView and have it display it appropriately. Here is a tutorial describing this in more detail.
Second Option
Pass DetailViewController some data & override the setter to refresh the detailView. Here is a tutorial describing this in more detail.
// in DetailViewController
- (void)setDetailItem:(id)newDetailItem {
if (detailItem != newDetailItem) {
[detailItem release];
detailItem = [newDetailItem retain];
// Update the view.
navigationBar.topItem.title = detailItem;
NSString * imageName = [NSString stringWithFormat:#"%#.png",detailItem];
[self.fruitImageView setImage:[UIImage imageNamed:imageName]];
}
}
Edit: Just looked at the template again, and setDetailItem type code is already in there, but the code is creating a completely new detailView so the detailView that is viewable on the splitViewController is not changed at all.

iPad: SplitViewController with navigation

I'm following Apple sample code "MultipleDetailViews" but what I want to do is that:
at start, shows the RootViewController (table view) display the default detailViewController (1st detailView)
when user selected a table cell, push into the stack, display the SubCategoriesVC (table view) in the master of the splitView but don't update the detailView.
in SubCategoriesVC, selecting a table cell.. update the detailViewController (2nd detailView)
So, in RootViewController.m, I push another navigation
...
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
SubCatVC *browseSubCatView = [[SubCatVC alloc] initWithNibName:#"SubCatVC" bundle:nil];
[self.navigationController pushViewController:browseSubCatView animated:YES];
[browseSubCatView release];
}
Then, in SubCatVC.m
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UIViewController <SubstitutableDetailViewController> *detailViewController = nil;
SecondDetailViewController *newDetailViewController = [[SecondDetailViewController alloc] initWithNibName:#"SecondDetailViewController" bundle:nil];
detailViewController = newDetailViewController;
// Update the split view controller's view controllers array.
NSArray *viewControllers = [[NSArray alloc] initWithObjects:self.navigationController, detailViewController, nil];
self.splitViewController.viewControllers = viewControllers;
[viewControllers release];
// Dismiss the popover if it's present.
if (self.popoverController != nil) {
[self.popoverController dismissPopoverAnimated:YES];
}
// Configure the new view controller's popover button (after the view has been displayed and its toolbar/navigation bar has been created).
if (self.rootPopoverButtonItem != nil) {
[detailViewController showRootPopoverButtonItem:self.rootPopoverButtonItem];
}
[detailViewController release];
[[NSNotificationCenter defaultCenter] postNotificationName:#"updateProduct" object:nil];
}
but it didn't update my detailView.. so I don't know what's wrong?
Src here: http://pastebin.com/iy6SqLqt
Hope someone can advise me. Thanks
I Have not looked at your source, but but a common problem with Split views are delegates.
When you Push a new rootController ont the nav stack, you need to make sure it has the pointer to the detailViewController that you want it to talk to. You can check htis my logging the delegate before you try to update it:
In your SubCatVC (or any root for that matter):
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
//do stuff, init alloc vc's....
NSLog(#"DELEGATE: %#",self.delegate);
//push/delegate etc..
}
If you find its nil, copy the original roots delegate, or when your putting your new detail in, notify/set the root you want to comunicate with it.
If you need any more detail, just ask.