I'm following a textbook and it's a bit outdated so I ended up mixing my code with it.
Its a basic app that populates a table view with Cities (london,san francisco,sydney and madrid) and upon clicking it, It should open up a detail view that should display the city as its title and an image of the city with the description, somehow even if I click any cell it shows me "London" with London's picture and description.
Here's my code
ViewController.m
#import "ViewController.h"
#import "City.h"
#import "AppDelegate.h"
#import "CityController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
AppDelegate *appDelegate = (AppDelegate*)[[UIApplication sharedApplication]delegate];
citys = appDelegate.cities;
}
#pragma mark - UITableViewDataSource Methods
- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
if(cell == nil){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"];
}
City *theCity = [citys objectAtIndex:indexPath.row];
cell.textLabel.text = theCity.cityName;
return cell;
}
- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return [citys count];
}
#pragma mark - UITableViewDelegate Methods
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
#end
CityController.m (the detail View)
#import "CityController.h"
#import "AppDelegate.h"
#import "City.h"
#implementation CityController
- (id) initWithIndexPath:(NSIndexPath *)indexPath{
if((self = [super init])){
index = indexPath;
}
return self;
}
- (void) viewDidLoad{
[super viewDidLoad];
AppDelegate *delegate = [[UIApplication sharedApplication]delegate];
City *thisCity = [delegate.cities objectAtIndex:index.row];
self.title = thisCity.cityName;
labelDescription.text = thisCity.cityDescription;
//descriptionView.editable = NO;
pictureView.image = thisCity.cityImage;
}
#end
City.h
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#interface City : NSObject
#property (nonatomic, strong) NSString *cityName;
#property (nonatomic, strong) NSString *cityDescription;
#property (nonatomic, strong) UIImage *cityImage;
#end
You don't show in your code how you are calling this method on your CityController
- (id) initWithIndexPath:(NSIndexPath *)indexPath
Therefore indexPath.row in CityController will always be zero which I'm assuming is the first entry in the cities that relates to London
You need to do something in this method to set the indexPath correctly for the CityController
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
Are you using Storyboards?
Your code must be,
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
CityController *cityVC = [[CityController alloc] initWithIndexPath:indexPath];
[[self view] addSubview:[cityVC view]];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
Related
I have a UIViewController and a UITableViewController.
In ViewController I have a UIButton and UITextfield, when I press button it will navigate to TableViewController with static data in the tableview like (iPhone 5S, iPhone 6, iPhone 6S, iPhone 7), when I select any of the row it should be displayed in the textfield of ViewController. Tried but cannot get this one. Help me to solve this. below is my code:
ViewController.h
————————————————
#import <UIKit/UIKit.h>
#import "Utility.h"
#interface ViewController : UIViewController
- (IBAction)oneButtonClicked:(id)sender;
#property (strong, nonatomic) IBOutlet UITextField *txtOne;
ViewController.m
————————————————
//Can't understand what to do in this viewcontroller.
TableViewController.h
—————————————————————-
#import <UIKit/UIKit.h>
#import "Utility.h"
#interface FamilyDetailsViewController : UITableViewController
#end
TableViewController.m
—————————————————————-
#import "FamilyDetailsViewController.h"
#interface FamilyDetailsViewController ()
{
NSArray *arr;
}
#end
#implementation FamilyDetailsViewController
- (void)viewDidLoad {
[super viewDidLoad];
arr=[[NSArray alloc]initWithObjects:#"Parent",#"Grandparent",#"Sibling",#"Child",#"Other", nil];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [arr count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.textLabel.text=[arr objectAtIndex:indexPath.row];
return cell;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[self.navigationController popViewControllerAnimated:YES];
}
in `ViewControllerB.h` which is a TableViewController declare a delegate to pass the data to ViewControllerA and create a delegate object
#import <UIKit/UIKit.h>
#protocol DataDelegate <NSObject>
- (void)passData:(NSString *)data;
#end
#interface ViewControllerB : UIViewController
#property (weak, nonatomic) id<DataDelegate> delegate;
#end
in ViewControllerB.m file
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *selectedText = titleArray[indexPath.row];
if [self.delegate respondsToSelector:#selector(passData:)]) {
[self.delegate passData:"hello"];
}
[self.navigationController popViewControllerAnimated:YES];
}
**in ViewControllerA**
#import "ViewControllerA.h"
#import "ViewControllerB.h"
#interface ViewControllerA () <DataDelegate>
#property (strong, nonatomic) ViewControllerB *viewControllerB;
#end
#implementation ViewControllerA
- (void)viewDidLoad {
_viewControllerB.delegate = self;
}
- (void)passData:(NSString *)data {
self.textField.text = data
}
Try Using NSNotification. Pass data back to ViewController with NSNotification. First register a notification in viewWillAppear of ViewController.
Try below code:
In ViewController:
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:YES];
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(getTextFromTable:) name:#"PassTextBackToViewController" object:nil];
}
Then define Method in ViewController like this:
-(void)getTextFromTable:(NSNotification *)notification
{
[self.textField setText:[notification.userInfo valueForKey:#"cellText"]];
}
And in tableView's didSelectRowAtIndexPath method, Post the notification:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell=[tableView cellForRowAtIndexPath:indexPath];
NSDictionary *dictionary=[NSDictionary dictionaryWithObjectsAndKeys:cell.textLabel.text,#"cellText", nil]
[[NSNotificationCenter defaultCenter]postNotificationName:#"PassTextBackToViewController" object:dictionary];
[self.navigationController popViewControllerAnimated:YES];
}
Make Sure, Notification's name must be same in both ViewController and
TableViewController
Follow this:
In AppDelegate.h
#property (strong, nonatomic) NSString *selectedText;
In ViewController.m
-(void)viewWillAppear:(BOOL)animated
{
AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
txtOne.text = appDelegate.selectedText;
}
Make appDelegate.selectedText = #"" while navigating to UITableViewController Class.
In FamilyDetailsViewController.m
pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *selected= [arr objectAtIndex:indexPath.row];
AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
appDelegate.selectedText = selected;
[self.navigationController popViewControllerAnimated:YES];
}
In this way you are storing selected value in Singleton class.(App delegate). You can fetch data from this in ViewController(viewWillAppear).
I have a view controller with a static cell named 'Make' I have two controllers one called "AddCarTableViewController" and "MakeTableViewController" when you click on the static cell named 'Make' it presents the make table view controller where you can select the make, then pops the view controller and am trying to store the selected value in the detailTextLabel of the static cell. here is my code for all the controllers.
The problem I'm having is once I select the make everything happens as it should I even log the selected item and it saves it after popping the view controller, but I can't figure out how to implement selected item into the detailTextLabel. Any help will be much appreciated!
"MakeTableViewController.h"
#import <UIKit/UIKit.h>
#import "AddCarTableViewController.h"
#protocol CarMakeDelegate <NSObject>
- (void)updateCarMake:(NSString *)updateMake;
#end
#interface MakeTableViewController : UITableViewController
#property (nonatomic, strong) NSArray *carMakes;
#property (nonatomic, weak) id <CarMakeDelegate> delegate;
#end
MakeTableViewController.m
#import "MakeTableViewController.h"
#interface MakeTableViewController ()
#end
#implementation MakeTableViewController {
NSIndexPath *oldIndexPath;
}
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.carMakes = [[NSArray alloc] initWithObjects:#"Acura", #"Aston Martin", nil];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [self.carMakes count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
cell.textLabel.text = [self.carMakes objectAtIndex:indexPath.row];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:NO];
oldIndexPath = indexPath;
NSString *addMake = self.carMakes[indexPath.row];
[self.delegate updateCarMake:addMake];
NSLog(#"%#", addMake );
[[self navigationController] popViewControllerAnimated:YES];
}
#end
AddCarTableViewController.h
#import <UIKit/UIKit.h>
#import "MakeTableViewController.h"
#interface AddCarTableViewController : UITableViewController
#property (strong, nonatomic) NSString *makeName;
#property (weak, nonatomic) IBOutlet UITableViewCell *makeCell;
#end
AddCarTableViewController.m
#import "AddCarTableViewController.h"
#interface AddCarTableViewController ()
#end
#implementation AddCarTableViewController
- (void)viewDidLoad
{
[super viewDidLoad];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return 4;
}
-(void)updateCarMake:(NSString *)updateMake {
self.makeCell.detailTextLabel.text = updateMake;
}
#end
You don't need to use delegate in this case. Just update the underlying data model. and call
[tableview reloadData];
When the makeViewController is popped.
In the AddCarVC's cellForRowAtIndex, add another line to check if current indexPath corresponds to Make cell and if it does update the detailLabel text.
I currently have a MatchCenterViewController that I want to programmatically turn into a UITableViewController. I've attempted to do so below based on tutorials I've found, but it doesn't seem to be appearing.
MatchCenterViewController.m:
#import "MatchCenterViewController.h"
#import <UIKit/UIKit.h>
#interface MatchCenterViewController () <UITableViewDataSource, UITableViewDelegate>
#end
#implementation MatchCenterViewController
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"newFriendCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"newFriendCell"];
if (cell == nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
//etc.
return cell;
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
#end
As a minimum, you need to implement the following methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
And you need to set the delegate and datasource, typically in viewDidLoad
- (void)viewDidLoad
{
[super viewDidLoad];
self.tableView.dataSource = self;
self.tableView.delegate = self;
}
Also, you need an IBOutlet to the table view if the table view was created in storyboard, or a property for the table view, if the table view was created in code.
I'm just going to be crazy. I want to display some attributes from an object in a TableViewController.
To resume :
I've got a first screen with a list of different Aircraft. Each Aircraft is different and get 2 attributes (a name and an identification number). When i click on an aircraft i want to display its informations in a new view controller (here a TableViewController).
The only thing i get is an empty string... I don't understand how to do this.
Here my code for AircraftViewController.h (the list of different aircraft)
#import <UIKit/UIKit.h>
#import "AircraftInfoViewController.h"
#interface AircraftViewController : UITableViewController <AircraftInfoViewControllerDelegate>
#property (nonatomic, strong) NSMutableArray *aircraft;
#end
Here my code for AircraftViewController.m
#import "AircraftViewController.h"
#import "Aircraft.h"
#interface AircraftViewController ()
#end
#implementation AircraftViewController
{
NSString *_info;
}
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [self.aircraft count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
AircraftCell *cell = (AircraftCell *)[tableView dequeueReusableCellWithIdentifier:#"AircraftCell"];
Aircraft *aircraft = (self.aircraft)[indexPath.row];
cell.immatLabel.text = aircraft.immat;
return cell;
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"PickInfo"]) {
AircraftInfoViewController *aircraftInfoViewController = segue.destinationViewController;
aircraftInfoViewController.delegate = self;
aircraftInfoViewController.info = _info;
}
}
- (void)aircraftInfoViewController:(AircraftInfoViewController *)controller didSelectInfo:(NSString *)info
{
_info = info;
Aircraft *aircraft = [[Aircraft alloc] init];
// Here is my problem !
NSLog(#"String is %#", aircraft.name);
[self.navigationController popViewControllerAnimated:YES];
}
#end
Here my Aircraft Object
#import <Foundation/Foundation.h>
#interface Aircraft : NSObject
#property (nonatomic, copy) NSString *name;
#property (nonatomic, copy) NSString *immat;
#end
Here my AircraftInfoViewController.h (where i display info)
#class AircraftInfoViewController;
#protocol AircraftInfoViewControllerDelegate <NSObject>
- (void)aircraftInfoViewController:(AircraftInfoViewController *)controller didSelectInfo:(NSString *)info;
#end
#interface AircraftInfoViewController : UITableViewController
#property (nonatomic, weak) id <AircraftInfoViewControllerDelegate> delegate;
#property (nonatomic, strong) NSString *info;
#end
Here my AircraftInfoViewController.m
#import "AircraftInfoViewController.h"
#interface AircraftInfoViewController ()
#end
#implementation AircraftInfoViewController
{
NSArray *_infos;
NSUInteger _selectedIndex;
}
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
_infos = #[#"TEST"];
_selectedIndex = [_infos indexOfObject:self.info];
}
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [_infos count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"AircraftCell"];
cell.textLabel.text = _infos[indexPath.row];
if (indexPath.row == _selectedIndex) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
} else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
if (_selectedIndex != NSNotFound) {
UITableViewCell *cell = [tableView cellForRowAtIndexPath:
[NSIndexPath indexPathForRow:_selectedIndex inSection:0]];
cell.accessoryType = UITableViewCellAccessoryNone;
}
_selectedIndex = indexPath.row;
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
NSString *info = _infos[indexPath.row];
[self.delegate aircraftInfoViewController:self didSelectInfo:info];
}
#end
Thx for helping...
I don't exactly get your problem, but in your code you are:
//1. creating a new aircraft
Aircraft *aircraft = [[Aircraft alloc] init];
//2. this aircraft object is new and dose not have a name yet as you never assigned a name to it.
//3. this is why your log shows an empty string
NSLog(#"String is %#", aircraft.name);
Looks like you need to print the info:
NSLog(#"String is %#", _info);
But it will be helpful to help you if you could explain what you want to get better.
I have two view controllers in tab bar controller. ViewControllerA has two buttons (MybuttonA and MybuttonB with enabled box unchecked in storyboard). ViewControllerB is a TableViewController. I would like to enable buttons in ViewControllerA upon selecting specific rows in ViewControllerB table.
Greatly appreciate any help...
ViewControllerA.h
#import <UIKit/UIKit.h>
#interface ViewControllerA : UIViewController {
IBOutlet UIButton * MybuttonA;
IBOutlet UIButton * MybuttonB;
}
-(IBAction)mybuttonaction:(id)sender;
#property(strong,nonatomic)UIButton *MybuttonA;
#property(strong,nonatomic)UIButton *MybuttonB;
#end
ViewControllerA.m
#import "ViewControllerA.h"
#interface ViewControllerA ()
#end
#implementation ViewControllerA
#synthesize MybuttonA;
#synthesize MybuttonB;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
}
-(IBAction)mybuttonaction:(id)sender{
NSString * link = #"https://google.com";
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:link]];
}
ViewControllerB.h
#import <UIKit/UIKit.h>
#import "ViewControllerA.h"
#interface ViewControllerB : UITableViewController{
ViewControllerA *viewcontrollerA;
}
#property (nonatomic, retain) ViewControllerA *viewcontrollerA;
#end
ViewControllerB.m
#import "ViewControllerB.h"
#import "ViewControllerA.h"
#interface ViewControllerB () {
}
#end
#implementation ViewControllerB
#synthesize viewcontrollerA;
- (void)viewDidLoad
{
[super viewDidLoad];
self.title = #"CONTENTS";
self.refreshControl = [[UIRefreshControl alloc] init];
[self.refreshControl addTarget:self action:#selector(reload) forControlEvents:UIControlEventValueChanged];
[self reload];
[self.refreshControl beginRefreshing];
}
#pragma mark - Table View
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{return 1;}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
{return 5;}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
cell.textLabel.text = [NSString stringWithFormat: #"Cell #%d", indexPath.row];
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
NSString* value = [tableView cellForRowAtIndexPath:indexPath].textLabel.text;
if ([value isEqual:#"1"]){
viewcontrollerA.MybuttonA.enabled=YES;
}
else if ([value isEqual:#"2"])
{
viewcontrollerA.MybuttonB.enabled=YES;
}
}
else {
[tableView deselectRowAtIndexPath:indexPath animated:NO];
}
}
#end
In ViewControllerB, add the following line to viewDidLoad:
viewControllerA = [self.tabBarController.viewControllers objectAtIndex:0];
Then, the rest of your code should work as you have it.
Note that you should generally use self.viewControllerA instead of accessing the iVar directly unless you have a good reason for it. :-)