Hopefully someone can help me out. Recently I have been having issues with the animations inside my view. I have been unable to find a solution to it but until now it has been fine as nothing major was going on inside the view, but now I have an alert view showing inside the view after I click a table cell. The alert view comes from the top right hand corner of the screen and goes down the screen and gets bigger with the black background. I just want it to appear without coming down from the right hand top corner. I have always used the same method of showing alert views and never had animation issues before in my views. I will attach a link to the gif below. I will also add the code for the view.
GIF:
https://imgflip.com/gif/x61vg
Track1.h
//
// Track1.h
// uDropOff 3
//
// Created by Curtis Boylan on 06/01/2016.
// Copyright © 2016 Curtis Boylan. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "TableViewCell.h"
#interface Track1 : UIViewController <UITableViewDelegate,UITableViewDataSource>
- (IBAction)back;
#property (weak, nonatomic) IBOutlet UITextField *trackingnumber;
- (IBAction)track;
#property (weak, nonatomic) IBOutlet UITableView *tableViewObject;
#end
Track1.m
//
// Track1.m
// uDropOff 3
//
// Created by Curtis Boylan on 06/01/2016.
// Copyright © 2016 Curtis Boylan. All rights reserved.
//
#import "Track1.h"
#import "TableViewCell.h"
#interface Track1 ()
#end
#implementation Track1
{
NSMutableArray *tableAray;
}
- (void)viewDidLoad {
[super viewDidLoad];
tableAray = [[NSMutableArray alloc] initWithObjects:#"test",#"test2", nil];
// [self webstuff1];
// Do any additional setup after loading the view.
// UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
// [refreshControl addTarget:self action:#selector(handleRefresh:) forControlEvents:UIControlEventValueChanged];
// [self.table addSubview:refreshControl];
}
- (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.
}
*/
- (IBAction)back {
UIStoryboard *sb = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UIViewController *vc = [sb instantiateViewControllerWithIdentifier:#"main"];
[self presentViewController:vc animated:YES completion:NULL];
}
- (IBAction)track {
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
// saving an NSString
[prefs setObject:self.trackingnumber.text forKey:#"uDropOffTracking"];
Track1 *track2 = [self.storyboard instantiateViewControllerWithIdentifier:#"track2"];
[self presentViewController:track2 animated:NO completion:nil];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [tableAray count];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 70;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"TableViewCell";
TableViewCell *cell = (TableViewCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
{
NSArray *nibArray = [[NSBundle mainBundle] loadNibNamed:#"TableViewCell" owner:self options:nil];
cell = [nibArray objectAtIndex:0];
}
cell.tracking.text = [tableAray objectAtIndex:indexPath.row];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UIAlertView *selectedAlert = [[UIAlertView alloc]
initWithTitle:[NSString stringWithFormat:#"%# Selected", [tableAray objectAtIndex:indexPath.row]] message:[NSString stringWithFormat:#"It takes 20 mins to prepare!"] delegate:nil cancelButtonTitle:#"Got It" otherButtonTitles:nil];
[selectedAlert show];
}
#end
Thanks!
Do you use
[UIView beginAnimations: context:];
somewhere in your code?
Make sure call
[UIView commitAnimations];
right after setting animation option.
I have found the solution, along with Vu's answer I done the following in my other view which was displaying track1.
UIStoryboard *sb = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UIViewController *vc = [sb instantiateViewControllerWithIdentifier:#"track1"];
vc.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentViewController:vc animated:YES completion:NULL];}
Changing it to the following and along with the solution Vu had fixed my issues:
UIStoryboard *sb = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UIViewController *vc = [sb instantiateViewControllerWithIdentifier:#"track1"];
[self presentViewController:vc animated:NO completion:NULL];}
Related
I have a UIViewController with a TableView. The TableView is populated with an image and a text for each cell. Now I need to present others Scenes when the user taps a cell. For example:
- tap on first row --> present ViewController1 - tap on second row --> present ViewController2
ViewController1 and ViewController2 are scenes in my Storyboard.
I've tried various solutions, but none of these works. Moreover it seems that the method didSelectRowAtIndexPath: is not called when I tap a cell (for example I tried to show up an alert).
Here the code of my ViewController:
ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
#end
ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
{
NSArray *recipes;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
recipes = [NSArray arrayWithObjects:#"News", #"Calendar",#"Take a photo",#"Draw",#"Mail us",#"Follow us on Facebook", nil];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [recipes count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"SimpleTableCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
cell.textLabel.text = [recipes objectAtIndex:indexPath.row];
if ([cell.textLabel.text isEqualToString:recipes[0]]) {
cell.imageView.image = [UIImage imageNamed:#"newsicon"];
}
else if ([cell.textLabel.text isEqualToString:recipes[1]]) {
cell.imageView.image = [UIImage imageNamed:#"mensaicon"];
}
else if ([cell.textLabel.text isEqualToString:recipes[2]]) {
cell.imageView.image = [UIImage imageNamed:#"fotoicon"];
}
else if ([cell.textLabel.text isEqualToString:recipes[3]]) {
cell.imageView.image = [UIImage imageNamed:#"drawicon"];
}
else if ([cell.textLabel.text isEqualToString:recipes[4]]) {
cell.imageView.image = [UIImage imageNamed:#"mailicon"];
}
else if ([cell.textLabel.text isEqualToString:recipes[5]]) {
cell.imageView.image = [UIImage imageNamed:#"fbicon"];
}
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// here we get the cell from the selected row.
UITableViewCell *selectedCell=[tableView cellForRowAtIndexPath:indexPath];
if ([selectedCell.textLabel.text isEqualToString:recipes[0]]) {
UIAlertView *messageAlert = [[UIAlertView alloc]
initWithTitle:#"Row Selected" message:#"You've selected a row" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
// Display Alert Message
[messageAlert show];
NSString *storyboardName = #"Main";
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:storyboardName bundle: nil];
UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:#"news"];
[self presentViewController:vc animated:YES completion:nil];
}
// use the image in the next window using view controller instance of that view.
}
#end
I'm new to iOS developing, so I don't know if my code is right or if there are other solutions more elegant of these. Anyway, let's focus on the problem, can anyone help me?
If your view is only a table view I'd suggest using a UITableViewController instead of a UIViewController. If you have a UITableView in an existing UIViewController you need to set up the delegate and data source methods yourself.
You can do this in the storyboard. Click on your tableView and then select the connections inspector. Then click the circle next to dataSource and drag it to your view controller. Do the same for delegate. This is probably why your table view methods aren't being called.
If it's a static table, you can create independent segues from each cell in the storyboard.
Moreover it seems that the method didSelectRowAtIndexPath: is not called when I tap a cell (for example I tried to show up an alert).
Your based class is UIViewController, therefore, your UITableViewDelegate and UITableViewDataSource won't get set automatically. You need to do it yourself. For example, you can set them in the init function:
- (instancetype)init {
self = [super init];
if( self ) {
self.delegate = self;
self.datasource = self;
}
return self;
}
An alternative is to use UITableViewController as your base call, then you don't need to worry about setting the delegates.
according to your code alert will only be shown when you click on 1st cell only..
but according to your needs let me write a code for that will help you..
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// here we get the cell from the selected row.
NSString *selectedcelltext=[recipes objectAtIndex:indexPath.row];
UIAlertView *messageAlert = [[UIAlertView alloc]
initWithTitle:#"Row Selected" message:[NSString stringWithFormat:#"You've selected a %# row ",selectedcelltext] delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
// Display Alert Message
[messageAlert show];
if ([selectedcelltext isEqualToString:recipes[0]]) {
NSString *storyboardName = #"Main";
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:storyboardName bundle: nil];
UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:#"news"];
[self presentViewController:vc animated:YES completion:nil];
}
else if ([selectedcelltext isEqualToString:recipes[1]]) {
NSString *storyboardName = #"Main";
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:storyboardName bundle: nil];
UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:#"calendar"];
[self presentViewController:vc animated:YES completion:nil];
}
// use the image in the next window using view controller instance of that view.
}
When I hit an element in my tableView it comes up with an error. I have checked all of the connections but still cant work it out. Here is my code
#import "CGViewController.h"
#import "CGAppDelegate.h"
#import "sls.h"
#import "patientController.h"
#interface CGViewController ()
#end
#implementation CGViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.title = #"Patients";
CGAppDelegate *delegate =
(CGAppDelegate *)[[UIApplication sharedApplication] delegate];
patients = delegate.patients;
self.navigationItem.rightBarButtonItem = self.editButtonItem;
UIBarButtonItem *addButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:#selector(add:)];
self.navigationItem.leftBarButtonItem = addButtonItem;
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark UITableViewDataSource Methods
- (UITableViewCell *)tableView:(UITableView *)tv
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tv dequeueReusableCellWithIdentifier:#"cell"];
if( nil == cell) {
cell = [[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:#"cell"];
}
if (indexPath.row < patients.count) {
sls *thissls = [patients objectAtIndex:indexPath.row];
cell.textLabel.text = thissls.patientName;
}
else {
cell.textLabel.text = #"";
cell.textLabel.textColor = [UIColor lightGrayColor];
}
return cell;
}
-(void)setEditing:(BOOL)editing animated:(BOOL)animated {
if ( editing != self.editing) {
[super setEditing:editing animated:animated];
[self.tableView setEditing:editing animated:animated];
NSArray *indexes =
[NSArray arrayWithObject:
[NSIndexPath indexPathForRow:patients.count inSection:0]];
if ( editing == YES ) {
[self.tableView insertRowsAtIndexPaths:indexes withRowAnimation:UITableViewRowAnimationLeft];
} else {
[self.tableView deleteRowsAtIndexPaths:indexes withRowAnimation:UITableViewRowAnimationLeft];
}
}
[self.tableView reloadData];
}
-(UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row < patients.count ) {
return UITableViewCellEditingStyleDelete;
}
else {
return UITableViewCellEditingStyleNone;
}
}
- (NSInteger)tableView:
(UITableView *)tv numberOfRowsInSection:
(NSInteger)section {
NSInteger count = patients.count;
if (self.editing) {
count = count + 1;
}
return count;
}
-(void)tableView:(UITableView *)tv didSelectRowAtIndexPath:
(NSIndexPath *)indexPath {
CGAppDelegate *delegate =
(CGAppDelegate *)[[UIApplication sharedApplication] delegate];
patientController *patient = [[patientController alloc] init];
[delegate.navController pushViewController:patient animated: YES];
[tv deselectRowAtIndexPath:indexPath animated: YES];
}
-(void) tableView:(UITableView *)tv
commitEditingStyle:(UITableViewCellEditingStyle)editing forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editing == UITableViewCellEditingStyleDelete) {
[patients removeObjectAtIndex:indexPath.row];
[tv deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationLeft];
}
}
#end
Any ideas on what is wrong if you know please can you help as soon as possible as i am on a deadline
Thanks in advance.
The error says Thread 1:signal SIGABRT
The error is in main.m
#import <UIKit/UIKit.h>
#import "CGAppDelegate.h"
int main(int argc, char *argv[])
{
#autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([CGAppDelegate class]));
}
}
it says that the error is here
patientController *patient = [[patientController alloc] init];
here is my patientController.h file
#import <UIKit/UIKit.h>
#interface patientController : UIViewController {
NSIndexPath *index;
IBOutlet UIImageView * pictureView;
IBOutlet UILabel * descriptionView1;
IBOutlet UILabel * descriptionView2;
IBOutlet UILabel * descriptionView3;
}
- (id)initwithIndexPath:(NSIndexPath *)indexPath;
#end
and my .m file
#import "patientController.h"
#import "CGAppDelegate.h"
#import "sls.h"
#interface patientController ()
#end
#implementation patientController
- (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 from its nib.
CGAppDelegate *delegate =
(CGAppDelegate *)[[UIApplication sharedApplication] delegate];
sls *thissls = [delegate.patients objectAtIndex:index.row];
self.title = thissls.patientName;
self->descriptionView1.text = thissls.patientName;
self->descriptionView2.text = thissls.surnameName;
self->descriptionView3.text = thissls.dateOfBirth;
self->pictureView.image = thissls.patientImage;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (id)initwithIndexPath:(NSIndexPath *)indexPath {
if ( (self == [super init]) ) {
index = indexPath;
}
return self;
}
#end
Please can anyone at all help
Use:
[self.navigationController pushViewController:patient animated: YES];
If you are currently in a navigationController (which you have to in order to push a new ViewController), then you can push your new controller by just calling these lines
-(void)tableView:(UITableView *)tv didSelectRowAtIndexPath:
(NSIndexPath *)indexPath {
patientController *patient = [[patientController alloc] init];
[self.navigationController pushViewController:patient animated: YES];
}
Use
[self.navController pushViewController:patient animated: YES];
Every viewcontroller has its navigation controller reference in itself,no need to call the application delegate to invoke it[The navigation controller Must be initialised and all the viewcontrollers must be pushed into the navigation stack until this one to make it work]
So use this to setup the navigation controller in the appdelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//Note : this is an example set like this with your viewcontroller instance
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
self.viewController = [[ViewController alloc] initWithNibName:#"ViewController_iPhone" bundle:nil];
} else {
self.viewController = [[ViewController alloc] initWithNibName:#"ViewController_iPad" bundle:nil];
}
self.window.rootViewController = [[UINavigationController alloc] initWithRootViewController:self.viewController];
[self.window makeKeyAndVisible];
return YES;
}
To check where your exception is raised, in Xcode, in the breakpoints navigation tab click on the plus button in the bottom-left corner and add an Exceptions Breakpoint. Then run the app from Xcode. The next time an exception is raised, as in your case, the execution of your app will stop and Xcode will point at the line of code where the exception is raised.
Anyway, to make you understand how navigationControllers work:
UINavigationController is a UIViewController that controls a stack of other UIViewController instances. This other view controllers are said to be in the 'navigation stack'. The top item in the navigation stack is the view controller whose view you see at a given time onto the screen. You can push (present) or pop (dismiss) a view controller on/from the navigation stack.
A UINavigationController is initialized with a 'rootViewController' which is going to be it's first view controller onto the stack and therefore the first you see when you add the navigationController onto the screen (e.g. by setting it as the appDelegate window's rootViewController). Each UIViewController on the navigation stack references it's navigationController through the property 'navigationController'.
At any given point, you can use the UINavigationController methods pushViewController:animated: and popViewControllerAnimated: or popToViewController:animated: or popToRootViewControllerAnimated: to add or remove viewControllers from the navigationStack. To see the results of this methods, of course, you should have the navigationController on screen.
For more informations refer to the UINavigationController Class Reference.
I have made simple cocoa touch apps before but I have never used UINavigationControllers, any advice would be greatly appreciated.
I'm trying to add an array of a list of store names to a UITableView. The UITableView is accessed through a UINavigation controller by a tab on a tab bar.
I have a TabBarController.xib file that holds the tab bar.
I also have a AtoZNavigationController.xib that holds the UINavigationController.
And I have a AtoZTableController.xib file that holds the UITableView.
This is my AppDelegate.h:
#import <UIKit/UIKit.h>
#class AtoZNavigationController;
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (strong, nonatomic) IBOutlet UITabBarController *rootController;
#property (strong, nonatomic) IBOutlet AtoZNavigationController *navController;
#end
The AppDelegate.m
#import "AppDelegate.h"
#import "AtoZNavigationController.h"
#implementation AppDelegate
#synthesize window = _window;
#synthesize rootController;
#synthesize navController;
#pragma mark -
#pragma mark Application lifecycle
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions: (NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
[[NSBundle mainBundle] loadNibNamed:#"TabBarController" owner:self options:nil];
[self.window addSubview:rootController.view];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
#end
The AtoZNavigationController.h
#import <UIKit/UIKit.h>
#interface AtoZNavigationController : UINavigationController
#end
The AtoZNavigationController.m
#import "AtoZNavigationController.h"
#interface AtoZNavigationController ()
#end
#implementation AtoZNavigationController
-(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 from its nib.
}
-(void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#end
The AtoZTableController.h
#import <UIKit/UIKit.h>
#interface AtoZTableController : UITableViewController <UITableViewDelegate, UITableViewDataSource>
{
IBOutlet UITableView *AtoZTableView;
NSMutableArray *AtoZArray;
}
#property (nonatomic, retain) IBOutlet UITableView *AtoZTableView;
#end
The AtoZTableController.h
#import "AtoZTableController.h"
#interface AtoZTableController ()
#end
#implementation AtoZTableController
#synthesize AtoZTableView;
-(id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
-(void)viewDidLoad
{
[super viewDidLoad];
self.title = NSLocalizedString(#"A to Z", #"An A to Z List of Stores");
AtoZArray = [[NSMutableArray alloc] init];
[AtoZArray addObject:#"Apple"];
[AtoZArray addObject:#"Boots"];
[AtoZArray addObject:#"Topman"];
}
-(void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#pragma mark - Table view data source
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 0;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [AtoZArray count];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// Configure the cell...
NSInteger row = [indexPath row];
cell.textLabel.text = [AtoZArray objectAtIndex:row];
return cell;
}
#pragma mark - Table view delegate
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Navigation logic may go here. Create and push another view controller.
/*
<#DetailViewController#> *detailViewController = [[<#DetailViewController#> alloc] initWithNibName:#"<#Nib name#>" bundle:nil];
// ...
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:detailViewController animated:YES];
*/
}
#end
In your AtoZTableController.h, you have a problem.
The problem is in your 'tableView:cellForRowAtIndexPath:' method.
Here's what you have:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// Configure the cell...
NSInteger row = [indexPath row];
cell.textLabel.text = [AtoZArray objectAtIndex:row];
return cell;
}
The problem is that you never handle for a return value of nil from dequeueReusableCellWithIdentifier:CellIdentifier.
Try this out:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// What happens if you don't get a cell to use?
// This is the way to create a new, default UITableViewCell
if (!cell) {
// You can look at the UITableViewCell class reference to see the 4 available styles
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Configure the cell...
NSInteger row = [indexPath row];
cell.textLabel.text = [AtoZArray objectAtIndex:row];
return cell;
}
Edit/Update:
OK, so it's a little bit difficult to know exactly where your error is, so I'll set up/describe for you a typical situation (or how I'd do it in your shoes).
If you create a new app and select the "Tabbed Application" template in Xcode, you get the following method in your app delegate (more or less; I condensed it a little bit and "fixed" Apple's poor choice to use dot notation):
Note: I believe the problem you're having with pushing a new view controller will be fixed below now...End Note
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[self setWindow:[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]];
// Override point for customization after application launch.
UIViewController *vc1 = [[FirstViewController alloc] initWithNibName:#"FirstVC" bundle:nil];
// New line...
UINavigationController *navC = [[UINavigationController alloc] initWithRootViewController:vc1];
UIViewController *vc2 = [[SecondViewController alloc] initWithNibName:#"SecondVC" bundle:nil];
[[self setTabBarController:[[UITabBarController alloc] init]];
// Change here, too...
[[self tabBarController] setViewControllers:[NSArray arrayWithObjects:navC, vc2, nil]];
[[self window] setRootViewController:[self tabBarController]];
[[self window] makeKeyAndVisible];
return YES;
}
This method sets up all you need to launch your app with 2 UIViewControllers created and set as tab 1 and tab 2 inside of a UITabBarController.
Now, you can make FirstViewController and SecondViewController be whatever you want. For purposes of this question, we'll assume that you want to alter FirstViewController to host a UITableView, which will push a detail UIViewController when a user selects a row on the screen.
Requirements
EITHER FirstViewController must be a subclass of UITableViewController (this is not what the default template provides) OR you must add a UITableView onto FirstViewController's view and set up all of the connections.
Let's assume you're going to keep FirstViewController as a standard UIViewController subclass and that you'll add a UITableView onto its view. (I'd probably change it to a UITableViewController subclass, but that might be more confusing at this point.)
First, in FirstViewController.h, change this:
#interface MMFirstViewController : UIViewController
#end
to this:
#interface MMFirstViewController : UIViewController <UITableViewDataSource, UITableViewDelegate> {
UITableView *TableView;
}
#property (strong, nonatomic) IBOutlet UITableView *TableView;
#end
Next, in FirstViewController.m, synthesize the TableView property (#synthesize TableView).
Next, click on FirstViewController.xib in Xcode to have it load up in Interface Builder (I'm assuming here that you're using Xcode 4).
Now, drag a UITableView from the controls panel onto your UIViewController's view.
Make the following connections in Interface Builder:
Right click on File's Owner and connect the TableView property to the UITableView you dropped on the view of FirstViewController.
Right click on the UITableView and connect BOTH the datasource AND delegate properties to File's Owner.
Now, the code you posted initializing and populating AtoZArray should work fine. Don't forget to copy in the 3 UITableView methods you previously had, numberOfSectionsInTableView:, tableView:numberOfRowsInSection: and tableView:cellForRowAtIndexPath:.
Those steps should get you working and should also let you see where you perhaps went wrong in your setup. Please note, you'll still have to figure out tableView:didSelectRowAtIndexPath: on your own in order to push in your new UIViewController.
Here's a teaser to get you started:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Navigation logic may go here. Create and push another view controller.
ThirdViewController *detailVC = [[ThirdViewController alloc] initWithNibName:#"ThirdViewController" bundle:nil];
[[self navigationController] pushViewController:detailVC animated:YES];
}
I had to create an instance of the navigationController and pass that into the subview in my appDelegate.m along with the tabBarController. It can then later be referenced in my UITableViewController.
Here's the code I added:
navigationController = [[UINavigationController alloc] initWithRootViewController:_tabBarController];
[self.window addSubview:_tabBarController.view];
[self.window addSubview:navigationController.view];
[self.window makeKeyAndVisible];
Where navigationController is simply an instance of a subclass of either UITableViewController or UIViewController, depending on what type of screen you want to display.
I am using Apple's MuiltipleDetailViewController sample app and get the message "UIViewController may not respond to showRootPopoverButtonItem"
This worked in XCode 3.X, but I get the message with 4.2
The app itself functions 100%, the popover is recognized in every nib, as is the table on the left when in landscape mode. But I can't submit with this warning. What do I need to change??
RootViewController.h
#import <UIKit/UIKit.h>
/*
SubstitutableDetailViewController defines the protocol that detail view controllers must adopt. The protocol specifies methods to hide and show the bar button item controlling the popover.
*/
#protocol SubstitutableDetailViewController <NSObject>
- (void)showRootPopoverButtonItem:(UIBarButtonItem *)barButtonItem;
- (void)invalidateRootPopoverButtonItem:(UIBarButtonItem *)barButtonItem;
#end
#interface RootViewController : UITableViewController <UISplitViewControllerDelegate> {
UISplitViewController *splitViewController;
UIPopoverController *popoverController;
UIBarButtonItem *rootPopoverButtonItem;
//UINavigationBar *navigationBar;
}
#property (nonatomic, assign) IBOutlet UISplitViewController *splitViewController;
#property (nonatomic, retain) UIPopoverController *popoverController;
#property (nonatomic, retain) UIBarButtonItem *rootPopoverButtonItem;
//#property (nonatomic, retain) IBOutlet UINavigationBar *navigationBar;
#end
RootViewController.m:
#import "RootViewController.h"
#import "WebViewController.h"
#import "Twitter.h"
//#import "SubstitutableDetailViewController.h"
#implementation RootViewController
#synthesize splitViewController, popoverController, rootPopoverButtonItem;//, navigationBar;
#pragma mark -
#pragma mark View lifecycle
- (void)viewDidLoad {
[super viewDidLoad];
// Set the content size for the popover: there are just two rows in the table view, so set to rowHeight*2.
self.contentSizeForViewInPopover = CGSizeMake(310.0, self.tableView.rowHeight*2.0);
//self.navigationController.navigationBar.tintColor = [UIColor colorWithRed:255/255 green:104/255 blue:1/255 alpha:1];
}
/*
-(void)customizeAppearance {
//create resizable images
UIImage *bluImage = [UIImage imageNamed:#"blu.jpg"];// resizableImageWithCapInsets:(0, 0, 0, 0)];
//set the bg for *all* UINavBars
[[UINavigationBar appearance] setBackgroundImage:bluImage forBarMetrics:UIBarMetricsDefault];
}
*/
-(void) viewDidUnload {
[super viewDidUnload];
self.splitViewController = nil;
self.rootPopoverButtonItem = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
- (void)splitViewController:(UISplitViewController*)svc willHideViewController:(UIViewController *)aViewController withBarButtonItem:(UIBarButtonItem*)barButtonItem
forPopoverController:(UIPopoverController*)pc {
// Keep references to the popover controller and the popover button, and tell the detail view controller to show the button.
barButtonItem.title = #"Index";
self.popoverController = pc;
self.rootPopoverButtonItem = barButtonItem;
UIViewController <SubstitutableDetailViewController> *detailViewController = [splitViewController.viewControllers objectAtIndex:1];
[detailViewController showRootPopoverButtonItem:rootPopoverButtonItem];
}
- (void)splitViewController:(UISplitViewController*)svc willShowViewController:(UIViewController *)aViewController
invalidatingBarButtonItem:(UIBarButtonItem *)barButtonItem {
// Nil out references to the popover controller and the popover button, and tell the detail view controller to hide the button.
UIViewController <SubstitutableDetailViewController> *detailViewController = [splitViewController.viewControllers objectAtIndex:1];
[detailViewController invalidateRootPopoverButtonItem:rootPopoverButtonItem];
self.popoverController = nil;
self.rootPopoverButtonItem = nil;
}
#pragma mark -
#pragma mark Table view data source
- (NSInteger)tableView:(UITableView *)aTableView numberOfRowsInSection:(NSInteger)section {
// Two sections, one for each detail view controller.
return 2;
}
- (UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"RootViewControllerCellIdentifier";
// Dequeue or create a cell of the appropriate type.
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
//cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
}
// Set appropriate labels for the cells.
if (indexPath.row == 0) {
cell.textLabel.text = #"Twitter";
}
else if (indexPath.row == 1) {
cell.textLabel.text = #"Contact Us";
}
cell.textLabel.textColor = [UIColor whiteColor];
cell.textLabel.backgroundColor = [UIColor blackColor];
cell.contentView.backgroundColor = [UIColor blackColor];
cell.detailTextLabel.backgroundColor = [UIColor blackColor];
return cell;
}
#pragma mark -
#pragma mark Table view selection
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
/*
Create and configure a new detail view controller appropriate for the selection.
*/
NSUInteger row = indexPath.row;
UIViewController *detailViewController = nil;
if (row == 0) {
Twitter *newDetailViewController = [[Twitter alloc]
initWithNibName:#"Twitter"
bundle:nil];
detailViewController = newDetailViewController;
}
if (row == 1) {
WebViewController *newDetailViewController = [[WebViewController alloc]
initWithNibName:#"WebViewController"
bundle:nil];
newDetailViewController.detailURL=
[[NSURL alloc] initWithString:#"http://www.chipmunkmobile.com/contact.html"];
detailViewController = newDetailViewController;
}
// Update the split view controller's view controllers array.
NSArray *viewControllers = [[NSArray alloc] initWithObjects:self.navigationController, detailViewController, nil];
splitViewController.viewControllers = viewControllers;
[viewControllers release];
// Dismiss the popover if it's present.
if (popoverController != nil) {
[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 (rootPopoverButtonItem != nil) {
[detailViewController showRootPopoverButtonItem:self.rootPopoverButtonItem];
}
[detailViewController release];
}
#pragma mark -
#pragma mark Managing the popover
/*
- (void)showRootPopoverButtonItem:(UIBarButtonItem *)barButtonItem {
// Add the popover button to the left navigation item.
[navigationBar.topItem setLeftBarButtonItem:barButtonItem animated:NO];
}
- (void)invalidateRootPopoverButtonItem:(UIBarButtonItem *)barButtonItem {
// Remove the popover button.
[navigationBar.topItem setLeftBarButtonItem:nil animated:NO];
}
*/
#pragma mark -
#pragma mark Memory management
- (void)dealloc {
[popoverController release];
[rootPopoverButtonItem release];
[super dealloc];
}
#end
Here is an image of the exact line where I get the warning
The reason you getting this warning is because of this UIViewController *detailViewController UIViewController does not have a method called "showRootPopoverButtonItem". If you want to get rid of the warning just do this instead:
[(WebViewController*)detailViewController showRootPopoverButtonItem:self.rootPopoverButtonItem];
or
[(Twitter*)detailViewController showRootPopoverButtonItem:self.rootPopoverButtonItem];
You just need to let it know its not really just a viewController, its a subclassed viewController you created. So what ever class showRootPopoverButtonItem: is in you just need to type cast it.
If you want to leave your code exactly the same but get rid of the warning you can do this.
if (rootPopoverButtonItem != nil) {
[detailViewController performSelector:#selector(showRootPopoverButtonItem:) withObject:self.rootPopoverButtonItem];
}
If you want to be more careful you should use this.
if (rootPopoverButtonItem != nil && [detailViewController respondsToSelector:#selector(showRootPopoverButtonItem:)]) {
[detailViewController performSelector:#selector(showRootPopoverButtonItem:) withObject:self.rootPopoverButtonItem];
}
Update
After reading through your code you could just specify the delegate on the detailViewController like you did in the other functions.
UIViewController<SubstitutableDetailViewController> *detailViewController = nil;
if (row == 0) {
//...
(1)Specify the Type for the detailedViewController: [(TYPE *)OBJECTNAME...
(2) Then Specify method call [(TYPE *)OBJECTNAME METHODCALL];
(*) You get the warning because the compiler does not know what type of object you are using. If you subclass a UIViewController then you have to specify type when accessing methods.Make sure the method is in .h so that you can access it.
I'm trying to get my data to load in my detail view. Can any one take a look and see why it isnt showing? It loads fine in my rootviewcontroller, just not the detail view.
DetailViewController.m
#import "DetailViewController.h"
#implementation DetailViewController
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
// Release anything that's not essential, such as cached data
}
- (void)setIcon:(UIImage *)newIcon
{
[super setIcon:newIcon];
iconView.image = newIcon;
}
- (void)setPublisher:(NSString *)newPublisher
{
[super setPublisher:newPublisher];
publisherLabel.text = newPublisher;
}
- (void)setName:(NSString *)newName
{
[super setName:newName];
nameLabel.text = newName;
}
- (void)dealloc
{
[iconView release];
[publisherLabel release];
[nameLabel release];
[priceLabel release];
[super dealloc];
}
#end
detailviewcontroller.h
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#interface DetailViewController : UIViewController {
IBOutlet UIImageView *iconView;
IBOutlet UILabel *publisherLabel;
IBOutlet UILabel *nameLabel;
IBOutlet UILabel *priceLabel;
}
#end
RootViewControllerPoints.m
#import "RootViewControllerPoints.h"
#import "DetailViewController.h"
#define USE_INDIVIDUAL_SUBVIEWS_CELL 1
#define DARK_BACKGROUND [UIColor colorWithRed:151.0/255.0 green:152.0/255.0 blue:155.0/255.0 alpha:1.0]
#define LIGHT_BACKGROUND [UIColor colorWithRed:172.0/255.0 green:173.0/255.0 blue:175.0/255.0 alpha:1.0]
#implementation RootViewController
#synthesize tmpCell, data;
#pragma mark View controller methods
- (void)viewDidLoad
{
[super viewDidLoad];
// Configure the table view.
self.tableView.rowHeight = 73.0;
self.tableView.backgroundColor = DARK_BACKGROUND;
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
// Load the data.
NSString *dataPath = [[NSBundle mainBundle] pathForResource:#"Data" ofType:#"plist"];
self.data = [NSArray arrayWithContentsOfFile:dataPath];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
switch (toInterfaceOrientation) {
case UIInterfaceOrientationPortrait:
case UIInterfaceOrientationLandscapeLeft:
case UIInterfaceOrientationLandscapeRight:
return YES;
default:
return NO;
}
}
#pragma mark Table view methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [data count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"ApplicationCell";
ApplicationCell *cell = (ApplicationCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
#if USE_INDIVIDUAL_SUBVIEWS_CELL
[[NSBundle mainBundle] loadNibNamed:#"IndividualSubviewsBasedApplicationCell" owner:self options:nil];
cell = tmpCell;
self.tmpCell = nil;
#endif
}
// Display dark and light background in alternate rows -- see tableView:willDisplayCell:forRowAtIndexPath:.
cell.useDarkBackground = (indexPath.row % 2 == 0);
// Configure the data for the cell.
NSDictionary *dataItem = [data objectAtIndex:indexPath.row];
cell.icon = [UIImage imageNamed:[dataItem objectForKey:#"Icon"]];
cell.publisher = [dataItem objectForKey:#"Publisher"];
cell.name = [dataItem objectForKey:#"Name"];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
DetailViewController *detailViewController = [[DetailViewController alloc] initWithNibName:#"DetailView" bundle:nil];
detailViewController. = [data objectAtIndex:indexPath.row];
[self.navigationController pushViewController:detailViewController animated:YES];
[detailViewController release];
}
#end
This has been bugging me for quite a while, I've looked at numerous examples, tutorials and even asked other iphone devs. Everything source seems to say something different.
First problem is that the setXXX methods in DetailViewController try to make calls to super setXXX but since DetailViewController is a subclass of UIViewController those calls to super will fail because UIViewController doesn't have such methods. Remove the calls to super in the setXXX methods.
Second problem is that the setXXX methods are setting the controls on the DetailViewController directly but the controls won't be accessible until the view is loaded so it won't work if the methods are called before the pushViewController call.
If you change the code in didSelectRowAtIndexPath as follows it should work:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
DetailViewController *detailViewController = [[DetailViewController alloc] initWithNibName:#"DetailView" bundle:nil];
[self.navigationController pushViewController:detailViewController animated:YES];
[detailViewController setName:#"name here"];
[detailViewController setPublisher:#"publisher here"];
[detailViewController setIcon:yourImageVariableHere];
[detailViewController release];
}
Although the above change should work, you might want to consider creating ivars to hold the values in DetailViewController (instead of using the ui controls themselves to hold the data). Then create properties for them using #property and #synthesize. The properties can be set immediately after DetailViewController is created and in the viewDidLoad of the view, you can set the ui controls to the property values. This will give the DetailViewController more control over how its ui is updated, allow you to change the ui without affecting callers, and it doesn't need to be displayed to set its properties.