iMax iMax - 4 months ago 14
iOS Question

IOS: Navigate through tableView and show table view data on next view

in my project i am using a custom

UITableView
in which i passes 2 array (image and name) arrays are showing on
UITableView
. Now i want to when i click on any cell of table view the credentials of
UITableViewCell
to be display on next View in which i take an
UIImageView
(for image) and UILabel (for name display). i also import the VC on which i have to display image and name.
please suggest me code to display name and image on another view

i am using the following codes

.h file

#import <UIKit/UIKit.h>

@interface FriendsViewController : UIViewController<UISearchDisplayDelegate , UISearchBarDelegate, UITableViewDataSource, UITableViewDelegate>

{
UITableView *friendslisttable;
NSMutableArray *friendslist;
NSMutableArray *friendsnamearray;
NSMutableArray *profilepicarray;
UIImageView * frndprofpic;
UILabel *friendnamelabel;

NSArray *searchResults;
}
@end


.m file

- (void)viewDidLoad
{
[super viewDidLoad];
self.title = @"Friends";

friendslisttable = [[UITableView alloc]initWithFrame:CGRectMake(0,110 , self.view.frame.size.width, self.view.frame.size.height)] ;
friendslisttable.delegate = self;
friendslisttable. dataSource = self;
[self.view addSubview:friendslisttable];

friendsnamearray = [[NSMutableArray alloc]initWithObjects:@"friend1",@"friend12",@"friend13",@"friend14",@"friend15",@"friend16",@"friend17",@"friend18",@"friend19",@"friend20",@"friend21 ",@"friend22",@"", nil];

profilepicarray = [[NSMutableArray alloc]initWithObjects:@"download3.jpeg", @"12045540_717548405011935_7183980263974928829_o.jpg" , @"download4.jpeg", @"download5.jpeg", @"download6.jpg", @"download12.jpeg", @"download13.jpeg", @"download16.jpeg",@"download3.jpeg", @"download6.jpg", @"download12.jpeg", @"download16.jpeg", @" ", nil];
}

#pragma mark - TableView Delegate Method -------------------->>>>

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 60;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (tableView == self.searchDisplayController.searchResultsTableView) {
return searchResults.count;
}
else {
return friendsnamearray.count;
}
}

- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *cellidentifier = @"cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellidentifier ];

if(!cell) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellidentifier];
cell.accessoryType=UITableViewCellAccessoryDisclosureIndicator;
}
friendslisttable = nil;
if (tableView == self.searchDisplayController.searchResultsTableView) {
friendslisttable = [searchResults objectAtIndex:indexPath.row];
} else
{
friendslisttable = [friendsnamearray objectAtIndex:indexPath.row];
}

frndprofpic = [[UIImageView alloc]initWithFrame:CGRectMake(5, 5, 50, 50)];

frndprofpic.image=[UIImage imageNamed:[profilepicarray objectAtIndex:indexPath.row]];
[cell.contentView addSubview:frndprofpic];

friendnamelabel = [[UILabel alloc]initWithFrame:CGRectMake(70, 10, 250, 50)];
friendnamelabel.text = [friendsnamearray objectAtIndex:indexPath.row];
friendnamelabel.font = [UIFont fontWithName:@"ChalkboardSE-Regular" size:20];
[cell.contentView addSubview:friendnamelabel];

return cell;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (!indexPath.row) {
ProfileViewController *u = [[ProfileViewController alloc]init];
[self.navigationController pushViewController:u animated:YES];
}
}

Answer

For the cases such as yours I suggest you to subclass the table view cell. Create 2 properties in your case for the profile image and for the name. Override setters of these properties and set the view components as needed.

On the event of did select row you may now use the same properties of the custom cell which can be set as properties to your target controller before pushing it.

But if you want to do it proper you should always use a model class (MyUserClass) which can then be inserted into the custom cell and the view controller. This way you keep only one property for both the input and output. Also if your model class changes or if you need to display more data not much of the code will change. For instance imagine your cell stays the same but on the view controller you wish to also add the user location: All you need to do is add the location property to the model class and then use it only in the view controller. (if you did it with multiple properties the cell would need that property to be collected even though it does not display it).

Let me give you a nice example on some uses of communications with the table view, table view cell and the owner (usually the view controller).

This is a display of how to get the data from cell nicely as well as hooking a custom control (the button) to the cell and notify the owner of the event with the appropriate data.

Note this is all done programmatically so you can see all the code done. This may all be done with storyboards though.

Header:

#import <UIKit/UIKit.h>

@class MyModel;
@class MyTableViewCell;

@interface MyViewController : UIViewController

- (void)specialCellButtonPressed:(MyTableViewCell *)sender selectedModel:(MyModel *)model;

@end

Source:

#import "MyViewController.h"


#pragma mark - My model
/*
 MyModel:
 Model that we will use to hold the data
*/
@interface MyModel : NSObject

@property (nonatomic, strong) NSString *title;
@property (nonatomic, strong) NSString *descriptionText;

@end

#pragma mark - My model
/*
 MyTableViewCell:
 Custom table view cell to show the MyModel data
 */
@interface MyTableViewCell : UITableViewCell

@property (nonatomic, strong) MyModel *model;

@property (nonatomic, strong) UIButton *specialButton; // have the secondary action
@property (nonatomic, weak) MyViewController *owner; // note this may also be solved with a custom delegate but we want to bind this one to a concrete class that has type of MyViewController. Be careful to set this property to "weak"

@end

@implementation MyTableViewCell

- (void)setModel:(MyModel *)model
{
    _model = model; // standard asignment

    // set some views to show the actual data
    self.textLabel.text = model.title;
    self.detailTextLabel.text = model.descriptionText;
}

#pragma mark - custom button on the cell

// lazy load for the button
- (UIButton *)specialButton
{
    if(_specialButton == nil)
    {
        // put the button on the right side of the frame
        _specialButton = [[UIButton alloc] initWithFrame:CGRectMake(.0f, .0f, self.contentView.frame.size.width*.5f, self.contentView.frame.size.width*.5f)];
        [_specialButton addTarget:self action:@selector(spectialButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
        [self.contentView addSubview:_specialButton];
    }
    return _specialButton;
}

#pragma mark - layout

- (void)layoutSubviews
{
    [super layoutSubviews];
    // reposition the custom view if needed
    self.specialButton.frame = CGRectMake(.0f, .0f, self.contentView.frame.size.width*.5f, self.contentView.frame.size.width*.5f);
}

#pragma mark - actions

- (void)spectialButtonPressed:(id)sender
{
    // just report this to the delegate or rather the owner in this case
    [self.owner specialCellButtonPressed:self selectedModel:self.model];
}

@end


#pragma mark - My model
/*
 MyViewController:
 A view controller showing the table view
 */
@interface MyViewController ()<UITableViewDataSource, UITableViewDelegate>

@property (nonatomic, strong) NSArray *models;
@property (nonatomic, strong) UITableView *tableView;

@end

@implementation MyViewController

#pragma mark - lifetime

- (void)viewDidLoad {
    [super viewDidLoad];

    // fill some data for our table view
    NSMutableArray *models = [[NSMutableArray alloc] init];
    for(NSInteger i=0; i<24; i++)
    {
        MyModel *model = [[MyModel alloc] init];
        model.title = [NSString stringWithFormat:@"Cell %d", (int)(i+1)];
        model.descriptionText = [NSString stringWithFormat:@"This is a cell with index: %d", (int)(i)];
        [models addObject:model];
    }
    self.models = models;
}

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    [self.tableView reloadData];
}

// lazy load from table view
- (UITableView *)tableView
{
    if(_tableView == nil)
    {
        _tableView = [[UITableView alloc] initWithFrame:CGRectMake(.0f, .0f, self.view.frame.size.width, self.view.frame.size.height)];
        _tableView.delegate = self;
        _tableView.dataSource = self;
        [self.view addSubview:_tableView];
    }
    return _tableView;
}

#pragma mark - layout

- (void)viewWillLayoutSubviews
{
    [super viewWillLayoutSubviews];
    // reposition the table view if needed
    self.tableView.frame = CGRectMake(.0f, .0f, self.view.frame.size.width, self.view.frame.size.height);
}

#pragma mark - table view

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return self.models.count;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return 44.0f;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    MyTableViewCell *cell = [[MyTableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:nil];
    cell.model = self.models[indexPath.row]; // assign the model from our list
    cell.owner = self;
    return cell;
}

// standard cell selection
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
    MyTableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
    MyModel *model = cell.model;
    /*
     Alternative if we have the data array (as we do in this case):

     MyModel *model = self.models[indexPath.row];

     */

    NSLog(@"Selected model: %@", model);
    // do whatever with the model
}

#pragma mark - special

- (void)specialCellButtonPressed:(MyTableViewCell *)sender selectedModel:(MyModel *)model
{
    NSLog(@"Special button for model pressed: %@", model);
}

@end




@implementation MyModel

// override description to get some usefull data
- (NSString *)description
{
    return [NSString stringWithFormat:@"<%p> %@ (%@)", self, self.title, self.descriptionText];
}

@end
Comments