UIView vs UITableCellView to show user posts - ios

My app has a home screen where I show user posts loaded from the server. My problem is that I use UIView for each post, but it takes up a lot of space (also the user keeps on scrolling making it more memory consuming). Ex:
UIView* box=[[UIView alloc]initWithFrame:CGRectMake(0, postY, maxWidth, 500)];
[box setTag:(NSInteger)[post_id[i] integerValue]];
[box setBackgroundColor:[UIColor whiteColor]];
//Profile pic+++
UIImageView* profile_img=[[UIImageView alloc] initWithFrame:CGRectMake(10, 10, 30, 30)];
profile_img.layer.cornerRadius=profile_img.frame.size.width/2; //Make it round
profile_img.layer.masksToBounds=YES; //Make it round
profile_img.layer.borderWidth=0.5;
profile_img.layer.borderColor=[rgb(214, 222, 231) CGColor];
[box addSubview:profile_img];
And so on...
Does anyone know a better way of doing this? I tough of UITableCellView but it seems to be odd doing this task this way

I recommend you use a UITableViewController and then subclass UITableViewCell to create a custom cell for you to display the data. A UITableViewController instance contains a UITableView and you display the data by setting it in your custom UITableViewCell subclass. So basically, a UITableView contains various UITableViewCell and use the delegate methods to respond to events and actions on your table.
// YourCustomTableViewCell.h
#import <UIKit/UIKit.h>
#interface YourCustomTableViewCell : UITableViewCell
// Setup the properties for the cell, e.g
#property (strong, nonatomic) IBOutlet UIImageView *profileImageView; // Connect to outlet in storyboard file
#end
// YourCustomTableViewCell.m
#import "YourCustomTableViewCell.h"
#implementation YourCustomTableViewCell
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
self.profileImageView = [[UIImageView alloc] initWithFrame:CGRectMake(10, 10, 30, 30)];
}
return self;
}
- (void)awakeFromNib
{
// Use this method to setup frames and sizes of your properties
self.profileImageView.layer.cornerRadius = profileImageView.frame.size.width/2; //Make it round
self.profileImageView.layer.masksToBounds = YES; //Make it round
self.profileImageView.layer.borderWidth=0.5;
self.profileImageView.layer.borderColor = [rgb(214, 222, 231) CGColor];
}
#end
// YourTableViewController.h
#import <UIKit/UIKit.h>
#interface YourTableViewController : UITableViewController
#end
// YourTableViewController.m
#import "YourTableViewController.h"
#import "YourCustomTableViewCell.h"
#interface YourTableViewController ()
#end
#implementation YourTableViewController
- (void)viewDidLoad
{
// Setup your data source for the table
self.tableView.dataSource = self;
// Setup other stuff after loading the view
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1; // Return the number of sections you want in the table view
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows for each section, in your case this would be something like this
return self.posts.count; // If your data is stored in an array
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *identifier = #"YourCustomCell";
YourCustomTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier forIndexPath:indexPath];
if (!cell){
cell = [[YourCustomTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
}
// Configure the cell...
// Here you add the code to display the data in the cell e.g.
[cell.profileImageView setImage:yourImageToDisplay];
return cell;
}
#end

As the comment said, you'd better choose UITableView as the posts' container and inherit from UITableViewCell as your box view.
Detailedly speaking much more, suppose the class inherited from UITableViewCell named MyTableViewCell, and you treat its contentView as your UIView *box. After that, you could tell the UITableView to use your MyTableViewCell as the Cell by sending him registerClass:forCellReuseIdentifier:.
Then, you can get MyTableViewCell instance by sending UITableView the
dequeueReusableCellWithIdentifier:forIndexPath: message. After being bound data (telling him display what posts), this instance can be returned to UITableView, which will arrange everything for you. Besides, these usually should be done in the UITableView's dataSource method - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath.

Related

Unwanted Behaviour of UICollectionView

I am trying to display some text in UICollection view. But i am getting the error that
Property cell label not fount on object of type
UICOllectionViewCell
.h file
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController<UICollectionViewDataSource,UICollectionViewDelegate>
#end
.m file
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 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)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 1;
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return 10;
}
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
NSString *cellIdentifier =#"cell";
UICollectionViewCell* cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
cell.cellLabel.text = #"Sample Text";
return cell;
}
#end
I have already set the delgate methods of UICollectionView.
Here is the Screenshot of Error
First note that even if you have a custom cell you are dequeing your collection view cell to a custom one :
UICollectionViewCell* cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
In compile time the compiler doesn't know you are trying to use your custom cell, therefore that property doesn't exist.
Be sure that you:
Created a custom UICollectionViewCell that has your cellLabel property
That you registered your cell via code OR you used your cell identifier in the Interface Builder
That you imported your cell and you are using it in cellForItemAtIndexPath
Do you have your cellLabel outlet set in interface builder?
If NO then make one.
You should have something like this in your cell's .h file:
#property (weak, nonatomic) IBOutlet UILabel *cellLabel;
then later you really just need to do this:
cell.cellLabel.text = #"";
You can also make a label like this,
UILabel *cellLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 10, cell.bounds.size.width, 40)]; //custom size
[cell.contentView addSubview:cellLabel];
and use it like
cell.cellLabel.text = #"Sample Text";
There are tutorial on UICollectionView you can have a look on this link.

How can I return a TableView from a instance method?

I am trying to add a TableView as a subview in my RootViewController.The TableView will come from another ViewController(TableViewGeneratorController) instance method.
So,What is the best way to do this?
I have created a TableViewGeneratorController it works fine as a standalone app. Then from my RootViewController I have created one instance of the TableViewGeneratorController and trying to call the instance method prepareField,which will return the TableView. I got the TableView but
numberOfRowsInSection and cellForRowAtIndexPath is not getting called.
TableViewGeneratorController.h
#import <UIKit/UIKit.h>
#interface TableViewGeneratorController:UIViewController<UITableViewDataSource,UITableViewDelegate>
{
UITableView *tableView;
}
#property(strong,nonatomic)UITableView *generatedTbleView;
- (UITableView *)prepareField;
#end
TableViewGeneratorController.m
#import "TableViewGeneratorController.h"
#import "RootViewController.h"
#interface TableViewGeneratorController (){
}
#end
#implementation TableViewGeneratorController
- (void)viewDidLoad {
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (UITableView *)prepareField
{
tableView = [[UITableView alloc]initWithFrame:CGRectMake(10, 80, 300, 500)];
tableView.dataSource = self;
tableView.delegate = self;
tableView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
[tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"Cell"];
[tableView reloadData];
return tableView;
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 10;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *cellIndentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIndentifier];
if (cell == nil){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIndentifier];
}
cell.textLabel.text = #"Yes";
return cell;
}
#end
RootViewController.m
Here I am trying to add the TableView as a subview.
TableViewGeneratorController *tableViewGeneratorController = [[TableViewGeneratorController alloc]initWithNibName:#"TableViewGeneratorController" bundle:nil];
UITableView *tv = [tableViewGeneratorController prepareField];
[self.view addSubview: tv];
What is the problem going on?
Thanks
What you are doing is not really the proper way.
The immediate issue is that the TableViewGeneratorController instance that you create goes out of scope and is deallocated. This leaves the table view with not existing data source or delegate. A simple workaround is to assign the TableViewGeneratorController instance to an instance variable instead of a local variable.
But the proper solution is to embed the TableViewGeneratorController as a child controller of the root view controller.
Change TableViewGeneratorController to be a UITableViewController and get rid of the prepareField method.
Then when you create the TableViewGeneratorController, you add it as a child controller. See the docs for UIViewController for details.

Self-sizing UITableViewCell with UITableView inside it - self-sizing doesn't work

I am having trouble with the new concept of self-sizing cells. They work great for simple custom cells, however, I am trying to have a UITableView inside one of my custom UITableViewCells. I thought I had set up everything correctly, the UITableView inside the cell has constraints and everything and the delegates and datasources are connected as well. What's happening is that 'numberOfRowsInSection' in ChecklistTableViewCell gets called and returns 5, but not the corresponding cellForRowAtIndexPath. Therefore, the cell that should include another UITableView is only shown as a smaller cell with no content.
My 'research' via Google has told me that cellForRowAtIndexPath might not get called because the space for the cells is too small. So, I set the rowHeight of all cells to some constant and the UITableView inside the cell is displayed - but I loose the self-sizing functionality.
Therefore, my question, do self-sizing cells not work with more complex components within custom cells or am I missing something basic or important?
First, the code of my UIViewController:
#interface MyViewController ()
#property (weak, nonatomic) IBOutlet UITableView *tableView;
#property (nonatomic, strong) NSArray *elements;
#end
#implementation MyViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.tableView.estimatedRowHeight = 500.0;
self.tableView.rowHeight = UITableViewAutomaticDimension;
}
#pragma mark - UITableView methods
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
Element *element = self.elements[indexPath.row];
if (something) {
...
} else if (something else) {
ChecklistTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"identifier"];
if (cell == nil) {
cell = [[ChecklistTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"identifier"];
}
cell.checklist = element.checklist;
return cell;
} else {
...
}
}
- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.elements count];
}
#end
Here is my code for the cell that has a UITableView inside of it:
#interface ChecklistTableViewCell : UITableViewCell <UITableViewDataSource, UITableViewDelegate>
#property (weak, nonatomic) IBOutlet UITableView *checklistTableView;
#property (strong, nonatomic) NSArray *checklist;
#end
#import "ChecklistTableViewCell.h"
#implementation ChecklistTableViewCell
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
}
return self;
}
- (void)layoutSubviews
{
[super layoutSubviews];
// Setup table view (self-sizing cells!)
self.checklistTableView.estimatedRowHeight = 50.0;
self.checklistTableView.rowHeight = UITableViewAutomaticDimension;
}
#pragma mark - UITableView methods
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
ChecklistElementTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"someIdentifier"];
if (cell == nil) {
cell = [[ChecklistElementTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"someIdentifier"];
}
cell.checklistElementTitleLabel.text = self.checklist[indexPath.row];
return cell;
}
- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.checklist count];
}
#end
And the code for the UIChecklistElementTableViewCell (there's no 'special' code in the .m file):
#interface ChecklistElementTableViewCell : UITableViewCell
#property (weak, nonatomic) IBOutlet UILabel *checklistElementTitleLabel;
#property (strong, nonatomic) IBOutlet M13Checkbox *checkbox;
#end
In the end, I went with implementing
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
where I return the calculated height for the cell with the table view in it and for all other cells, I return UITableViewAutomaticDimension.
It's not what I had hoped for, but it works. If anyone has another solution, I'm still very interested.
Are you sure that you set correctly you Autolayout's constraints for the cell's elements?
Did you set all the UILabel's line numbers to 0?

Accessory view of a table view cell is only shown in the last cell

I want to display the same accessory view in several table view cells, but it is always shown only in the last row. I thus created a very simple test project, and it behaves the same. Here is the test project:
Header:
#import <UIKit/UIKit.h>
#interface TVController : UITableViewController
#end
Implementation:
#import "TVController.h"
#interface TVController ()
#property (nonatomic, strong) UIImageView *image;
#end
#implementation TVController
- (void)viewDidLoad{
[super viewDidLoad];
self.image = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"TestImage38x38"]];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return 4;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"TableViewCell" forIndexPath:indexPath];
cell.textLabel.text = #"test";
cell.accessoryView = self.image;
return cell;
}
#end
Simulator output (the checkmark is the test image):
As you can see, the image is only displayed in the last row, although all cells are set up the same.
What am I doing wrong?
You can't add the same instance of a view to a superview more than once. A view can only have one parent view. You must create instance of UIImageView for each cell:
#property (nonatomic, strong) UIImage *image;
...
self.image = [UIImage imageNamed:#"TestImage38x38"];
...
cell.accessoryView = [[UIImageView alloc] initWithImage:self.image];

UITableView Cell Redirect

I am creating an UITableView and has a question on how to redirect the user to a new view when the person clicks on the cell. It would helpful if could provide some code and possible an explanation. Thank you :)
ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController <UITableViewDataSource, UITableViewDelegate> {
IBOutlet UIButton *Startbutton;
}
#property (strong,nonatomic) NSArray *array;
#end
ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
Startbutton.layer.cornerRadius = 5; // this value vary as per your desire
Startbutton.clipsToBounds = YES;
//Status Bar
[self setNeedsStatusBarAppearanceUpdate];
//Array
self.array = [[ NSArray alloc]initWithObjects:#"1",#"2",#"3", nil];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(UIStatusBarStyle)preferredStatusBarStyle{
return UIStatusBarStyleLightContent;
}
//Array Main Code
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.array.count;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellID = #"cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID forIndexPath:indexPath];
if (!cell) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];
}
cell.textLabel.text = [self.array objectAtIndex:indexPath.row];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
#end
There is a pretty basic way of doing this without having to write code at all, but I am not sure if it is exactly what you want, sorry if it doesn't help.
Drag in a UITableViewController, in the Attributes inspector, select Static Cells from the 'Content' drop down box. Then add how ever many cells you like, click on the cell, then under the attributes inspector change the 'Style' to whatever you like and then change the content of the cell. Then all you have to do to link that cell to a new view is; right click the cell and drag your cursor to the destination view, then Select Modal (or Push if you are in a navigation controller).
That way when you run the app and click on that cell you should be switched to the new view.
No coding is required at all.
Hoped that helped in someway.
Cheers

Resources