why UITableView is showing data when I touch it? - objective-c

I have a UITableView loading some tweets, all works nicely but when I populate the table it doesn't enter to the CellForRow method til I touch the table view.... does somebody know how to solve this?
tab = [[UITableView alloc] initWithFrame:CGRectMake(10, 300, 400, 200) style:UITableViewStylePlain];
tab.dataSource = self;
tab.delegate = self;
then...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"entra a cellula");
Tweet *t = [tweets objectAtIndex:indexPath.row];
static NSString *MyIdentifier = #"MyIdentifier";
// Try to retrieve from the table view a now-unused cell with the given identifier.
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
// If no cell is available, create a new one using the given identifier.
if (cell == nil) {
// Use the default cell style.
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:MyIdentifier];
}
cell.textLabel.text = t.screenName;
cell.detailTextLabel.text = t.text;
cell.imageView.image = t.profileImage;
return cell;
}

Best guess based on what we know is that you aren't adding the table as a subview on the main thread. This means that redrawing doesn't occur until you scroll. Try wrapping the addsubview call in a GCD call like so:
dispatch_async(dispatch_get_main_queue(), ^() {
[self addSubview:tab];
});

When you finished loading your tweets call this method:
[tab reloadData];
to reload your tableView data source.

Related

How to indicate new message in UITableViewCell

I have a problem which should be a trivial one but I still can't find a good solution to it.
I have a tableView in which I store cells representing different threads/chatrooms. I have an NSArray with data for cells/chats.
I want to display a badge (with a custom badgeCell) indicating a new message on a corresponding cell.
When I receive a push notification my method searches through the cells and finds indexPath for a cell connected with that new message and adds it to NSArray. Then I reload the tableView.
In tableView:willDisplayCell:forRowAtIndexPath: I check if the cells' indexPath is inside that NSArray of indices and if so I display a badge.
Everything works just fine until I scroll tableView so the cell is not visible. When it comes back again it doesn't have any badge.
Also if my cell is not visible when the Push Notification comes it also doesn't display the badge.
I know it has something to do with ReuseIdentifiers but I can't think of any good solution. Please help me !
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier1 = #"MyCell";
ProblemsTableViewCell *cell;
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier1];
if(!cell) {
cell = [[ProblemsTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier1];
}
if ([cell respondsToSelector:#selector(setSeparatorInset:)]) {
cell.separatorInset = UIEdgeInsetsZero;
}
[cell setSelectionStyle:UITableViewCellSelectionStyleGray];
cell.delegate = self;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
[cell.contentView.superview setClipsToBounds:NO];
[cell.contentView setClipsToBounds:NO];
cell.clipsToBounds = NO;
return cell;
}
-(void)tableView:(UITableView *)tableView willDisplayCell:(nonnull UITableViewCell *)cell forRowAtIndexPath:(nonnull NSIndexPath *)indexPath{
ProblemsTableViewCell * Cell = (ProblemsTableViewCell*)cell;
/* … some customization - > backgroundColor/images etc. … */
for(NSIndexPath* index in self.newMessages){
if(indexPath.row == index.row){
Cell.badgeString = #"new message"; // the _badge property is a built in view of a custom Cell class with a badge.
Cell.badgeColor = [UIColor whiteColor];
Cell.badgeColorHighlighted = [UIColor whiteColor];
Cell.badge.radius = 0;
Cell.badge.fontSize = 15;
Cell.badge.layer.opacity = 0.55f;
NSLog(#"update 0");
break;
}
}
}
Instead of trying to maintain an array of indices, use the array with cell data. Add an indicator for each element in there to say whether a badge is needed or not and use it to turn the badge on or off during cellForRowAtIndexPath.

Multiple checkbox in tableview iOS Objective-C

Im working on Multiple checkbox Functionality in tableview, I have to search in google finally i got it one solution.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
}
if ([selectedRowsArray containsObject:[contentArray objectAtIndex:indexPath.row]]) {
cell.imageView.image = [UIImage imageNamed:#"checked.png"];
}
else {
cell.imageView.image = [UIImage imageNamed:#"unchecked.png"];
}
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleChecking:)];
[cell.imageView addGestureRecognizer:tap];
cell.imageView.userInteractionEnabled = YES; //added based on #John 's comment
//[tap release];
cell.textLabel.text = [contentArray objectAtIndex:indexPath.row];
return cell;
}
- (void) handleChecking:(UITapGestureRecognizer *)tapRecognizer {
CGPoint tapLocation = [tapRecognizer locationInView:self.tableView];
NSIndexPath *tappedIndexPath = [self.tableView indexPathForRowAtPoint:tapLocation];
if ([selectedRowsArray containsObject:[contentArray objectAtIndex:tappedIndexPath.row]]) {
[selectedRowsArray removeObject:[contentArray objectAtIndex:tappedIndexPath.row]];
}
else {
[selectedRowsArray addObject:[contentArray objectAtIndex:tappedIndexPath.row]];
}
[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:tappedIndexPath] withRowAnimation: UITableViewRowAnimationFade];
}
In that code i have one doubt. what is selectedRowsArray and what is ContentArray Please explain anyone. Thanks in advance.
The selectedRowsArray is another array maintained beside your contentArray which is used to hold the content for of the cells that are currently selected in the UITableView. The contentArray holds the actual content which is populated the cells.
Make note of the following lines:
if ([selectedRowsArray containsObject:[contentArray objectAtIndex:indexPath.row]])
{
cell.imageView.image = [UIImage imageNamed:#"checked.png"];
}
else
{
cell.imageView.image = [UIImage imageNamed:#"unchecked.png"];
}
The cell contents are checked for their presence in the selectedRowsArray which means that the cell is selected.
The selection and deselection is handled by the handleChecking: method which adds or removes the object from the same index in the contentArray into the selectedRowsArray.
You must have understood by now that cells in a UITableView are reused, so the actual number of UITableViewCells in the memory are most probably less than the number of cells to be shown in the UITableView. Hence the need for a system which can actually determine whether the cell is currently selected so this status can be populated when the cell is rendered again in the view.
Alternative methods to achieve the same involve using Booleans in an array representing the status of each cell, or simply the indexes of each selected cell in an array.

Default CellAccessory

How can I set first row of tableview checkmarked when the app started? I mean when I start app now, there are few rows in tableview and when I click on some of them its accessory change to checkmark. When click another one, the another one comes checkmarked and previous checkmark dissapears. So now I want first row of tableview to be checkmarked when app is started and then when I click another row it 'uncheckmark' and 'checkmark' new row etc...
Try the options suggested in these posts how to apply check mark on table view in iphone using objective c? or iPhone :UITableView CellAccessory Checkmark
Basically you need to keep track of the checkmarks using say a dictionary or so. And In viewDidLoad or init method make the first cell as checked in the dictionary. While drawing cells, always check if the corresponding entry in the dictionary is checked or not and display check mark accordingly. When user taps on a cell, modify the value in dictionary to checked/unchecked.
Update:
Here is a sample code.
In .h file declare a property as
#property(nonatomic) NSInteger selectedRow;
Then use the below code,
- (void)viewDidLoad {
//some code...
self.selectedRow = 0; //if nothing should be selected for the first time, then make it as -1
//create table and other things
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// create cell and other things here
if (indexPath.row == self.selectedRow)
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
} else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// some other code..
if (indexPath.row != self.selectedRow) {
self.selectedRow = indexPath.row;
}
[tableView reloadData];
}
You could set an integer to a variable similar to "checkedCell", have that value default to cell 0, and in the cellForRowAtIndexPath check to see if the cell is already checked, if not change the accessory to make it checked and update your variable.
-(void)viewWillAppear{
currentCheckedCell = 0;
}
- (UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//
// Create cells -- if indexpath.row is equal to current checked cell reload the table with the correct acessories.
//
static NSString *cellIdentifier = #"RootMenuItemCell";
MyCell *cell = (MyCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[MyCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier];
NSArray *nibContents = [[NSBundle mainBundle] loadNibNamed:#"MyCell" owner:self options:nil];
for (UIView *view in nibContents) {
if ([view isMemberOfClass:[MyCell class]]) {
cell = (MyCell *)view;
break;
}
}
//OTHER CELL CREATION STUFF HERE
// cell accessory
UIImage *accessory = [UIImage imageNamed:#"menu-cell-accessory-default.png"];
UIImage *highlighted = [UIImage imageNamed:#"menu-cell-accessory-selected.png"];
if(indexPath.row == currentCheckedCell){
//DEFAULT ACCESSORY CHECK
// cell.accessoryType = UITableViewCellAccessoryCheckmark;
UIImageView *accessoryView = [[UIImageView alloc] initWithImage:accessory highlightedImage:highlighted];
}else{
//DEFAULT ACCESSORY NONE
// cell.accessoryType = UITableViewCellAccessoryNone;
UIImageView *accessoryView = [[UIImageView alloc] initWithImage:accessory highlightedImage:accessory];
}
[cell setAccessoryView:accessoryView];
}
return cell;
}
- (void)tableView:(UITableView *)aTableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//UPDATE SELECTED CELL & RELOAD TABLE
currentCheckedCell = indexPath.row;
[self.tableview reloadData];
}
Also worth noting that my examples uses custom images for accessories.
If you check out the link #ACB provided you'll find a very similar concept.
You can use,
if (firstCellSelected)
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
Set the firstCellSelected flag in viewDidLoad method.

Detailtext is not showing in case?

I have a case but the detailtext is not showing? Does anyone know what te problem is?
i used: UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UIViewController *controller;
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
switch(indexPath.row) {
case 0:
{
NSLog(#"Case 0");
controller = [[wed1 alloc] init]; //WithStyle:UITableViewStylePlain];
[self.navigationController pushViewController:controller animated:YES];
cell.detailTextLabel.text = #"Wedstrijden!";
}
break;
case 0:
{
NSLog(#"Case 0");
controller = [[wed1 alloc] init]; //WithStyle:UITableViewStylePlain];
//created a controller
[self.navigationController pushViewController:controller animated:YES];
//at his point, you are showing next ViewController's view
cell.detailTextLabel.text = #"Wedstrijden!";
//here you are changing the text of the text for current tableView's cell (which is actually going to be off the screen as new controller's view will be shown after previous statement execution)
}
with the piece of code you shared - I don't find anything wrong here, the detail text should not be visible as this view will be gone.
I don't fully understand why you'd want to set the detail text on a cell after pushing a new view controller. As samfisher said, when the user presses the first cell, in case 0, the new view controller will be alloc'd, init'd and then pushed, and after that you set the detail text to "Wedstrijden".
I'm assuming you're probably just confused between which property to use. My question to you is: when and where do you want this text to appear?
If the cell was created with the style UITableViewCellStyleDefault, the detail text label isn't displayed. In tableView:cellForRowAtIndexPath: implementation, you may create the cell with style UITableViewCellStyleSubtitle or UITableViewCellStyleValue1.
Use UIListContentConfiguration instead, or subtitle won't show.
#import <UIKit/UIListContentConfiguration.h>
And in the cellForRowAtIndexPath method:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"AddressCell" forIndexPath:indexPath];
if(cell==nil){
cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"AddressCell"];
}
NSRange range = [self.dataArray[indexPath.row] rangeOfString:#","];
NSString *street;
NSString *restAddress;
if (range.location != NSNotFound) {
street = [self.dataArray[indexPath.row] substringToIndex:range.location];
restAddress= [self.dataArray[indexPath.row] substringFromIndex:range.location + 1];
}
UIListContentConfiguration *configuration = cell.defaultContentConfiguration;
configuration.text=street;
configuration.image=kImage(#"Location");
configuration.secondaryText=restAddress;
cell.contentConfiguration = configuration;
return cell;
}
Will look like this:

2 NSArrays in one UITableView with Label as subView?

I'm having a problem with my current App. It has one UITableView in the UIViewController. I have one UIButton at the bottom (out of the UITableView). It works in that way:
if ([[NSUserDefaults standardUserDefaults] boolForKey:#"bla"]) {
[[NSUserDefaults standardUserDefaults] setBool:FALSE forKey:#"bla"];
[tableView reloadData];
} else {
[[NSUserDefaults standardUserDefaults] setBool:TRUE forKey:#"tasks2do"];
[tableView reloadData]; }
This worked when I had the cell.textLabel.text Method in this way:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *ident = #"indet";
cell = [tableView dequeueReusableCellWithIdentifier:ident];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:ident] autorelease];
}
if (![[NSUserDefaults standardUserDefaults] boolForKey:#"bla"]) {
cell.textLabel.text = [firstArray objectAtIndex:indexPath.row];
} else {
cell.textLabel.text = [secondArray objectAtIndex:indexPath.row];
}
return cell; }
Now I want to use an UILabel instead of cell.textLabel, because I need it for some reasons (eg. setting the labels frame)
For that I used the following code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *ident = #"indet";
cell = [tableView dequeueReusableCellWithIdentifier:ident];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:ident] autorelease];
}
UILabel *thislabel = [[[UILabel alloc] initWithFrame:CGRectMake(10, 10, 250, 44)] autorelease];
if (![[NSUserDefaults standardUserDefaults] boolForKey:#"bla"]) {
[thislabel setText:[firstArray objectAtIndex:indexPath.row]];
} else {
[thislabel setText:[secondArray objectAtIndex:indexPath.row]];
}
[cell.contentView addSubview:thislabel];
return cell; }
That works fine, until I push the UIButton for switching. It switches, the cell shows the new text but behind the new text is still the old text as you can see here:
http://d.pr/Rqx2
(the firstArray contains the letter L, the secondArray contains the Letter J, it mixes up both up)
Do you have any idea for solving this problem since I tried some stuff (for example using 2 UILabels for the arrays and hide one)? Would be cool. :)
I hope my English is not too bad to understand, my English skills for writing aren't the best, I'm sorry for that.
If you need further information / code just post it, shouldn't be a problem.
I recommend you create a UITableViewCell subclass in which you configure the label (set frame and add it as subview in UITableViewCell's initializer). Add a property for setting the text in the label and write a setter like this for the property:
- (void)setLabelText:(NSString *)newLabelText
{
if ([self.labelText isEqualToString:newLabelText]) return;
[labelText autorelease];
labelText = [newLabelText copy];
self.label.text = labelText;
[self.label setNeedsDisplay]; // or perhaps [self setNeedsDisplay];
}
Edit: by the way, the issue you're dealing with is the caching. You recreate a new label every time a cell comes in view, even if the cell already had a label before. This happens because you initialize an UILabel outside the UITableViewCell initializer (which only should be called once for every cached cell, afterwards it can be retrieved from cache, including all it's subviews).