I'm creating an iPad app. The root UITableview has a right bar button item in the navigation controller. When you tap the button, it shows a pop over controller. The popover is a UITableViewController. When you tap a cell in the popover, how could I pass the data in that cell and insert it into a cell into the root UITableview? I searched the Apple docs and couldn't find what I needed. Can anyone push me in the right direction?
Roottable.h
#interface Roottable : UITableViewController<PopoverDelegate>
Popover.h
#protocol AthleteSelectPopoverDelegate <NSObject>
#required
-(void)selectedObject:(Object *)newObject;
#end
#property (nonatomic, weak) id<PopoverDelegate> delegate;
#property (readwrite, nonatomic) Object *currentObject;
#end
popover.m
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
_currentObject = [_objectArray objectAtIndex:indexPath.row];
//Notify the delegate if it exists.
if (_delegate != nil) {
[_delegate selectedObject:_currentObject];
}
}
You add data from the selected cell to the main table's data source delegate.
Then that data source should tell the main table that a cell has been inserted at an index path.
I figured it out. Hope I help someone. I'll explain the code first then post it below. Basically, I set the data source of the root table view, "ObjectSelect", as a NSMutableArray called "currentObjectArray". ObjectSelect is also the ObjectSelectPopoverDelegate. Basically, when a cell in the popover is tapped, it adds the object tapped to the "currentObjectArray" and reloads the tableview.
ObjectSelect.h
#import <UIKit/UIKit.h>
#import "ObjectSelectPopover.h"
#interface ObjectSelect : UITableViewController<ObjectSelectPopoverDelegate>
#property (nonatomic, strong) ObjectSelectPopover *objectPicker;
#property (nonatomic, strong) UIPopoverController *objectPickerPopover;
#property (readwrite, nonatomic) Object *currentObject;
#property (nonatomic, strong) NSMutableArray *selectedObjectArray;
#end
ObjectSelect.m
-(void)selectedObject:(Object *)newObject
{
_currentObject = newObject;
if(!_selectedObjectArray){
_selectedObjectArray = [[NSMutableArray alloc] init];
}
if([_selectedObjectArray containsObject:_currentAthlete]){
//lol you don't get added, bub
}
else{
[_selectedObjectArray addObject:_currentObject];
}
[self.tableView reloadData];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
Object *objectTapped = (Object *)[_objectAthleteArray objectAtIndex:indexPath.row];
return cell;
}
ObjectSelectPopover.h
#import <UIKit/UIKit.h>
#import "Object.h"
#protocol ObjectSelectPopoverDelegate <NSObject>
#required
-(void)selectedObject:(Object *)newObject;
#end
#interface ObjectSelectPopover : UITableViewController
#property (nonatomic, weak) id<ObjectSelectPopoverDelegate> delegate;
#property (nonatomic, strong) NSMutableArray *objectArray;
#property (readwrite, nonatomic) Object *currentObject;
#end
ObjectSelectPopover.m
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
_currentObject = [_objectArray objectAtIndex:indexPath.row];
//Notify the delegate if it exists.
if (_delegate != nil) {
[_delegate selectedObject:_currentObject];
}
[self.tableView deselectRowAtIndexPath:indexPath animated:YES];
}
I think you should have a property with a name other than delegate in your popover controller since UITableViewController already has a delegate property for the UITableViewDelegate protocol; maybe masterTable or something.
Then in the selectedObject: implementation in the root UITableView you can do an insert row or add it to the data array and reload the table.
Oops, my bad... #geraldWilliam is right, UITableViewController does not have the delegate property...
What you have seems like it should work... So does the selectedObject: method get called in the delegate? If so, what do you do in that method? If you add the object to the data set (array or dictionary or database) for the root view, insert a row in its tableview (or reload the data), it should work.
Here is some code that works for me. It is not from a popover but from a pushed view but there is no reason that should make a difference:
- (ThingStatus) thingPicker: (ThingPickerTableViewController *) thingPicker didSelectThing: (Thing *) thing {
NSLog( #"Entering %s", __func__ );
// Dismiss the pushed view controller (for you, the popover)
[self.navigationController popViewControllerAnimated: YES];
NSArray *startingList = self.currentCellObjectList;
[self.databaseManager addThing: thing];
NSArray *endingList = self.databaseManager.thingsForTableView;
// Figure out the differences adding made...
DiffResult *changes = [startingList simpleDiffWithArray: endingList];
NSLog( #"%d deletions, %d insertions", changes.deletionCount, changes.insertionCount );
// I only handle insertions in this code... deletions would be similar
__block NSUInteger objIdx = 0;
NSMutableArray *changeableThingList = [startingList mutableCopy];
[changes.insertionIndexes enumerateIndexesUsingBlock: ^( NSUInteger idx, BOOL *stop ) {
NSLog( #" - insert %# at %d", [[changes.insertionObjects objectAtIndex: objIdx] name], idx );
NSIndexPath *indexPath = [NSIndexPath indexPathForRow: idx inSection: 0];
[changeableThingList insertObject: [changes.insertionObjects objectAtIndex: objIdx] atIndex: idx];
self.currentCellObjectList = changeableThingList;
[self.tableView insertRowsAtIndexPaths: [NSArray arrayWithObject: indexPath] withRowAnimation: UITableViewRowAnimationRight];
++objIdx;
}];
[self.databaseManager save];
return [self.databaseManager: thingStatus];
}
Here is some good code to use that may be able to help you.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return self.item.count;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
//Get the row
Sport *rowSport = self.sports[indexPath.row];
cell.textLabel.text = rowItem.itemName;
cell.detailTextLabel.text = rowItem.section;
return cell;
}
I hope this will help you.
Related
I have a UITableViewController with many UITableViewCell. Each Cell have a UISwitch Button.
Here is my UITableViewController Class:
#implementation DanhsachTableViewController{
NSMutableArray *data;
}
- (void)viewDidLoad {
[super viewDidLoad];
[self loadData];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
DichVu2TableViewCell *cell = (DichVu2TableViewCell *)[tableView dequeueReusableCellWithIdentifier:#"dscell"];
NSDictionary *dataCell = data[indexPath.row];
cell.service = dataCell[#"service"];
cell.package = dataCell[#"package"];
cell.loai_goi = dataCell[#"loai_goi"];
return cell;
}
-(void) changeCellState:(NSString *)service package:(NSString *)package loaigoi:(NSString *)loai_goi{
for (int i =0;i<data.count;i++){
DichVu2TableViewCell *cellLocal = [self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:0]];
if ([service isEqualToString:cellLocal.service] && ![package isEqualToString:cellLocal.package] && [loai_goi isEqualToString:cellLocal.loai_goi]){
[cellLocal.sudung setOn:NO animated:YES];
}
}
}
"Data" array was loaded in method loadData (not important here so I don't include it).
In UITableViewCell (class name: DichVu2TableViewCell), I set event Value Change of Switch so that each time a Switch change value (ON for example), all other cell's switch which have the same value "service" and "loai_goi" will be set OFF.
DanhsachTableViewController *tableview = [[DanhsachTableViewController alloc] init];
tableview.tableView.delegate = (DanhsachTableViewController *)self.superview.superview;
[tableview changeCellState:_service package:_package loaigoi:_loai_goi];
But when I call, the array "data" of above tableview have 0 object so nothing happened.
Is there any way to do that?
Hi Oyeoj,
Thanks for your help.
I have a little problem when followed your guide. There are some error in xcode when I use extract your code so I have to customize. But the program still has error when running. Would you please help me review my code. Thanks in advance.
DichVu2TableViewCell.h
#class DichVu2TableViewCell;
//Change : NSObject to <NSObject> because XCode 6.3 has error.
#protocol DichVu2TableViewCellDelegate <NSObject>
-(void)changeCell:(DichVu2TableViewCell *)sender state:(NSString *)service package:(NSString *)package loaigoi:(NSString *)loai_goi;
#end
#interface DichVu2TableViewCell : UITableViewCell
#property (weak) id <DichVu2TableViewCellDelegate> delegate;
#end
DichVu2TableViewCell.m
#implementation DichVu2TableViewCell
….
- (void)someSwitchingEvent
{
[self.delegate changeCell:self state:_service package:_package loaigoi:_loai_goi];
}
#end
DanhsachTableViewController.h
#interface DanhsachTableViewController : UITableViewController
#property (strong,nonatomic) NSString *loaitb;
#property (strong,nonatomic) NSString *type;
#property (strong,nonatomic) NSString *name;
#property NSMutableArray *pre_inuse_;
#property NSMutableArray *data_inuse_;
#property NSMutableArray *vas_inuse_;
#end
DanhsachTableViewController.m
#import "DichVu2TableViewCell.h"
//Change <DichVu2TableViewCellDelegate> to (DichVu2TableViewCellDelegate) because XCode 6.3 has error.
#interface DanhsachTableViewController (DichVu2TableViewCellDelegate)
#property (nonatomic) NSIndexPath *forUpdateIndexPath;
#end
#implementation DanhsachTableViewController{
NSMutableArray *data;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
DichVu2TableViewCell *cell = (DichVu2TableViewCell *)[tableView dequeueReusableCellWithIdentifier:#"dscell"];
NSDictionary *dataCell = data[indexPath.row];
cell.service = dataCell[#"service"];
cell.package = dataCell[#"package"];
cell.loai_goi = dataCell[#"loai_goi"];
cell.kieu_goi = dataCell[#"kieu_goi"];
[cell.sudung setOn:NO animated:YES];
cell.delegate = self;
//Change cellLocal —> cell because there are no cellLocal avaiable. And Program error when run to this row.
[cell.sudung setOn:(self.forUpdateIndexPath == indexPath) animated:YES];
return cell;
}
-(void)changeCell:(DichVu2TableViewCell *)sender state:(NSString *)service package:(NSString *)package loaigoi:(NSString *)loai_goi
{
//Add cellLocal —> cell because there are no cellLocal avaiable
DichVu2TableViewCell *cellLocal = (DichVu2TableViewCell *)[self.tableView cellForRowAtIndexPath:self.forUpdateIndexPath];
if ([service isEqualToString:cellLocal.service] && ![package isEqualToString:cellLocal.package] && [loai_goi isEqualToString:cellLocal.loai_goi]){
// get the indexPath of the cell
self.forUpdateIndexPath = [self.tableView indexPathForCell:sender];
// update the date source
NSMutableDictionary *dataCell = [data[self.forUpdateIndexPath.row] mutableCopy];
[dataCell setObject:service forKey:#"service"];
[dataCell setObject:package forKey:#"package"];
[dataCell setObject:loai_goi forKey:#"loai_goi"];
// you dont need the for-statement just reload the table
[self.tableView reloadData];
// then update the switch inside `- cellForRowAtIndexPath`
}
}
A more efficient method would be to use custom delegates.
You can declare a protocol in your UITableViewController class.
Declare the changeCellState function in the protocol.
Create a delegate property in the UITableViewCell class.
Call the delegate method from the UITableViewCell class when the switch value is changed.
The UITableViewController will itself receive the message, and the function will be called respectively.
Have you tried logging self.superview.superview; ? are your sure is in type UIViewController?
if so:
Do not call [[DanhsachTableViewController alloc]
instead use the DanhsachTableViewController from your parentview
DanhsachTableViewController *tableview = (DanhsachTableViewController *)self.superview.superview;
[tableview changeCellState:_service package:_package loaigoi:_loai_goi];
This
DanhsachTableViewController *tableview = [[DanhsachTableViewController alloc] init]; assigns a new DanhsachTableViewController class and not the existing one.
Edit
USING protocol and delegate
When using delegate you dont need the self.superview.superview :)
UNDER DichVu2TableViewCell
#class DichVu2TableViewCell;
#protocol DichVu2TableViewCellDelegate <NSObject>
-(void)changeCell:(DichVu2TableViewCell *)sender state:(NSString *)service package:(NSString *)package loaigoi:(NSString *)loai_goi;
#end
#interface DichVu2TableViewCell : UIViewController
#property (weak) id <DichVu2TableViewCellDelegate> delegate;
#end
#implementaion DichVu2TableViewCell
..
- (void)someSwitchingEvent
{
[self.delegate changeCell:self state:_service package:_package loaigoi:_loai_goi];
}
#end
while
UNDER DanhsachTableViewController
// assuming you alreading imported the `DichVu2TableViewCell` like
//
// #import "DichVu2TableViewCell.h"
//
// set the delegate
#interface DanhsachTableViewController () <DichVu2TableViewCellDelegate>
#property (nonatomic) NSIndexPath *forUpdateIndexPath;
#end
// then implement the method from the delegate under implementation file
#implementation DanhsachTableViewController
{
NSMutableArray *data;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self loadData];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
DichVu2TableViewCell *cell = (DichVu2TableViewCell *)[tableView dequeueReusableCellWithIdentifier:#"dscell"];
NSDictionary *dataCell = data[indexPath.row];
cell.service = dataCell[#"service"];
cell.package = dataCell[#"package"];
cell.loai_goi = dataCell[#"loai_goi"];
// this is the magic .. :)
//--
cell.delegate = self;
[cell.sudung setOn:(self.forUpdateIndexPath == indexPath) animated:YES];
//--
return cell;
}
-(void)changeCell:(DichVu2TableViewCell *)sender state:(NSString *)service package:(NSString *)package loaigoi:(NSString *)loai_goi
{
// `self.forUpdateIndexPath` is declared as property
if ([service isEqualToString:service] && ![package isEqualToString:package] && [loai_goi isEqualToString:loai_goi]){
// get the indexPath of the cell
self.forUpdateIndexPath = [self.tableView indexPathForCell:sender];
// update the date source
NSMutableDictionary *dataCell = [data[self.forUpdateIndexPath.row] mutableCopy];
[dataCell setObject:service forKey:#"service"];
[dataCell setObject:package forKey:#"package"];
[dataCell setObject:loai_goi forKey:#"loai_goi"];
// you dont need the for-statement just reload the table
[self.tableView reloadData];
// then the switch will be updated inside `- cellForRowAtIndexPath`
}
}
Hope this is more helpful now.. :) Cheers...
First of all I want to apologize for my bad english.
I'm having trouble to set the properties of my custom UITableViewCell (HistoricoCell).
When I try to set a property of my cell I get: Signal SIGABRT error:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// Dequeue the cell.
HistoricoCell *cell = (HistoricoCell *)[self.tblHistorico dequeueReusableCellWithIdentifier:#"CellIdentifier" forIndexPath:indexPath];
// Fetch Item
NSDictionary *item = [self.dbManager.arrColumnNames objectAtIndex:indexPath.row];
// Configure Table View Cell
[cell.lblCodigo setText:[NSString stringWithFormat:#"%#", item[#"codigo"]]];
[cell.btnFavoritar addTarget:self action:#selector(didTapButton:) forControlEvents:UIControlEventTouchUpInside];
return cell;
}
I followed a lot of tutorials and questions on the web but I stil with my error.
Can someone help me?
My code:
HistoricoCell.h
#import <UIKit/UIKit.h>
#interface HistoricoCell : UITableViewCell
#property (weak, nonatomic) IBOutlet UILabel *lblCodigo;
#property (weak, nonatomic) IBOutlet UIButton *btnFavoritar;
#end
SecondViewController.h
#import <UIKit/UIKit.h>
#interface SecondViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
#property (weak, nonatomic) IBOutlet UITableView *tblHistorico;
SecondViewController.m
#import "SecondViewController.h"
#import "DBManager.h"
#import "HistoricoCell.h"
#interface SecondViewController ()
#property (nonatomic, strong) DBManager *dbManager;
#property (nonatomic, strong) NSArray *arrPeopleInfo;
-(void)loadData;
#end
#implementation SecondViewController
static NSString *CellIdentifier = #"CellIdentifier";
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// Make self the delegate and datasource of the table view.
self.tblHistorico.delegate = self;
self.tblHistorico.dataSource = self;
// Initialize the dbManager property.
self.dbManager = [[DBManager alloc] initWithDatabaseFilename:#"bernoullidb.sql"];
[self.tblHistorico registerClass:[HistoricoCell class] forCellReuseIdentifier:#"CellIdentifier"];
[self loadData];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)loadData{
// Form the query.
NSString *query = #"select * from tbHistorico";
// Get the results.
if (self.arrPeopleInfo != nil) {
self.arrPeopleInfo = nil;
}
self.arrPeopleInfo = [[NSArray alloc] initWithArray:[self.dbManager loadDataFromDB:query]];
// Reload the table view.
//[self.tblHistorico reloadData];
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return self.arrPeopleInfo.count;
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
return 60.0;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// Dequeue the cell.
HistoricoCell *cell = (HistoricoCell *)[self.tblHistorico dequeueReusableCellWithIdentifier:#"CellIdentifier" forIndexPath:indexPath];
// Fetch Item
NSDictionary *item = [self.dbManager.arrColumnNames objectAtIndex:indexPath.row];
// Configure Table View Cell
[cell.lblCodigo setText:[NSString stringWithFormat:#"%#", item[#"codigo"]]];
[cell.btnFavoritar addTarget:self action:#selector(didTapButton:) forControlEvents:UIControlEventTouchUpInside];
return cell;
}
- (void)didTapButton:(id)sender {
NSLog(#"%s", __PRETTY_FUNCTION__);
}
#end
You should set cell indentifier "CellIdentifier" for your cell in File Inspector
Or register your nib file if you add cell with nib:
UINib *itemNib = [UINib nibWithNibName:#"yourCell" bundle:nil];
[self.tableView registerNib:itemNib forCellReuseIdentifier:#"yourCellReuseIndentifier"];
I think your problem is in your cell creation: you try to dequeue a cell if it exists (i.e. recycle a previously used cell). that is OK, but, especially when the TableView is displayed for the first time, no previously used cell for this table exists. So, you have to create one if the dequeueReusableCellWithIdentifier call return nil.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// Dequeue the cell.
HistoricoCell *cell = (HistoricoCell *)[self.tblHistorico dequeueReusableCellWithIdentifier:#"HistoricoCellIdentifier" forIndexPath:indexPath];
if( cell == nil ) // no queuded cell to dequeue
{
// you have to create a fresh new one
cell = [HistoricoCell alloc] initWithStyle:<your cell style> reuseIdentifier:#"HistoricoCellIdentifier"];
}
// Fetch Item
NSDictionary *item = [self.dbManager.arrColumnNames objectAtIndex:indexPath.row];
// Configure Table View Cell
[cell.lblCodigo setText:[NSString stringWithFormat:#"%#", item[#"codigo"]]];
[cell.btnFavoritar addTarget:self action:#selector(didTapButton:) forControlEvents:UIControlEventTouchUpInside];
return cell;
}
Whenever I search for something from a search bar, I get the correct results. When I click on those results, it links me to the same place that the original results would have linked me to. In other words, I have teacher a-e, I type in 'e', and get only the result 'e', but when I click on that cell, it links me to the teacher 'a' profile.
Here is what I have so far.
#import <UIKit/UIKit.h>
#interface ListTableViewController : UITableViewController
#end
---
#import "ListTableViewController.h"
#import "DetailsViewController.h"
#interface ListTableViewController () <UISearchDisplayDelegate>
#property (strong, nonatomic) NSArray *className;
#property (strong, nonatomic) NSArray *teacherName;
#property (strong, nonatomic) NSArray *blockNumber;
#property (strong, nonatomic) NSArray *myNew;
#property (strong, nonatomic) NSArray *searchResults;
#end
#implementation ListTableViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.className = [NSArray arrayWithObjects:#"Biology",#"English III",#"Chemistry",#"Algebra II",#"Morality", nil];
self.teacherName = [NSArray arrayWithObjects:#"Teacher A",#"Teacher B",#"Teacher C",#"Teacher D",#"Teacher E", nil];
self.blockNumber = [NSArray arrayWithObjects:#"B1",#"B3",#"B6",#"B2",#"B1", nil];
NSMutableArray *combinedArray = [[NSMutableArray alloc]init];
for (int i = 0; i < [self.className count]; i++)
{
NSString *combinedString = [NSString stringWithFormat:#"%# | %# | %#",[self.className objectAtIndex:i],[self.teacherName objectAtIndex:i],[self. blockNumber objectAtIndex:i]];
[combinedArray addObject:combinedString];
}
self.myNew = combinedArray;
}
- (void)filterContentForSearchText: (NSString *) searchText
{
NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:#"SELF CONTAINS[cd] %#", searchText];
self.searchResults = [self.myNew filteredArrayUsingPredicate:resultPredicate];
}
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
[self filterContentForSearchText:searchString];
return YES;
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (tableView == self.tableView) {
return [self.myNew count];
} else { // (tableView == self.searchDisplayController.searchResultsTableView)
return [self.searchResults count];
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (tableView == self.tableView) {
cell.textLabel.text = [self.myNew objectAtIndex:indexPath.row];
} else {
cell.textLabel.text = [self.searchResults objectAtIndex:indexPath.row];
}
return cell;
}
#pragma mark - Table view delegate
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"showDetails"]) {
DetailsViewController *dvc = segue.destinationViewController;
NSIndexPath *indexPath = nil;
if ([self.searchDisplayController isActive]) {
indexPath = [self.searchDisplayController.searchResultsTableView indexPathForSelectedRow];
dvc.sendLabel = [self.searchResults objectAtIndex:indexPath.row];
dvc.teachersendLabel = [self.teacherName objectAtIndex:indexPath.row];
return;
} else{
indexPath = [self.tableView indexPathForSelectedRow];
dvc.sendLabel = [self.myNew objectAtIndex:indexPath.row];
dvc.teachersendLabel = [self.teacherName objectAtIndex:indexPath.row];
return;
}
}
}
#end
In my DetailsViewController
#import <UIKit/UIKit.h>
#interface DetailsViewController : UIViewController
#property (weak, nonatomic) IBOutlet UILabel *label;
#property (strong, nonatomic) NSString *sendLabel;
#property (weak, nonatomic) IBOutlet UILabel *teacherlabel;
#property (strong, nonatomic) NSString *teachersendLabel;
#end
---
#implementation DetailsViewController
#synthesize label;
- (void)viewDidLoad
{
[super viewDidLoad];
self.teacherlabel.text = [NSString stringWithFormat:#"%#", self.teachersendLabel];
self.label.text = [NSString stringWithFormat:#"%#", self.sendLabel];
}
#end
Looking at your code it wouldn't seem there to be any problem. The are only two things I can think of:
1) I'm not sure how you're displaying the 'main' tableView and the search results one. Might it be that your touches are actually getting handled by the 'main' tableView? This might happen if you have the two tables aligned on top of each other and the bottom one is still visible and with userInteractionEnabled set to YES when the search one 'isActive'. In this case the view hierarchy should look similar to this:
- UIView
- UITableView (main)
- UITableView (search)
2) the use of -[UITableView indexPathForSelectedRow] in prepareForSegue:sender:. If you're using Storyboard the sender is the selected cell. You may want to check that the sender is an actual cell or an indexPath isKindOfClass. If the sender is an indexPath you can use it, if it's a cell you can call the method -[UITableView indexPathForCell:]. Using this approach you make sure your segue is actually triggering for the right event (e.g. you can programmatically select a cell, but this won't fire a segue and you can later decide to call -performSegueWithIdentifier:sender: and this would break your implementation).
I'm building a sign-in app. It has two table views. One lists people who have visited before (existingNames), and one lists the current people signed in (names).
At certain points in my code the only mutable array that does not crash the program when accessed is names.
names and existingNames seems to somehow be reversed as well. When I try to remove from names, the program crashes. When I remove from existingNames, the changes are reflected in tableView2, but tableView2 is supposed to be associated with names.
In the app's current state everything is "working" except for accessing any company arrays. I put quotes around working because of the names and existingNames being used backwards.
Any insight into what might be causing the problem would be much appreciated!
.h:
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>{
UITableView *tableView;
}
#property (weak, nonatomic) IBOutlet UITextField *nameField;
#property (weak, nonatomic) IBOutlet UITextField *companyField;
#property (nonatomic, retain) NSMutableArray *names;
#property (nonatomic, retain) NSMutableArray *companies;
#property (nonatomic, retain) NSMutableArray *existingNames;
#property (nonatomic, retain) NSMutableArray *existingCompanies;
- (IBAction)add:(id)sender;
- (IBAction)addExisting:(id)sender;
- (IBAction)remove:(id)sender;
- (IBAction)submit:(id)sender;
#property (strong, nonatomic) IBOutlet UITableView *tableView1;
#property (weak, nonatomic) IBOutlet UITableView *tableView2;
#end
.m:
#import "ViewController.h"
#import <MessageUI/MessageUI.h>
#interface ViewController () <MFMailComposeViewControllerDelegate>
#end
#implementation ViewController
#synthesize nameField;
#synthesize companyField;
#synthesize names;
#synthesize companies;
#synthesize existingNames;
#synthesize existingCompanies;
#synthesize tableView1 = _tableView1;
#synthesize tableView2 = _tableView2;
int rowNumber1;
int rowNumber2;
- (void)viewDidLoad
{
[super viewDidLoad];
self.names = [[NSMutableArray alloc] init];
self.companies = [[NSMutableArray alloc] init];
self.existingNames = [[NSMutableArray alloc] init];
self.existingCompanies = [[NSMutableArray alloc] init];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (tableView == self.tableView1){
return [existingNames count];
}
else if (tableView == self.tableView2){
return [names count];
}
return 0;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"SimpleTableItem";
UITableViewCell *cell;
if (tableView == self.tableView1){
cell = [_tableView1 dequeueReusableCellWithIdentifier:simpleTableIdentifier];
}
else if (tableView == self.tableView2){
cell = [_tableView2 dequeueReusableCellWithIdentifier:simpleTableIdentifier];
}
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
if (tableView == self.tableView1){
cell.textLabel.text = [existingNames objectAtIndex:indexPath.row];
}
else if (tableView == self.tableView2){
cell.textLabel.text = [names objectAtIndex:indexPath.row];
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
if (tableView == self.tableView1){
rowNumber1 = indexPath.row;
}
else if (tableView == self.tableView2){
rowNumber2 = indexPath.row;
}
}
- (IBAction)add:(id)sender {
BOOL exists = [existingNames containsObject:nameField.text];
if(exists == FALSE){
[names addObject:nameField.text];
[companies addObject:companyField.text];
[existingNames addObject:nameField.text];
[existingCompanies addObject:companyField.text];
}
else{
[names addObject:nameField.text];
[companies addObject:companyField.text];
}
[_tableView1 reloadData];
[_tableView2 reloadData];
nameField.text=#"";
companyField.text=#"";
}
- (IBAction)addExisting:(id)sender {
[existingNames addObject:[names objectAtIndex:rowNumber1]];
//[companies addObject:[existingCompanies objectAtIndex:rowNumber]];
[_tableView2 reloadData];
}
- (IBAction)remove:(id)sender {
[existingNames removeObjectAtIndex:rowNumber2];
[existingCompanies removeObjectAtIndex:rowNumber2];
[_tableView2 reloadData];
}
#end
The following methods are part of the UITableViewDataSource and UITableViewDelegate protocols
tableView:numberOfRowsInSection:
tableView:cellForRowAtIndexPath:
tableView:didSelectRowAtIndexPath:
and will be called by your table view assuming you've property assigned the table view's delegate and dataSource properties. These methods, however,
tableView2:numberOfRowsInSection:
tableView2:cellForRowAtIndexPath:
tableView2:didSelectRowAtIndexPath:
are not part of the protocol and won't ever get called by the table view. It looks like you may be confusing your property names, e.g. tableView, with with the protocol method names, e.g. tableView:numberOfRowsInSection:. What you need to do is:
If you haven't already done so, set your view controller as the delegate and dataSource for both your tableView and tableView2.
In each of the data source and delegate methods that you need to implement, handle the cases for both tables.
For example, your tableView:numberOfRowsInSection: method would look like:
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (tableView == self.tableView) {
return [existingNames count];
}
else if (tableView == self.tableView2) {
return [names count];
}
return 0;
}
i have problem to display selected data into detaillabeltext in one of my row of section, beside reload the whole table view any other method to reload only certain row of section?
//RootViewController.m (parent controller)
-(void) selectedData:(NSString*) text
{
selectedAbsenceType = text;
NSLog(#"the absence type select is %#",text);
}
-(void) (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
if (indexPath.section == 0)
{
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
}
NSDictionary *dictionary = [dataArray objectAtIndex:indexPath.section];
NSArray *array = [dictionary objectForKey:#"data"];
NSString *cellValue = [array objectAtIndex:indexPath.row];
cell.textLabel.text = cellValue;
if([cellValue isEqual: #"Absence Type"])
{
cell.detailTextLabel.text = selectedAbsenceType;
}
else if([cellValue isEqual:#"Start Date"])
{
cell.detailTextLabel.text = selectedDate;
}
return cell;
}
===========================================================================================
i have a problem when i calling the method of the protocol, it keep prompt me a ARC Semantic Issue at this statement
[self.delegate selectedData: (NSString*) [self.absenceTypes objectAtIndex:indexPath.row]];:
//child.h
#import <UIKit/UIKit.h>
#protocol childViewControllerDelegate;
#interface AbsenceTypesViewController : UITableViewController
{
id<childViewControllerDelegate>delegate;
}
#property (nonatomic,weak) id<childViewControllerDelegate> delegate;
#property NSArray *absenceTypes;
#end
#protocol childViewControllerDelegate <NSObject>
-(void) selectedData:(NSString*) text;
#end
//child.m
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *selectedCell = nil;
selectedCell = [self.absenceTypes objectAtIndex:indexPath.row];
[self.delegate selectedData: (NSString*) [self.absenceTypes objectAtIndex:indexPath.row]];
//[self.navigationController popViewControllerAnimated:YES];
NSLog(#"%#", selectedCell);
}
Remove {
id<childViewControllerDelegate>delegate;
} inside user class interface.id<childViewControllerDelegate>delegate; means strong variable which will be released only when holding object is released. But in property declaration you are mentioning delegate as weak property. Hence the ARC Semantic is giving you warning. You can also make the delegate weak by declaring it as weak explicitly like __weak id<childViewControllerDelegate>delegate;
Try replacing the .h file content with this.
#import <UIKit/UIKit.h>
#class AbsenceTypesViewController;
#protocol childViewControllerDelegate <NSObject>
-(void) selectedData:(NSString*) text;
#end
#interface AbsenceTypesViewController : UITableViewController
{
id<childViewControllerDelegate>delegate;
}
#property (nonatomic,weak) id<childViewControllerDelegate> delegate;
#property NSArray *absenceTypes;
#end
So that you have forward declaration of class.
You can save all selected option of second view controller in NSMutable Array and save all components separated by comma and send this array to your parent controller.
NSMutableArray *selectedVal =[[NSMutableArray alloc] init];
FirstViewController *FVC = (FirstViewController*)
if ([FVC isKindOfClass:[FirstViewController class]])
{
[FVC setSelectedOption:[selectedVal componentsJoinedByString:#","]];
}
[self.navigationController popViewControllerAnimated:YES];