Scenario:
I have made 2 sections in one UITableView and the user needs to select a row in each section as shown in the screenshot below.
Expected Outcome:
1. User should be able to select a row in each section
Outcome right now:
1. After I have selected row in one section, and then when I select the row in second section, the first selection disappears.
Here is my code:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// Uncheck the previous checked row
long sec=indexPath.section;
if(sec==0){
if(self->checkedIndexPath)
{
UITableViewCell* uncheckCell = [tableView
cellForRowAtIndexPath:self->checkedIndexPath];
uncheckCell.accessoryType = UITableViewCellAccessoryNone;
}
if([self->checkedIndexPath isEqual:indexPath])
{
self->checkedIndexPath = nil;
}
else
{
UITableViewCell* cell = [tableView cellForRowAtIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
self->checkedIndexPath = indexPath;
}}
if(sec==1){
if(self->checkedIndexPath)
{
UITableViewCell* uncheckCell = [tableView
cellForRowAtIndexPath:self->checkedIndexPath];
uncheckCell.accessoryType = UITableViewCellAccessoryNone;
}
if([self->checkedIndexPath isEqual:indexPath])
{
self->checkedIndexPath = nil;
}
else
{
UITableViewCell* cell = [tableView cellForRowAtIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
self->checkedIndexPath = indexPath;
}
}
}
Help is appreciated.
This is the simplest way.
Finally i found a solution. It works for me, hope it will work for you.
declare these
#interface ViewController ()
{
int selectedsection;
NSMutableArray *selectedindex;
}
Replace didSelectRowAtIndexPath as follows:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// Uncheck the previous checked row
NSIndexPath *selectedIndexPath = [tableView indexPathForSelectedRow];
if(self.checkedIndexPath)
{
for (int i=0; i<[selectedindex count]; i++) {
NSIndexPath *temp= [selectedindex objectAtIndex:i];
if (temp.section==selectedIndexPath.section) {
UITableViewCell* uncheckCell = [tableView
cellForRowAtIndexPath:temp];
uncheckCell.accessoryType = UITableViewCellAccessoryNone;
}
}
NSInteger numb= [tableView numberOfRowsInSection:selectedIndexPath.section];
if (selectedsection==selectedIndexPath.section) {
UITableViewCell* uncheckCell = [tableView
cellForRowAtIndexPath:self.checkedIndexPath];
uncheckCell.accessoryType = UITableViewCellAccessoryNone;
}
}
if([self.checkedIndexPath isEqual:indexPath])
{
for (int i=0; i<[selectedindex count]; i++) {
NSIndexPath *temp= [selectedindex objectAtIndex:i];
if (temp.section==selectedIndexPath.section) {
UITableViewCell* uncheckCell = [tableView
cellForRowAtIndexPath:temp];
uncheckCell.accessoryType = UITableViewCellAccessoryNone;
}
}
self.checkedIndexPath = nil;
}
else
{
for (int i=0; i<[selectedindex count]; i++) {
NSIndexPath *temp= [selectedindex objectAtIndex:i];
if (temp.section==selectedIndexPath.section) {
UITableViewCell* uncheckCell = [tableView
cellForRowAtIndexPath:temp];
uncheckCell.accessoryType = UITableViewCellAccessoryNone;
}
}
UITableViewCell* cell = [tableView cellForRowAtIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
self.checkedIndexPath = indexPath;
[selectedindex addObject:indexPath];
selectedsection=indexPath.section;
NSLog(#"check");
}
}
You can enable the multiple selection in the tableview:
self.tableView.allowsMultipleSelection = YES;
I wrote a sample code where a compound datasource holds datasource objects for each section. Sounds complicated but actually provides an easy to extend architecture. And keeps your view controller small.
The advantages of this approach:
Small ViewController
ViewController set ups view and handles user interaction — as it should be in MVC
Reusable datasources
by using different datasources per section easy to customize cells for each section
the base datasource architecture
This provides easy extension and is simple to reuse.
#import UIKit;
#interface ComoundTableViewDataSource : NSObject
#property (nonatomic,strong, readonly) NSMutableDictionary *internalDictionary;
-(void) setDataSource:(id<UITableViewDataSource>)dataSource forSection:(NSUInteger)section;
-(instancetype)initWithTableView:(UITableView *)tableView;
#end
#import "ComoundTableViewDataSource.h"
#interface ComoundTableViewDataSource () <UITableViewDataSource>
#property (nonatomic,strong, readwrite) NSMutableDictionary *internalDictionary;
#property (nonatomic, weak) UITableView *tableView;
#end
#implementation ComoundTableViewDataSource
-(instancetype)initWithTableView:(UITableView *)tableView
{
self = [super init];
if (self) {
_tableView = tableView;
tableView.dataSource = self;
_internalDictionary = [#{} mutableCopy];
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"Cell"];
}
return self;
}
-(void)setDataSource:(id<UITableViewDataSource>)dataSource forSection:(NSUInteger)section
{
self.internalDictionary[#(section)] = dataSource;
[self.tableView reloadData];
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [[self.internalDictionary allKeys] count];
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
id<UITableViewDataSource> sectionDataSource = self.internalDictionary[#(section)];
return [sectionDataSource tableView:tableView numberOfRowsInSection:section];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
id<UITableViewDataSource> sectionDataSource = self.internalDictionary[#(indexPath.section)];
return [sectionDataSource tableView:tableView cellForRowAtIndexPath:indexPath];
}
-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
id<UITableViewDataSource> sectionDataSource = self.internalDictionary[#(section)];
return [sectionDataSource tableView:tableView titleForHeaderInSection:section];
}
#end
#import UIKit;
#interface SingleSectionDataSource : NSObject <UITableViewDataSource>
#property (nonatomic, strong, readonly) NSArray *array;
#property (nonatomic, strong, readonly) UITableView *tableView;
- (instancetype)initWithArray:(NSArray *)array;
#end
#import "SingleSectionDataSource.h"
#interface SingleSectionDataSource ()
#property (nonatomic, strong, readwrite) NSArray *array;
#property (nonatomic, strong, readwrite) UITableView *tableView;
#end
#implementation SingleSectionDataSource
- (instancetype)initWithArray:(NSArray *)array
{
self = [super init];
if (self) {
self.array = array;
}
return self;
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
self.tableView = tableView;
return self.array.count;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
cell.textLabel.text = self.array[indexPath.row];
return cell;
}
-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
return [#(section) stringValue];
}
#end
the selection datasource architecture
We extend the classes from above to allow one selection per section
#import "ComoundTableViewDataSource.h"
#interface OnSelectionPerSectionComoundTableViewDataSource : ComoundTableViewDataSource
-(void)selectedCellAtIndexPath:(NSIndexPath *)indexPath;
#end
#import "OnSelectionPerSectionComoundTableViewDataSource.h"
#import "SingleSelectionSingleSectionDataSource.h"
#implementation OnSelectionPerSectionComoundTableViewDataSource
-(instancetype)initWithTableView:(UITableView *)tableView
{
self = [super initWithTableView:tableView];
if(self){
[tableView setAllowsMultipleSelection:YES];
}
return self;
}
-(void)selectedCellAtIndexPath:(NSIndexPath *)indexPath
{
SingleSelectionSingleSectionDataSource *sectionDataSource = self.internalDictionary[#(indexPath.section)];
[sectionDataSource selectedCellAtIndexPath:indexPath];
}
#end
View Controller Implementation
As promised, a very slim view controller:
#interface ViewController () <UITableViewDelegate>
#property (weak, nonatomic) IBOutlet UITableView *tableView;
#property (nonatomic, strong) OnSelectionPerSectionComoundTableViewDataSource *tableViewDataSource;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.tableViewDataSource = [[OnSelectionPerSectionComoundTableViewDataSource alloc] initWithTableView:self.tableView];
self.tableView.delegate = self;
[self.tableViewDataSource setDataSource:[[SingleSelectionSingleSectionDataSource alloc] initWithArray:#[#"Hallo", #"Welt"]] forSection:0];
[self.tableViewDataSource setDataSource:[[SingleSelectionSingleSectionDataSource alloc] initWithArray:#[#"Hello", #"World", #"!"]] forSection:1];
[self.tableViewDataSource setDataSource:[[SingleSelectionSingleSectionDataSource alloc] initWithArray:#[#"Hola", #"Mundo", #"!", #"¿Que tal?"]] forSection:2];
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self.tableViewDataSource selectedCellAtIndexPath:indexPath];
}
#end
You will want to add methods to the datasources to get the selected rows.
get the example: https://github.com/vikingosegundo/CompoundDatasourceExample
Note This code has a cell reuse issue. It is fixed on GitHub.
Related
I have 2 UiTableviews in a UiViewController. My exact requirement is to get the selected values from tableview1 and loaded to the tableview2 by tapping the Add Button.
I done Following at the moment
1. loaded JSON Responses to tableview1 (loaded the responses from a filepath at the moment) and printed to a custom nib cell
2. I can get the selected values to a response as follows
Next
3. I want to print that values to *cell2 from the selected values. Please explain the next steps in details.
Here is the UI
Main UI and Description
Here are the codes from table loading to selections.
Object - PSAData.h
#interface PSAData : NSObject
#property (nonatomic, strong) NSString *firstname;
#property (nonatomic, strong) NSString *lastname;
- (void)loadWithDictionary:(NSDictionary *)dict;
#end
Object - PSAData.m
#implementation PSAData
- (void)loadWithDictionary:(NSDictionary *)dict
{
self.firstname=[dict objectForKey:#"firstname"];
self.lastname=[dict objectForKey:#"lastname"];
}
table1 Viewcell - PSATableViewCell.h
#import <UIKit/UIKit.h>
#import "PSAData.h"
#import "NetworkConnectivityClass.h"
#interface PSATableViewCell : UITableViewCell
#property (nonatomic) NetworkConnectivityClass *networkConnectivityClassInstance;
-(void)loadWithData:(PSAData *)psaData;
#end
table1 viewcell - PSATableViewCell.m
#interface PSATableViewCell ()
#property (strong, nonatomic) IBOutlet UILabel *firstnameLbl;
#property (strong, nonatomic) IBOutlet UILabel *lastnameLbl;
#end
#implementation PSATableViewCell
- (void)awakeFromNib {
[super awakeFromNib];
// Initialization code
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
}
-(void)loadWithData:(PSAData *)psaData
{
[self methodSetupText:psaData];
}
-(void)methodSetupText:(PSAData *)psaData
{
self.firstnameLbl.text=psaData.firstname;
self.lastnameLbl.text=psaData.lastname;
}
#end
Main View Controller - PersonnelViewController
- (void)viewDidLoad {
[super viewDidLoad];
// NSMutableArray *selectedArray=[[NSMutableArray alloc]init];
tableView1.dataSource =self;
tableView1.delegate=self;
tableView2.dataSource=self;
tableView2.delegate=self;
//initializing arrays for get selected values
self.selectedCells=[NSMutableArray array];
self.selectedPSAData=[NSMutableArray array];
//loading web resonse data
self.loadedPSAData=[[NSMutableArray alloc]init];
NetworkConnectivityClass *networkConnectivityClassInstance = [NetworkConnectivityClass new];
__weak PersonnelViewController *weakVersionOfSelf=self;
[networkConnectivityClassInstance methodReturnTableViewMessages:^(NSMutableArray *returnedArrayWithMessages)
{
weakVersionOfSelf.loadedPSAData=returnedArrayWithMessages;
[weakVersionOfSelf.tableView1 reloadData];
}];
//register left side tableview cell (Assigned tableview1)
[self.tableView1 registerNib:[UINib nibWithNibName:#"PSATableViewCell" bundle:nil] forCellReuseIdentifier:#"PSATableViewCell"];
}
//tableview Delegates
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
if(tableView ==self.tableView1)
{
return 1;
}
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if(tableView==self.tableView1)
{
return self.loadedPSAData.count;
}
return self.loadedPSAData.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//loading table data into cell tableview1 and tableview2
static NSString *cellIdentifier=#"PSATableViewCell";
PSATableViewCell *cell=[tableView1 dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell==nil) {
cell=[[PSATableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"PSATableViewCell"];
}
//tableview2 implementation
static NSString *cellIdentifier2=#"PSSITableViewCell";
PSSITableViewCell *cell2=[tableView2 dequeueReusableCellWithIdentifier:cellIdentifier2];
if (cell2==nil) {
cell2=[[PSSITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"PSSITableViewCell"];
}
cell.accessoryType = ([self isRowSelectedOnTableView:tableView1 atIndexPath:indexPath]) ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;
if(tableView == self.tableView1)
{
[cell loadWithData:[self.loadedPSAData objectAtIndex:[indexPath row]]];
}
else if(tableView == self.tableView2)
{
[cell2 loadWithDataS2:[self.loadedPSAData objectAtIndex:[indexPath row]]];
return cell2;
}
return cell;
}
pragma mark - multiple selection
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *psaData =[self.loadedPSAData objectAtIndex:indexPath.row];
PSATableViewCell *cell=[tableView1 cellForRowAtIndexPath:indexPath];
NSString *sampleAH =[self.selectedPSAData description];
if([self isRowSelectedOnTableView:tableView1 atIndexPath:indexPath])
{
[self.selectedCells removeObject:indexPath];
[self.selectedPSAData removeObject:psaData];
cell.accessoryType =UITableViewCellAccessoryNone;
}
else{
[self.selectedCells addObject:indexPath];
[self.selectedPSAData addObject:psaData];
cell.accessoryType =UITableViewCellAccessoryCheckmark;
}
NSLog(#"%#", self.selectedPSAData);
sampleArrayholder.text=[NSString stringWithFormat:#"%#", sampleAH];
}
-(BOOL)isRowSelectedOnTableView:(UITableView *)tableView atIndexPath:(NSIndexPath *)indexPath
{
return ([self.selectedCells containsObject:indexPath]) ? YES : NO;
}
**Finally NetworkConnectivity class - NetworkConnectivityClass.h **
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import "WorksitenameList.h"
#interface NetworkConnectivityClass : NSObject
-(void)methodLogin:(NSString *)stringToLogin withUserName:(NSString *)stringUsername withPassword:(NSString *)stringPassword completion:(void(^)(NSDictionary *))completion;
-(void)methodReturnTableViewMessages:(void (^)(NSMutableArray *))completion;
-(NSURLSessionTaskState)methodCheckIfSessionIsRunning;
-(void)methodCancelNetworkRequest;
#end
**Finally NetworkConnectivity class - NetworkConnectivityClass.m **
-(void)methodReturnTableViewMessages:(void (^)(NSMutableArray *))completion
{
dispatch_queue_t queueForJSON = dispatch_queue_create("queueForJSON", NULL);
dispatch_async(queueForJSON, ^{
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"PSAData" ofType:#"json"];
NSError *error = nil;
NSData *rawData = [NSData dataWithContentsOfFile:filePath options:NSDataReadingMappedIfSafe error:&error];
id JSONData = [NSJSONSerialization JSONObjectWithData:rawData options:NSJSONReadingAllowFragments error:&error];
NSMutableArray *loadedPSAData = [NSMutableArray new];
[loadedPSAData removeAllObjects];
if([JSONData isKindOfClass:[NSDictionary class]])
{
NSArray *loadedArray=[JSONData objectForKey:#"records"];
if([loadedArray isKindOfClass:[NSArray class]])
{
for(NSDictionary *psaDict in loadedArray)
{
PSAData *psaData=[[PSAData alloc]init];
[psaData loadWithDictionary:psaDict];
[loadedPSAData addObject:psaData];
}
}
}
dispatch_async(dispatch_get_main_queue(), ^{
completion(loadedPSAData);
NSLog(#"test: %#", loadedPSAData);
});
});
}
I Added All the required codes to have a look at it. Since I am relatively new to iOS Dev. Please Write a codes / instructions step by step clearly to save some time :).
**Please Note : At the moment I loaded the same tableview1 data to tableview2 *cell2 But I want here to load the selected values(Multiple Selection). from tableview1 loadedPSAData Array to load in table view to by tapping an Add Button. Finally sorry for my poor English ;) **
Suppose these 2 are your table outlet.
__weak IBOutlet UITableView * myTable1;
__weak IBOutlet UITableView * myTable2;
You set the Delegate and Data Source like below in your viewDidLoad
myTable1.delegate=self;
myTable1.dataSource=self;
myTable2.delegate=self;
myTable2.dataSource=self;
Now These are 2 Arrays
array1 ==> Which contain All Data
arraySelectedValues ==> Which contain you selected data
So you use this like below
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if(self.myTable1 == tableView)
{
return [array1 count];
} else {
return [arraySelectedValues count];
}
}
As I review your Code, Your problem may be in CellForRow. Why to create 2 separate cells, when there is same CellIdentifier. You just need to change the Data.
You should create 2 cells only When Both Tableview are using Diff-Diff tableviewcells. In your case you are using same cell.
Try to modify the code like this
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier=#"PSATableViewCell";
PSATableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell==nil) {
cell=[[PSATableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier: cellIdentifier];
}
if(tableView == myTable1)
{
[cell loadWithData:[array1 objectAtIndex:[indexPath row]]];
}
else if(tableView == myTable2)
{
[cell loadWithData:[arraySelectedValues objectAtIndex:[indexPath row]]];
}
return cell;
}
didSelectRowAtIndexPath should look like :
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if(tableView == myTable1)
{
// Your code for highlighting
} else {
// This will be you myTable2 did select click.
}
}
Just When ever you want to refresh the record, you should to Call ReloadData method For respective Tableviews.
Hope you understand how you load the data in 2 Tableviews in Single ViewController.
I have implemented a Twitter feed in a UITableViewController and I'm using a custom cell with a UITextView in it so it has link detection. The problem I'm having is that only the first cell shows up and if I start scrolling the app crashes with EXC_BAD_ACCESS on cell.tweetText.text = t[#"text"];. The feed shows up correctly if I don't use a custom cell, but then you can't tap on a link.
TweetCell.h
#import <UIKit/UIKit.h>
#interface TweetCell : UITableViewCell <UITextViewDelegate>
#property (weak, nonatomic) IBOutlet UITextView *tweetText;
#end
tableviewcontroller.h
#import <UIKit/UIKit.h>
#interface GRSTwitterTableViewController : UITableViewController
#property (nonatomic, strong) NSMutableArray *twitterFeed;
#end
tableviewcontroller.m
#import "GRSTwitterTableViewController.h"
#import "TweetCell.h"
#import "STTwitter.h"
#interface GRSTwitterTableViewController ()
#end
#implementation GRSTwitterTableViewController
#synthesize twitterFeed;
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.title = #"";
self.tableView = [[UITableView alloc]initWithFrame:CGRectZero style:UITableViewStyleGrouped];
UIBarButtonItem *openTwitterButton = [[UIBarButtonItem alloc]initWithTitle:#"Open in Twitter" style:UIBarButtonItemStylePlain target:self action:#selector(openTwitter:)];
self.navigationItem.rightBarButtonItem = openTwitterButton;
STTwitterAPI *twitter = [STTwitterAPI twitterAPIAppOnlyWithConsumerKey:#"xz9ew8UZ6rz8TW3QBSDYg" consumerSecret:#"rm8grg0aIPCUnTpgC5H1NMt4uWYUVXKPqH8brIqD4o"];
[twitter verifyCredentialsWithSuccessBlock:^(NSString *username)
{
[twitter getUserTimelineWithScreenName:#"onmyhonorband" count:50 successBlock:^(NSArray *statuses)
{
twitterFeed = [NSMutableArray arrayWithArray:statuses];
[self.tableView reloadData];
}
errorBlock:^(NSError *error)
{
NSLog(#"%#", error.debugDescription);
}];
}
errorBlock:^(NSError *error)
{
NSLog(#"%#", error.debugDescription);
}];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)openTwitter:(id)sender
{
NSURL *twitterURL = [NSURL URLWithString:#"twitter:///user?screen_name=onmyhonorband"];
NSURL *safariURL = [NSURL URLWithString:#"https://twitter.com/onmyhonorband"];
if ([[UIApplication sharedApplication]canOpenURL:twitterURL])
{
[[UIApplication sharedApplication]openURL:twitterURL];
}
else
{
[[UIApplication sharedApplication]openURL:safariURL];
}
}
#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 [twitterFeed count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
tableView.backgroundColor = [UIColor darkGrayColor];
TweetCell *cell = [tableView dequeueReusableCellWithIdentifier:#"myCell"];
if (!cell)
{
[tableView registerNib:[UINib nibWithNibName:#"TweetCell" bundle:nil] forCellReuseIdentifier:#"myCell"];
cell = [tableView dequeueReusableCellWithIdentifier:#"myCell"];
}
NSInteger idx = indexPath.row;
NSDictionary *t = twitterFeed[idx];
cell.tweetText.text = t[#"text"];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
#end
Here is a screenshot of what the tableview looks like when using the custom cell.
replace the line code
TweetCell *cell = [tableView dequeueReusableCellWithIdentifier:#"myCell"];
if (!cell)
{
[tableView registerNib:[UINib nibWithNibName:#"TweetCell" bundle:nil] forCellReuseIdentifier:#"myCell"];
cell = [tableView dequeueReusableCellWithIdentifier:#"myCell"];
}
with the below code
TweetCell *cell = [tableView dequeueReusableCellWithIdentifier:#"myCell"];
if (!cell)
{
NSArray *nibs =[[NSBundle mainBundle] loadNibNamed:#"TweetCell" owner:self options:NULL];
cell = [nibs firstObject];
}
I have a TableView displaying a list of domain :
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.tableView.dataSource = mainClass.domainList;
}
The domain list is set up like that :
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.domainList count];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [[UITableViewCell alloc] init];
cell.textLabel.text = [[self.domainList objectAtIndex:indexPath.row] name];
return cell;
}
This works perfectly, it displays each domain in a row of my table view.
Now i would like to add a "Sub TableView" in each cell of my Table View to display a list of documents related to the domain.
I tried that :
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableView *table = [[UITableView alloc] init];
table.dataSource = [self.domainList objectAtIndex:indexPath.row];
UITableViewCell *cell = [[UITableViewCell alloc] init];
cell.textLabel.text = [[self.domainList objectAtIndex:indexPath.row] name];
[cell.contentView addSubView table]
return cell;
}
It doesn't crash but it doesn't work neither. I mean the sublist doesn't appear anywhere.
What am i doing wrong?
datasource must be a class implementing the protocol UITableViewDataSource. It looks like you are setting it to a custom object. Create a separate class with the code you used to implement the first table, then set the sublist as source data. In the objc.io article “clean table view code” they explain how to make reusable datasources. Or you can just give it a try on your own.
Consider this code:
// ARRAYDATASOURCE.H
#import <Foundation/Foundation.h>
typedef void (^TableViewCellConfigureBlock)(id cell, id item);
#interface ArrayDataSource : NSObject <UITableViewDataSource>
-(id) init __attribute__((unavailable("disabled, try initWithItems:cellIdentifier:configureCellBlock")));
- (id) initWithItems:(NSArray *)anItems
cellIdentifier:(NSString *)aCellIdentifier
configureCellBlock:(TableViewCellConfigureBlock)aConfigureCellBlock;
- (id)itemAtIndexPath:(NSIndexPath *)indexPath;
#end
// ARRAYDATASOURCE.M
#import "ArrayDataSource.h"
#interface ArrayDataSource ()
#property (nonatomic, strong) NSArray *items;
#property (nonatomic, copy) NSString *cellIdentifier;
#property (nonatomic, copy) TableViewCellConfigureBlock configureCellBlock;
#end
#implementation ArrayDataSource
- (id)initWithItems:(NSArray *)anItems
cellIdentifier:(NSString *)aCellIdentifier
configureCellBlock:(TableViewCellConfigureBlock)aConfigureCellBlock
{
self = [super init];
if (self) {
self.items = anItems;
self.cellIdentifier = aCellIdentifier;
self.configureCellBlock = [aConfigureCellBlock copy];
}
return self;
}
- (id)itemAtIndexPath:(NSIndexPath *)indexPath
{
return self.items[(NSUInteger) indexPath.row];
}
#pragma mark UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.items.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:self.cellIdentifier
forIndexPath:indexPath];
id item = [self itemAtIndexPath:indexPath];
self.configureCellBlock(cell, item);
return cell;
}
#end
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've a UITableView embedded into a UIViewController, I've followed all the steps needed to display a list into the table view and this is working
I've a problem with the following method, it looks like it is invoked but it return null instead of the item of the list
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"%#",[self.list objectAtIndex:indexPath.row]);
}
thank you to everyone for its thoughts
Alessandro
Here below the code, the list is correctly displayed so the outlet and protocol method are set up (delegate, datasource).
The method tableview:didSelectRowAtIndexPath: it prints out (null) instead of the right element in the list
//
// MainViewController.m
// ProvaTable
//
// Created by Alessandro on 12/6/12.
// Copyright (c) 2012 Alessandro. All rights reserved.
//
#import "MainViewController.h"
#interface MainViewController ()
#property (weak, nonatomic) IBOutlet UITableView *tableView;
#property (weak, nonatomic) NSArray *listOfObjects;
#end
#implementation MainViewController
#synthesize tableView = _tableView;
#synthesize listOfObjects = _listOfObjects;
-(void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.listOfObjects = [NSArray arrayWithObjects:#"Object 1",#"Object 2", nil];
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.listOfObjects count];
}
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell Item";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
}
// Set up the cell...
cell.textLabel.font = [UIFont fontWithName:#"Helvetica" size:15];
cell.textLabel.text = [self.listOfObjects objectAtIndex:indexPath.row];
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"%#",[self.listOfObjects objectAtIndex:indexPath.row]);
}
#end