tableview crash with '*** -[__NSArrayM insertObject:atIndex:]: object cannot be nil' - ios

I got a problem.
I have a TableView in my ViewController. This TableView has 5 rows with textFields. The height of each row is 156 pixels. also I have button "Save", and after click I want save all my data to NSMutableArray in following method, but in result I got an error.
What should I do in this way?
thank you
my method example:
- (void) saveDataToArray
{
carCellTableViewCell * cell;
_carNewPrices = [[NSMutableArray alloc] init];
for (int i = 0; i < 5; i++)
{
cell = (carCellTableViewCell *)[_meTableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:0]];
[_carPrices addObject:cell.priceText.text];
}
}
and here is cellForRowAtIndexPath:
- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
carCellTableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
cell.nameLabel.text = [_carNames objectAtIndex:indexPath.row];
cell.priceLabel.text = [NSString stringWithFormat:#"$%#/day",[_carPrices objectAtIndex:indexPath.row]];
cell.infoLabl.text = [_carInfos objectAtIndex:indexPath.row];
switch (indexPath.row) {
case 0:
{
[cell.img setImage:[UIImage imageNamed:#"rolls.jpg"]];
return cell;
}
case 1:
{
[cell.img setImage:[UIImage imageNamed:#"bentley.jpg"]];
return cell;
}
case 2:
{
[cell.img setImage:[UIImage imageNamed:#"mercedes.jpg"]];
return cell;
}
case 3:
{
[cell.img setImage:[UIImage imageNamed:#"bmw.jpg"]];
return cell;
}
case 4:
{
[cell.img setImage:[UIImage imageNamed:#"skoda.jpg"]];
}
default:
break;
}
return cell;
}
additional:
in my tableviewCell i have a label, and a textfield. when i click on "Save" i want save all my data from textField and send it to label.
here is all code from .m file:
#import "carListViewController.h"
#import "carCellTableViewCell.h"
#import "UserSingleton.h"
#import "CheckInternetConnection.h"
#define getCarList #"http:mylink.php" //changed
#define setCarList #"http:mylink.php" //changed
#interface carListViewController ()
#property (weak, nonatomic) IBOutlet UIBarButtonItem *editButtonOutler;
- (IBAction)editButtonOnClick:(id)sender;
#property BOOL editOrSave;//0 when edit, 1 when save
#property UserSingleton * userInfo;
#property NSMutableArray *json;
#property NSMutableArray * carNames;
#property NSMutableArray * carPrices;
#property NSMutableArray * carInfos;
#property NSMutableArray * carNewPrices;
- (void) setData;
#property (weak, nonatomic) IBOutlet UITableView *meTableView;
- (void) saveDataToArray;
- (void) getDataOfCars;
#end
#implementation carListViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.title = #"List of cars";
// Do any additional setup after loading the view.
}
- (void) viewWillAppear:(BOOL)animated
{
CheckInternetConnection * checkInternet = [[CheckInternetConnection alloc] init];
if (![checkInternet isInternetAvailable])
[self.navigationController popViewControllerAnimated:YES];
_userInfo = [UserSingleton sharedInstance];
if (_userInfo.priority == 2)
{
_editButtonOutler.enabled = YES;
_editButtonOutler.title = #"Edit";
}
else
{
_editButtonOutler.enabled = NO;
_editButtonOutler.title = #"";
}
_editOrSave = NO;
[self getDataOfCars];
[_meTableView reloadData];
}
- (NSInteger) numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 5;
}
- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
carCellTableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
cell.nameLabel.text = [_carNames objectAtIndex:indexPath.row];
cell.priceLabel.text = [NSString stringWithFormat:#"$%#/day",[_carPrices objectAtIndex:indexPath.row]];
cell.infoLabl.text = [_carInfos objectAtIndex:indexPath.row];
switch (indexPath.row) {
case 0:
{
[cell.img setImage:[UIImage imageNamed:#"rolls.jpg"]];
return cell;
}
case 1:
{
[cell.img setImage:[UIImage imageNamed:#"bentley.jpg"]];
return cell;
}
case 2:
{
[cell.img setImage:[UIImage imageNamed:#"mercedes.jpg"]];
return cell;
}
case 3:
{
[cell.img setImage:[UIImage imageNamed:#"bmw.jpg"]];
return cell;
}
case 4:
{
[cell.img setImage:[UIImage imageNamed:#"skoda.jpg"]];
}
default:
break;
}
return cell;
}
- (IBAction)editButtonOnClick:(id)sender {
if (_editOrSave == 0)
{
_editOrSave = 1;
_editButtonOutler.title = #"Save";
carCellTableViewCell * cell;
for (int i = 0; i < 5; i ++)
{
cell = (carCellTableViewCell *)[_meTableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:0]];
cell.priceLabel.hidden = YES;
cell.priceText.hidden = NO;
cell.priceText.text = [[_json objectAtIndex:i] objectForKey:#"cost"];
}
}
else if (_editOrSave == 1)
{
_editOrSave = 0;
carCellTableViewCell * cell;
for (int i = 0; i < 5; i ++)
{
cell = (carCellTableViewCell *)[_meTableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:0]];
cell.priceLabel.hidden = NO;
cell.priceText.hidden = YES;
[self saveDataToArray];
[self setData];
//cell.priceLabel.text = [_carPrices objectAtIndex:i];
}
_editButtonOutler.title = #"Edit";
}
[self getDataOfCars];
[_meTableView reloadData];
}
- (void) getDataOfCars
{
_carInfos = [[NSMutableArray alloc] init];
_carNames = [[NSMutableArray alloc] init];
_carPrices = [[NSMutableArray alloc] init];
NSURLRequest* urlRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:getCarList] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
NSData * data = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:nil error:nil];
_json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
carCellTableViewCell * cell;
for (int i = 0; i < _json.count; i ++)
{
cell = (carCellTableViewCell *)[_meTableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:0]];
[_carNames addObject:[[_json objectAtIndex:i] objectForKey:#"name"]];
[_carPrices addObject:[[_json objectAtIndex:i] objectForKey:#"cost"]];
[_carInfos addObject:[[_json objectAtIndex:i] objectForKey:#"about"]];
}
}
- (void) setData{
for (int i = 0; i < 5; i ++)
{
NSMutableString * postString = [NSMutableString stringWithFormat:setCarList];
[postString appendString:[NSString stringWithFormat:#"?id=%d", i+1]];
[postString appendString:[NSString stringWithFormat:#"&cost=%#", [_carPrices objectAtIndex:i]]];
[postString setString:[postString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSMutableURLRequest * request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:postString]];
[request setHTTPMethod:#"POST"];
NSURLConnection * postConnection;
postConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];
}
}
- (void) saveDataToArray
{
carCellTableViewCell * cell;
_carNewPrices = [[NSMutableArray alloc] init];
for (int i = 0; i < 5; i++)
{
cell = (carCellTableViewCell *)[_meTableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:0]];
[_carPrices addObject:cell.priceText.text];
}
}
#end
it seems that an error is caused because not all cells are visible in the screen. after my scroll down now even last cell has changed after my onclick on edit button.
how to resovle this problem?

It's upside-down to fill an array with what's in a UITableView. The way to do that is the other way around.
In other words, somewhere else in your code you determine what's in the priceText label. If it's a static table, then the information might be in IB, or if you're implementing tableview:cellForRowAtIndexPath:, you're looking up the priceText there.
Put those values in the priceArray.
Your edit helped. This line:
[NSString stringWithFormat:#"$%#/day",[_carPrices objectAtIndex:indexPath.row]];
Is your friend, so:
NSMutableArray *newArrayOfStrings = [NSMutableArray array];
for (int i=0; i<_carPrices.count; i++) {
NSString *str = [NSString stringWithFormat:#"$%#/day",_carPrices[i]];
[newArrayOfStrings addObject:str];
}
Edit again. More code and comments, more clarity:
Declare that your vc implements the UITextFieldDelegate, and declare a property to keep your edited prices:
#interface MyViewController <UITextFieldDelegate>
#property (nonatomic, strong) NSMutableArray *editedStrings;
// initialize this with the carPrices after you get these from JSON
self.editedStrings = [_carPrices mutableCopy]; // if they are NSNumbers
// if they are strings, you'll need a deeper copy:
self.editedStrings = [NSMutableArray array];
for (NSString *str in _carPrices) {
[self.editedStrings addObject:[str copy]];
}
In cellForRowAtIndexPath, make your vc the delegate, and tag the textFields, so you know which one is being edited:
cell.priceLabel.delegate = self;
cell.priceLabel.tag = indexPath.row;
Then implement the delegate method for when the user edits:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSInteger index = textField.tag;
NSString *candidateString = [textField.text stringByReplacingCharactersInRange:range withString:string];
[self.editedStrings replaceObjectAtIndex:index withObject: candidateString];
return YES;
}

Add a breakpoint to the line [_carPrices addObject:cell.priceText.text] and you'll see that at some index, the text will be nil. I can't tell you why will it be nil, since I don't know how you're creating the cell.

Related

Json issue in tableview with stepper and lable

I am new in ios developer.
I want to selected data into other tableview my problem is i dont know how to get the name and quantity.
See here is my screen shot
My json data like this format
{
Data = (
{
"Dry_cleaning" = 49;
Iron = 8;
Name = "Shirt/Tees";
Wash = 15;
"Wash_Iron" = 19;
id = 1;
},
{
"Dry_cleaning" = 49;
Iron = 5;
Name = "Kurta(short)";
Wash = 20;
"Wash_Iron" = 19;
id = 2;
},
{
"Dry_cleaning" = 50;
Iron = 8;
Name = "Kurta(Long)";
Wash = 15;
"Wash_Iron" = 20;
id = 3;
},
{
"Dry_cleaning" = 50;
Iron = 5;
Name = Shorts;
Wash = 15;
"Wash_Iron" = 19;
id = 4;
},
{
"Dry_cleaning" = 55;
Iron = 8;
Name = "Trousers/Pyjamas";
Wash = 20;
"Wash_Iron" = 30;
id = 5;
},
{
"Dry_cleaning" = 70;
Iron = 7;
Name = Jeans;
Wash = 20;
"Wash_Iron" = 29;
id = 6;
},
{
"Dry_cleaning" = 150;
Iron = 5;
Name = Blazer;
Wash = 25;
"Wash_Iron" = 19;
id = 7;
},
{
"Dry_cleaning" = 100;
Iron = 6;
Name = "Leather_Jacket";
Wash = 30;
"Wash_Iron" = 36;
id = 8;
}
}
Here this is my code
ViewController.h
import
#interface ViewController : UIViewController<UITableViewDataSource,UITableViewDelegate>
#property (weak, nonatomic) IBOutlet UITableView *tableview;
#property (strong, nonatomic)NSMutableArray *arrayCounts;
- (IBAction)placeorder:(id)sender;
#end
ViewController.m
//
// ViewController.m
// orderscreenfile
//
// Created by Tranetech on 02/02/16.
// Copyright (c) 2016 Tranetech. All rights reserved.
//
#import "ViewController.h"
#import "custom.h"
#interface ViewController ()
{
NSDictionary *dic_property;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[NSThread detachNewThreadSelector:#selector(fetchdata) toTarget:self withObject:nil];
//[NSThread detachNewThreadSelector:#selector(arrycount) toTarget:self withObject:nil];
self.arrayCounts = [NSMutableArray array];
NSLog(#"array count=%d",self.arrayCounts.count);
[self.tableview reloadData];
// Do any additional setup after loading the view, typically from a nib.
}
//-(void)arrycount
//{
// for (int i = 0; i<[[dic_property objectForKey:#"Data"] count]; i++) {
// [self.arrayCounts insertObject:[NSString stringWithFormat:#"0"] atIndex:i];
// }
//
//}
-(void)fetchdata
{
NSString *login= [[NSString stringWithFormat:#"http://men_dry.php"]stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSLog(#"----%#", login);
NSURL *url = [NSURL URLWithString:[login stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
//-- Get request and response though URL
NSMutableURLRequest *request = [[NSMutableURLRequest alloc]initWithURL:url];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
if (data) {
dic_property= [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
NSLog(#"%#", dic_property);
NSLog(#"counts=%d",[[dic_property objectForKey:#"Data"]count]);
for (int i = 0; i<[[dic_property objectForKey:#"Data"] count]; i++) {
[self.arrayCounts insertObject:[NSString stringWithFormat:#"0"] atIndex:i];
}
[self.tableview reloadData];
}
else {
NSLog(#"network error, %#", [error localizedFailureReason]);
}
});
}];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return self.arrayCounts.count;
// return [[dic_property objectForKey:#"Data"]count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
custom *cell;
static NSString *simpleTableIdentifier = #"customcell";
cell = (custom *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
cell = [[[NSBundle mainBundle] loadNibNamed:#"customcell" owner:self options:nil] objectAtIndex:0];
cell.lblcount.text = self.arrayCounts[indexPath.row];
cell.lbltitle.text=[[[dic_property objectForKey:#"Data"]objectAtIndex:indexPath.row]objectForKey:#"Name"];
cell.lblcount.tag=indexPath.row;
[cell.stepper addTarget:self action:#selector(itemsChange:) forControlEvents:UIControlEventValueChanged];
return cell;
}
- (void)itemsChange:(UIStepper*)stepper
{
CGPoint cursorPosition = [stepper convertPoint:CGPointZero toView:self.tableview];
NSIndexPath *indexPath = [self.tableview indexPathForRowAtPoint:cursorPosition];
custom *currentCell = (custom *)[self.tableview cellForRowAtIndexPath:indexPath];
currentCell.lblcount.text=[NSString stringWithFormat:#"%f",[stepper value]];
[self.arrayCounts replaceObjectAtIndex:indexPath.row withObject:[NSString stringWithFormat:#"%f",[stepper value]]];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)placeorder:(id)sender {
}
#end
I am stuck into three days please solve my problem
Thanks in ADVANCE.
#Arpit replace your code with Arry.
viewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController<UITableViewDataSource,UITableViewDelegate>
#property (weak, nonatomic) IBOutlet UITableView *tableview;
#property (strong, nonatomic)NSMutableArray *arrayCounts;
- (IBAction)placeorder:(id)sender;
#property (weak, nonatomic) IBOutlet UIButton *placeorder;
#end
ViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
[NSThread detachNewThreadSelector:#selector(fetchdata) toTarget:self withObject:nil];
self.arrayCounts = [NSMutableArray array];
NSLog(#"array count=%lu",(unsigned long)self.arrayCounts.count);
}
-(void)fetchdata
{
NSArray *tempArray = #[#{#"Dry_cleaning" : #"49",
#"Iron":#"5",
#"Name":#"Shirt/Tees",
#"Wash":#"20",
#"Wash_Iron":#"19",
#"id":#"1"},
#{#"Dry_cleaning" : #"49",
#"Iron":#"5",
#"Name":#"Kurta(short)",
#"Wash":#"20",
#"Wash_Iron":#"19",
#"id":#"2"},
#{#"Dry_cleaning" : #"49",
#"Iron":#"5",
#"Name":#"Kurta(Long)",
#"Wash":#"15",
#"Wash_Iron":#"20",
#"id":#"3"},
#{#"Dry_cleaning" : #"50",
#"Iron":#"5",
#"Name":#"Shorts",
#"Wash":#"15",
#"Wash_Iron":#"19",
#"id":#"4"},
#{#"Dry_cleaning" : #"51",
#"Iron":#"5",
#"Name":#"Trousers/Pyjamas",
#"Wash":#"20",
#"Wash_Iron":#"19",
#"id":#"5"}];
// remove comment from below code and add where responce will come. -----------------
// NSArray *tempArray = dic_property[#"Data"];
[tempArray enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
NSMutableDictionary *dictValues = [NSMutableDictionary dictionaryWithDictionary:obj];
[dictValues setValue:#"0" forKey:#"counts"];
[self.arrayCounts addObject:dictValues];
}];
[self.tableview reloadData];
//--------------------------------
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return self.arrayCounts.count;
// return [[dic_property objectForKey:#"Data"]count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
custom *cell;
static NSString *simpleTableIdentifier = #"customcell";
cell = (custom *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
cell = [[[NSBundle mainBundle] loadNibNamed:#"custom" owner:self options:nil] objectAtIndex:0];
cell.lblCount.text = self.arrayCounts[indexPath.row][#"counts"];
cell.lbltitle.text=self.arrayCounts[indexPath.row][#"Name"];;
[cell.stepper addTarget:self action:#selector(itemsChange:) forControlEvents:UIControlEventValueChanged];
return cell;
}
- (void)itemsChange:(UIStepper*)stepper
{
CGPoint cursorPosition = [stepper convertPoint:CGPointZero toView:self.tableview];
NSIndexPath *indexPath = [self.tableview indexPathForRowAtPoint:cursorPosition];
custom *currentCell = (custom *)[self.tableview cellForRowAtIndexPath:indexPath];
double value = [stepper value];
[currentCell.lblCount setText:[NSString stringWithFormat:#"%d", (int)value]];
self.arrayCounts[indexPath.row][#"counts"] = [NSString stringWithFormat:#"%d",(int)value];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
}
- (IBAction)placeorder:(id)sender {
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"counts != %#",#"0"];
NSArray *filteredArray = [self.arrayCounts filteredArrayUsingPredicate:predicate];
NSLog(#"yoyr arry:%#",filteredArray);
}
You are following the wrong way to do this. Just use an array which have initial value 0 on all index and set array value to label in cellForRowAtIndexPath than update the array index value on click on stepper event than reload your table with updated array.

Expanding and collapsing tableView sections iOS?

I am able to expand and collapse the tableView sections successfully however I am not able to do it for individual sections so far.So all the sections collapse or expand at the same time, which is because I call [tableView reloadData] .So How can I expand or collapse a particular section?
Here is how I am doing it currently.
-(UIView*)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
headerLabel = [[UILabel alloc]init];
headerLabel.tag = section;
headerLabel.userInteractionEnabled = YES;
headerLabel.backgroundColor = [[UIColor grayColor]colorWithAlphaComponent:0.2];
headerLabel.text = [menuCategoryArray objectAtIndex:section];
headerLabel.frame = CGRectMake(5, 0, tableView.tableHeaderView.frame.size.width, tableView.tableHeaderView.frame.size.height);
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(headerClicked:)];
tapGesture.cancelsTouchesInView = NO;
[headerLabel addGestureRecognizer:tapGesture];
return headerLabel;
}
-(void)headerClicked:(UIGestureRecognizer*)sender
{
if (!isShowingList) {
isShowingList=YES;
[self.menuTableView reloadData];
UILabel *lbl = (UILabel*)sender.view;
NSLog(#"header no : %d", lbl.tag);
}else{
isShowingList=NO;
[self.menuTableView reloadData];
UILabel *lbl = (UILabel*)sender.view;
NSLog(#"header no : %d", lbl.tag);
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
if (isShowingList) {
return [[[[jsonArray valueForKey:#"menus"] valueForKey:#"menuName"] objectAtIndex:section] count];
}else{
return 0;
}
return 0;
}
First take isShowingList as
#property (nonatomic, strong) NSMutableArray *isShowingList;
And for identifying previously opened section you need another property
#property (nonatomic, assign) NSInteger openSectionIndex;
when you have the data initialized, isShowingList in you case, initialize isShowingList array before reloading table
self.isShowingList = [NSMutableArray array];
if (jsonArray && [jsonArray valueForKey:#"menus"] && [[jsonArray valueForKey:#"menus"] valueForKey:#"menuName"]) {
for (int i = 0; i < [[[jsonArray valueForKey:#"menus"] valueForKey:#"menuName"] count]; i++) {
[self.isShowingList addObject:[NSNumber numberWithBool:NO]];
}
}
and initialize openSectionIndex in viewDidLoad() like this
self.openSectionIndex = NSNotFound;
and your code should be changed like this
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if ([[self.isShowingList objectAtIndex:section] boolValue]) {
return [[[[jsonArray valueForKey:#"menus"] valueForKey:#"menuName"] objectAtIndex:section] count];
} else {
return 0;
}
return 0;
}
-(void)headerClicked:(UIGestureRecognizer*)sender {
UILabel *lbl = (UILabel*)sender.view;
NSLog(#"header no : %d", lbl.tag);
if ([[self.isShowingList objectAtIndex:lbl.tag] boolValue]) {
[self closeSection:lbl.tag];
} else {
[self openSection:lbl.tag];
}
}
//methods for expanding and collapsing sections
- (void)openSection:(NSInteger)section {
[self.isShowingList replaceObjectAtIndex:section withObject:[NSNumber numberWithBool:YES]];
NSInteger countOfRowsToInsert = [[[[jsonArray valueForKey:#"menus"] valueForKey:#"menuName"] objectAtIndex:section] count];
NSMutableArray *indexPathsToInsert = [[NSMutableArray alloc] init];
for (NSInteger i = 0; i < countOfRowsToInsert; i++) {
[indexPathsToInsert addObject:[NSIndexPath indexPathForRow:i inSection:section]];
}
NSMutableArray *indexPathsToDelete = [[NSMutableArray alloc] init];
NSInteger previousOpenSectionIndex = self.openSectionIndex;
if (previousOpenSectionIndex != NSNotFound) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.menuTableView reloadSections:[NSIndexSet indexSetWithIndex:previousOpenSectionIndex] withRowAnimation:UITableViewRowAnimationNone];
});
[self.isShowingList replaceObjectAtIndex:previousOpenSectionIndex withObject:[NSNumber numberWithBool:NO]];
NSInteger countOfRowsToDelete = [[[[jsonArray valueForKey:#"menus"] valueForKey:#"menuName"] objectAtIndex:previousOpenSectionIndex] count];
for (NSInteger i = 0; i < countOfRowsToDelete; i++) {
[indexPathsToDelete addObject:[NSIndexPath indexPathForRow:i inSection:previousOpenSectionIndex]];
}
}
// Apply the updates.
[self.menuTableView beginUpdates];
[self.menuTableView insertRowsAtIndexPaths:indexPathsToInsert withRowAnimation:UITableViewRowAnimationAutomatic];
[self.menuTableView deleteRowsAtIndexPaths:indexPathsToDelete withRowAnimation:UITableViewRowAnimationAutomatic];
[self.menuTableView endUpdates];
self.openSectionIndex = section;
}
- (void)closeSection:(NSInteger)section {
[self.isShowingList replaceObjectAtIndex:section withObject:[NSNumber numberWithBool:NO]];
NSInteger countOfRowsToDelete = [self.menuTableView numberOfRowsInSection:section];
if (countOfRowsToDelete > 0) {
NSMutableArray *indexPathsToDelete = [[NSMutableArray alloc] init];
for (NSInteger i = 0; i < countOfRowsToInsert; i++) {
[indexPathsToDelete addObject:[NSIndexPath indexPathForRow:i inSection:section]];
}
[self.menuTableView deleteRowsAtIndexPaths:indexPathsToDelete withRowAnimation:UITableViewRowAnimationTop];
}
self.openSectionIndex = NSNotFound;
}
You really would be better off looking at using a 'tableView update block'. Please take a look at this viewController for an answer I posted very recently. The updateBlock allows you to manipulate some variable or other which affects the dataSource, and instruct the table to add/remove rows/sections in order to reflect that change. Note that when you call the endUpdates method the table must not conflict with the model or you'll get an exception.
#import "ViewController.h"
//dont worry, the header is empty except for import <UIKit/UIKit.h>, this is a subclass on UIViewController
#interface ViewController ()<UITableViewDataSource, UITableViewDelegate>
#property (weak, nonatomic) UITableView *tableView;
#end
#implementation ViewController
{
//ivars
BOOL sectionIsOpen[4]; //we will use this BOOL array to keep track of the open/closed state for each section. Obviously I have the number of sections fixed at 4 here, but you could make a more dynamic array with malloc() if neccesary..
}
- (void)viewDidLoad {
[super viewDidLoad];
UITableView *tv = [[UITableView alloc]initWithFrame:self.view.bounds style:UITableViewStyleGrouped];
tv.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
tv.dataSource = self;
tv.delegate = self;
[self.view addSubview:tv];
self.tableView = tv;
// Do any additional setup after loading the view, typically from a nib.
}
#pragma mark - UITableViewDataSource
-(NSInteger )numberOfSectionsInTableView:(UITableView *)tableView{
return 4;
}
-(NSInteger )tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return ((sectionIsOpen[section]) ? [self numberOfRowsInSection:section] : 0);
}
-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{
//put your switch() here...
return [NSString stringWithFormat:#"I am section %i", (int)section ];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *cellId = #"cellID";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellId];
if (!cell) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellId];
}
//etc etc decorate your cell...
cell.textLabel.text = [NSString stringWithFormat:#"cell %i / %i", (int)indexPath.section, (int)indexPath.row ];
return cell;
}
#pragma mark - UITableViewDelegate
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{
const CGRect fr = CGRectMake(0, 0, 320.0, 40.0 );
UIButton *btn = [[UIButton alloc]initWithFrame:fr];
[btn setTitle:[self tableView:tableView titleForHeaderInSection:section] forState:UIControlStateNormal ];
[btn setTag:section];
[btn addTarget:self action:#selector(sectionOpenToggle:) forControlEvents:UIControlEventTouchUpInside];
// add an image, colour etc if you like
return btn;
}
#pragma mark - tableViewHelpers
//the number of rows in sectionX when it is open...
-(NSInteger )numberOfRowsInSection:(NSInteger )section{
//get your count from your model
return section + 1;
}
//opening/closing a section
-(void )setSection:(NSInteger )section toOpen:(BOOL )open{
if (open != sectionIsOpen[section]) {
//build an array of indexPath objects
NSMutableArray *indxPths = [NSMutableArray array];
for (NSInteger row = 0; row < [self numberOfRowsInSection:section]; row ++) {
[indxPths addObject: [NSIndexPath indexPathForRow:row inSection:section ]
];
}
[self.tableView beginUpdates];
if (open) {
[self.tableView insertRowsAtIndexPaths:indxPths withRowAnimation:UITableViewRowAnimationFade];
//nb there is a large ENUM of tableViewRowAnimation types to experiment with..
}else{
[self.tableView deleteRowsAtIndexPaths:indxPths withRowAnimation:UITableViewRowAnimationFade];
}
sectionIsOpen[section] = open;
[self.tableView endUpdates];
}
}
-(void )sectionOpenToggle:(id )sender{
[self setSection:[sender tag] toOpen: !sectionIsOpen[[sender tag]] ];
}
// open/close all sections.
-(void )setAllSectionsOpen:(BOOL )open{
for (NSInteger section = 0; section < [self numberOfSectionsInTableView:self.tableView]; section ++) {
[self setSection:section toOpen:open];
}
}
//these two for your convenience, hook up to navbar items etc..
-(IBAction)openAllSections:(id)sender{
[self setAllSectionsOpen:YES];
}
-(IBAction)closeAllSections:(id)sender{
[self setAllSectionsOpen:NO];
}
#end

Problems in setting imageview on a selected cell in tableview in ios

I am having an app in which I am showing some data in my tableview as shown in the ScreenShot1 below.
Screenshot1.
Now I am having an imageview On my each tableview cell.
If I select any of the cell from tableview, I want an image on that selected cell as shown in screenshot2 below.
Screenshot2.
Now If I select any other cell form tableview. I want to set my imageview's image only on those selected cells as shown in Screenshot3 below.
Below is the code I am doing.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
lblRecipe = [[UILabel alloc] initWithFrame:CGRectMake(50, 5, 600, 32)];
lblRecipe.backgroundColor = [UIColor clearColor];
lblRecipe.font = [UIFont systemFontOfSize:20.0f];
[cell.contentView addSubview:lblRecipe];
checkedimg=[[UIImageView alloc]initWithFrame:CGRectMake(40, 20, 500, 5)];
[cell.contentView addSubview:checkedimg];
lblRecipe.text = [array objectAtIndex:indexPath.row];
return cell;
}
On Tableview's didselect method, what should i keep to have this kind of a functionality?
I searched a lot and there are lots of questions for this but couldn't find one for this.
So Please help me on this.
Thanks in advance.
You may be better off just subclassing UITableViewCell, as this would let you change the way the cells draw, and add a property or something of the sort to indicate this state.
To create the subclass, create a new file in Xcode, and select UITableViewCell as its superclass.
Then, within that subclass, you could implement a method called setStrikeThrough: like this that you can call on the cell you dequeue from the table:
- (void) setStrikeThrough:(BOOL) striked {
if(striked) {
// create image view here and display, if it doesn't exist
} else {
// hide image view
}
}
Then, in the view controller that holds the table, you'd call this in viewDidLoad to register your subclass with the table view:
[_tableView registerClass:[YourAmazingTableCell class] forCellReuseIdentifier:#"AmazingCellSubclass"];
You would then alter your tableView:cellForRowAtIndexPath: to be something like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"AmazingCellSubclass";
YourAmazingTableCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[YourAmazingTableCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// here you would look up if this row should be selected
[cell setStrikeThrough:YES];
// Set up the remainder of the cell, again based on the row
cell.textLabel.text = #"chilli";
return cell;
}
Try this,
Add a NSMutableArray checkedCellArray, as property and alloc init.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
UILabel *labelRecipe = [[UILabel alloc] initWithFrame:CGRectMake(50, 5, 600, 32)];
labelRecipe.backgroundColor = [UIColor clearColor];
labelRecipe.font = [UIFont systemFontOfSize:20.0f];
labelRecipe.tag = kRecipeTag;//a tag to label
[cell.contentView addSubview:labelRecipe];
UIImageView *checkedimg = [[UIImageView alloc]initWithFrame:CGRectMake(40, 20, 500, 5)];
[checkedimg setImage:[UIImage imageNamed:#"checked.png"];
checkedimg.tag = kCheckedImageTag;//a tag to imageView
[cell.contentView addSubview:checkedimg];
checkedimg.hidden = YES;
}
UILabel *labelRecipe = (UILabel *)[cell.contentView viewWithTag:kRecipeTag];
UIImageView *checkedimg = (UIImageView *)[cell.contentView viewWithTag:kCheckedImageTag];
if ([self.checkedCellArray containsObject:indexPath]) {
checkedimg.hidden = NO;
} else {
checkedimg.hidden = YES;
}
labelRecipe.text = [array objectAtIndex:indexPath.row];
return cell;
}
and in didSelectRowAtIndexPath:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (![self.checkedCellArray containsObject:indexPath]) {
[self.checkedCellArray addObject:indexPath];
}
NSArray* rowsToReload = [NSArray arrayWithObjects:indexPath, nil];
[UITableView reloadRowsAtIndexPaths:rowsToReload withRowAnimation:UITableViewRowAnimationNone];
}
Oky hear you can do like this
just subclass the tableview cell
in CustomCell.h file
#import <UIKit/UIKit.h>
#interface CustomCell : UITableViewCell
#property (nonatomic,retain)UIImageView *dashImageView; //add a property of image view
#end
in CustomCell.m file
#import "CustomCell.h"
#implementation CustomCell
{
BOOL isCellSelected; //add this to check
}
#synthesize dashImageView = _dashImageView; //synthesize it
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
isCellSelected = NO;//initially set it no
_dashImageView = [[UIImageView alloc]initWithFrame:CGRectMake(self.bounds.origin.x + 15, self.bounds.origin.y + 10, self.bounds.size.width, 15.0f)];
_dashImageView.backgroundColor = [UIColor redColor];
_dashImageView.tag = 12345;
_dashImageView.hidden = YES;
[self.contentView addSubview:_dashImageView];
}
return self;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
if(selected)
{
UIImageView *dashImageVIew = (UIImageView *)[self viewWithTag:12345];
if(dashImageVIew)
{
if(!isCellSelected)
{
dashImageVIew.hidden = NO;
isCellSelected = YES;
}
else
{
dashImageVIew.hidden = YES;
isCellSelected = NO;
}
}
}
}
EDIT:2 *For selecting both section and row for the table view*
there is no change in the custom cell only change in the controller so that u hav to reflect what changes that u made to tableview cell i.e weather u select or deselect
since u want select section along with the selected row.(your requirement) there are various way to do that, but i go by using some model object which contains index section and row.
for that u need to create a subclass of NSObject and name it as MySelectedIndex then in
in MySelectedIndex.h file
#import <Foundation/Foundation.h>
#interface MySelectedIndex : NSObject<NSCoding>//to store and retrieve data like user defaults, for non-property list objects, confirms to NSCoding protocol
#property (nonatomic,retain) NSNumber *selectedRow;
#property (nonatomic,retain) NSNumber *selectedSection;
- (id)initWithSelectedRow:(NSNumber *)selRow andSelectedIndex:(NSNumber *)selSection;
#end
in MySelectedIndex.m file
#import "MySelectedIndex.h"
#implementation MySelectedIndex
#synthesize selectedSection = _selectedSection;
#synthesize selectedRow = _selectedRow;
- (id)initWithSelectedRow:(NSNumber *)selRow andSelectedIndex:(NSNumber *)selSection
{
self = [super init];
if(self)
{
_selectedRow = selRow;
_selectedSection = selSection;
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder
{
[aCoder encodeObject:_selectedRow forKey:#"ROW"];
[aCoder encodeObject:_selectedSection forKey:#"SECTION"];
}
-(id)initWithCoder:(NSCoder *)aDecoder
{
self = [super init];
if(self)
{
_selectedRow = [aDecoder decodeObjectForKey:#"ROW"];
_selectedSection = [aDecoder decodeObjectForKey:#"SECTION"];
}
return self;
}
#end
now get back to controller where u are using the table
in .m file
import it #import "CustomCell.h"
and in the method
in viewController.m
#interface SampleViewController ()<UITableViewDataSource,UITableViewDelegate>
{
NSMutableArray *indexes;//to store in defaults
NSMutableArray *indexesRed;//to red from the defaults
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
//...other stuff's
indexes = [[NSMutableArray alloc]init];//initilise your arrays
indexesRed = [[NSMutableArray alloc]init];
//after initilizing your array
NSData *data = [[NSUserDefaults standardUserDefaults] objectForKey:#"SELECTED_CELLL"];
if(data != nil)
{
indexes = [NSKeyedUnarchiver unarchiveObjectWithData:data];
[indexes retain];//you hav to retain the objects other wise u will get crash, make sure u will release it by proper memory mabagement (if u are not using ARC)
}
}
as u said u are using buttons to pop this viewcontroller so already u know where to place so put this in all the action methods(just replace where u are saving to user defaults )
and also read the comments that i put in the code
//put all these codes where u poping this viewcontroller
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:indexes];
[[NSUserDefaults standardUserDefaults] setObject:data forKey:#"SELECTED_CELLL"];
[[NSUserDefaults standardUserDefaults] synchronize];
[self.navigationController popViewControllerAnimated:YES];
replace the cellForRowAtIndexPath by following code (i added in the below method)
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:( NSIndexPath *)indexPath
{
CustomTabedCell *Cell = [tableView dequeueReusableCellWithIdentifier:#"CELL"];
if(Cell == nil)
{
Cell = [[CustomTabedCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"CELL"];
}
Cell.textLabel.text = #"Apple";
NSNumber *rowNum = [NSNumber numberWithInt:indexPath.row];
NSNumber *secNum = [NSNumber numberWithInt:indexPath.section];
__block BOOL isImageHidden = YES;
[indexes enumerateObjectsUsingBlock:^(MySelectedIndex *obj, NSUInteger idx, BOOL *stop)
{
if(obj.selectedRow == rowNum && obj.selectedSection == secNum)
{
isImageHidden = NO;
}
}];
Cell.dashImageView.hidden = isImageHidden;
[Cell.contentView bringSubviewToFront:Cell.dashImageView];//as i notised the red dash imageview appers below the text, but in your image it is appearing above the text so put this line to bring the imageview above the text if dont want commnent this
return Cell;
}
finally in the method didSelectRowAtIndexPath replace by following method
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSNumber *selSection = [NSNumber numberWithInt:indexPath.section];
NSNumber *selRow = [NSNumber numberWithInt:indexPath.row];
if([indexes count] == 0)
{
MySelectedIndex *selectedIndx = [[MySelectedIndex alloc]initWithSelectedRow:selRow andSelectedIndex:selSection];
[indexes addObject:selectedIndx];
}
else if ([indexes count] == 1)
{
MySelectedIndex *singleIndex = [indexes objectAtIndex:0];
if(singleIndex.selectedSection == selSection & singleIndex.selectedRow == selRow)
{
[indexes removeAllObjects];
}
else
{
MySelectedIndex *selectedIndx = [[MySelectedIndex alloc]initWithSelectedRow:selRow andSelectedIndex:selSection];
[indexes addObject:selectedIndx];
}
}
else
{
__block BOOL addSelectedRow = NO;
__block int index = -1;
[indexes enumerateObjectsUsingBlock:^(MySelectedIndex *obj, NSUInteger idx, BOOL *stop) {
if(!((obj.selectedRow == selRow) & (obj.selectedSection == selSection)))
{
addSelectedRow = YES;
}
else
{
index = idx;
addSelectedRow = NO;
*stop = YES;
}
}];
if(addSelectedRow)
{
MySelectedIndex *selectedIndx = [[MySelectedIndex alloc]initWithSelectedRow:selRow andSelectedIndex:selSection];
[indexes addObject:selectedIndx];
}
else
{
if(index >= 0)
{
[indexes removeObjectAtIndex:index];
}
}
}
NSLog(#"%#",indexes.description);
[tableView reloadData];
}
edit for not able to select more than 13 row's
in viewDidLoad
do like this
indexes = [[NSMutableArray alloc]init];
indexesRed = [[NSMutableArray alloc]init];
NSData *data = [[NSUserDefaults standardUserDefaults] objectForKey:#"SELECTED_CELLL"];
if(data != nil)
{
indexes = [[NSKeyedUnarchiver unarchiveObjectWithData:data] retain]; //hear only u retain it
NSLog(#"%#",indexes.description);//check the description, how many objects are there in the array
NSLog(#"indexes->%d",[indexes count]);
}
//[indexes retain];//comment this
} //end of `viewDidLoad`
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
CustomTabedCell *Cell = [tableView dequeueReusableCellWithIdentifier:#"CELL"];
if(Cell == nil)
{
Cell = [[CustomTabedCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"CELL"];
}
Cell.textLabel.text = #"Apple";
__block BOOL isImageHidden = YES; //remove that __block qualifier
// __block NSInteger currentRow = indexPath.row;
// __block NSInteger currentSection = indexPath.section;
// [self.indexes enumerateObjectsUsingBlock:^(MySelectedIndex *obj, NSUInteger idx, BOOL *stop)
// {
// NSInteger rowNum = [obj.selectedRow integerValue];
// NSInteger secNum = [obj.selectedSection integerValue];
// if(rowNum == currentRow && secNum == currentSection)
// {
// isImageHidden = NO;
// }
// }];
//comment block code and use simple for loop, looping through each obj slightly faster
for(int k = 0;k < [indexes count];k++)
{
MySelectedIndex *seletedIndex = [indexes objectAtIndex:k];
NSInteger row = [seletedIndex.selectedRow integerValue];
NSInteger sec = [seletedIndex.selectedSection integerValue];
if(row == indexPath.row & sec == indexPath.section)
{
isImageHidden = NO;
}
}
Cell.dashImageView.hidden = isImageHidden;
[Cell.contentView bringSubviewToFront:Cell.dashImageView];//as i notised the red dash imageview appers below the text, but in your image it is appearing above the text so put this line to bring the imageview above the text if dont want commnent this
return Cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSNumber *selSection = [NSNumber numberWithInt:indexPath.section];
NSNumber *selRow = [NSNumber numberWithInt:indexPath.row];
if([indexes count] == 0)
{
MySelectedIndex *selectedIndx = [[MySelectedIndex alloc]initWithSelectedRow:selRow andSelectedIndex:selSection];
[indexes addObject:selectedIndx];
}
else if ([indexes count] == 1)
{
MySelectedIndex *singleIndex = [indexes objectAtIndex:0];
NSInteger rowNumInInt = [singleIndex.selectedRow integerValue];
NSInteger sectionInInt = [singleIndex.selectedSection integerValue];
if(sectionInInt == indexPath.section & rowNumInInt == indexPath.row)
{
[indexes removeAllObjects];
}
else
{
MySelectedIndex *selectedIndx = [[MySelectedIndex alloc]initWithSelectedRow:selRow andSelectedIndex:selSection];
[indexes addObject:selectedIndx];
}
}
else
{
BOOL addSelectedRow = NO;
int index = -1;
for(int j = 0; j < [indexes count];j++)
{
MySelectedIndex *selectedObj = [indexes objectAtIndex:j];
NSInteger rowInt = [selectedObj.selectedRow integerValue];
NSInteger sectionInt = [selectedObj.selectedSection integerValue];
if(!(rowInt == indexPath.row && sectionInt == indexPath.section))
{
addSelectedRow = YES;
}
else
{
index = j;
addSelectedRow = NO;
// *stop = YES;
}
}
if(addSelectedRow)
{
MySelectedIndex *selectedIndx = [[MySelectedIndex alloc]initWithSelectedRow:selRow andSelectedIndex:selSection];
[indexes addObject:selectedIndx];
}
else
{
if(index >= 0)
{
[indexes removeObjectAtIndex:index];
}
}
}
// [tableView reloadData];
NSLog(#"indexes count->%d",[indexes count]);//check each time by selecting and deselectin weateher it is working or not
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone];
}
thats it simple .. :)
hope this helps u .. :)
Try This it work good
#import "ViewController.h"
#interface ViewController ()<UITableViewDataSource,UITableViewDelegate>
{
UITableView *menuTableView;
NSMutableArray *colorsArray,*tagvalueArray;
}
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
menuTableView=[[UITableView alloc]initWithFrame:CGRectMake(0, 60, 320, 404) style:UITableViewStyleGrouped];
menuTableView.delegate=self;
menuTableView.dataSource=self;
menuTableView.separatorColor=[UIColor grayColor];
[self.view addSubview:menuTableView];
NSArray *serverResponseArray=[[NSArray alloc]initWithObjects:#"red",#"yellow",#"pink",#"none", nil]; // consider this array as the information you receive from DB or server
colorsArray =[[NSMutableArray alloc]init];
tagvalueArray =[[NSMutableArray alloc]init];
for (int i=0; i<serverResponseArray.count; i++) {
[colorsArray addObject:serverResponseArray[i]];
[tagvalueArray addObject:#"0"];
}
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return colorsArray.count;
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 40;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier];
}
for (UIView *view in cell.contentView.subviews) {
[view removeFromSuperview];
}
cell.textLabel.text =colorsArray[indexPath.row];
if ([[tagvalueArray objectAtIndex:indexPath.row]intValue]==1) {
UIImageView *checkedimg=[[UIImageView alloc]initWithFrame:CGRectMake(40, 20, 500, 5)];
checkedimg.backgroundColor=[UIColor redColor];
[cell.contentView addSubview:checkedimg];
}
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"%#",colorsArray[indexPath.row]);
[tagvalueArray replaceObjectAtIndex:indexPath.row withObject:#"1"];
[menuTableView reloadData];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end

UITableView with Json file, loading images to cell disappear

I am using asyncimageview classes nicely provided by: http://www.markj.net/iphone-asynchronous-table-image/
I am getting image urls from a json file and loading each image to a cell.
Problem:
When i scroll up, and scroll back down to the same cell, the image reloads (disappears and appears again). I can't figure out why the image keeps reloading? Does anyone have suggestions or a solution to how I could make it stop? Thanks in advance!
// Asks the data source to return a cell to insert in a particular table view location
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//Gets the current news article
NewsArticle *theCurrentArticle = [self.listofNewsArticles objectAtIndex:[indexPath row]];
//Gets the title from the current article
NSString *theTitle = theCurrentArticle.title;
//Gets the image url
NSString *imageUrl = theCurrentArticle.imageURL;
//Gets the description of the current news article
NSString *theDescription = theCurrentArticle.description;
NewsCustomCell *cell = (NewsCustomCell *)[tableView dequeueReusableCellWithIdentifier:#"NewsContent"];
__block NewsCustomCell *aCell;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
if (cell == nil) {
aCell = (NewsCustomCell *)[tableView dequeueReusableCellWithIdentifier:#"NewsContent"];
} else {
AsyncImageView* oldImage = (AsyncImageView*)
[cell.contentView viewWithTag:999];
[oldImage removeFromSuperview];
}
AsyncImageView *imageView = [[AsyncImageView alloc] initWithFrame:CGRectMake(5, 5, 100, 100)];
imageView.tag = 999;
dispatch_async(dispatch_get_main_queue(), ^{
[imageView loadImageFromURL:[NSURL URLWithString:imageUrl]];
[cell.contentView addSubview:imageView];
cell.titleLabel.text = theTitle;
cell.descriptionLabel.text = theDescription;
cell.imageLabel.contentMode = UIViewContentModeScaleAspectFill;
});
});
return cell;
}
Heres what the current app looks like:
Solution:
Just worked with this class I finally found.
https://github.com/rs/SDWebImage
This handles caching, async downloads. Wish I found this sooner..
I hope you have Write AsyncImageView and ImageCache and ImageCacheObject classes.
Write this code inside cellForRowAtIndexPath:
static NSString *CellIdentifier = #"CellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
Quest_Forum *Quest_ForumObj=[queArr objectAtIndex:i+indexPath.row];
// NSLog(#"cell for row at... i val.. %d",i+indexPath.row);
for(UIView * view in cell.contentView.subviews){
if([view isKindOfClass:[AsyncImageView class]])
{
// NSLog(#"remove old images");
[view removeFromSuperview];
view = nil;
}
}
AsyncImageView *asyncImageView = nil;
UIImageView *cellImage = (UIImageView *)[cell viewWithTag:1]; // Inside tableview i have taken tableviewcell and given tag 1 to that imageview
asyncImageView = [[AsyncImageView alloc] initWithFrame:cellImage.frame] ;
[asyncImageView loadImageFromURL:Quest_ForumObj.Quest_Image];
asyncImageView.backgroundColor=[UIColor clearColor];
[cell.contentView addSubview:asyncImageView];
UILabel *lblQuest = (UILabel *)[cell viewWithTag:2]; // Given tag 2 to the label inside tableViewCell
lblQuest.text=Quest_ForumObj.Question;
In ImageCacheObject.h
#class ImageCacheObject;
#interface ImageCache : NSObject
{
NSUInteger totalSize; // total number of bytes
NSUInteger maxSize; // maximum capacity
NSMutableDictionary *myDictionary;
}
#property (nonatomic, readonly) NSUInteger totalSize;
-(id)initWithMaxSize:(NSUInteger) max;
-(void)insertImage:(UIImage*)image withSize:(NSUInteger)sz forKey:(NSString*)key;
-(UIImage*)imageForKey:(NSString*)key;
In ImageCacheObject.m
#import "ImageCacheObject.h"
#synthesize totalSize;
-(id)initWithMaxSize:(NSUInteger) max
{
if (self = [super init])
{
totalSize = 0;
maxSize = max;
myDictionary = [[NSMutableDictionary alloc] init];
}
return self;
}
-(void)dealloc // Don't write this method if you are using ARC
{
[myDictionary release];
[super dealloc];
}
-(void)insertImage:(UIImage*)image withSize:(NSUInteger)sz forKey:(NSString*)key
{
// NSLog(#"count of insert image%d",sz);
ImageCacheObject *object = [[ImageCacheObject alloc] initWithSize:sz Image:image];
while (totalSize + sz > maxSize)
{
NSDate *oldestTime;
NSString *oldestKey;
for (NSString *key in [myDictionary allKeys])
{
ImageCacheObject *obj = [myDictionary objectForKey:key];
if (oldestTime == nil || [obj.timeStamp compare:oldestTime] == NSOrderedAscending)
{
oldestTime = obj.timeStamp;
oldestKey = key;
}
}
if (oldestKey == nil)
break; // shoudn't happen
ImageCacheObject *obj = [myDictionary objectForKey:oldestKey];
totalSize -= obj.size;
[myDictionary removeObjectForKey:oldestKey];
}
[myDictionary setObject:object forKey:key];
[object release];
}
-(UIImage*)imageForKey:(NSString*)key
{
ImageCacheObject *object = [myDictionary objectForKey:key];
if (object == nil)
return nil;
[object resetTimeStamp];
return object.image;
}
In ImageCacheObject.h
#interface ImageCacheObject : NSObject
{
NSUInteger size; // size in bytes of image data
NSDate *timeStamp; // time of last access
UIImage *image; // cached image
}
#property (nonatomic, readonly) NSUInteger size;
#property (nonatomic, retain, readonly) NSDate *timeStamp;
#property (nonatomic, retain, readonly) UIImage *image;
-(id)initWithSize:(NSUInteger)sz Image:(UIImage*)anImage;
-(void)resetTimeStamp;
In ImageCacheObject.m
#synthesize size;
#synthesize timeStamp;
#synthesize image;
-(id)initWithSize:(NSUInteger)sz Image:(UIImage*)anImage
{
if (self = [super init])
{
size = sz;
timeStamp = [[NSDate date] retain];
image = [anImage retain];
}
return self;
}
-(void)resetTimeStamp
{
[timeStamp release];
timeStamp = [[NSDate date] retain];
}
-(void) dealloc
{
[timeStamp release];
[image release];
[super dealloc];
}

TableView does not reloaddata when I clicked "More data..." at the last row of tableView

Request my test webService for the data,
The tableView's last row is "More data..."
when click this row, send another request to get more data,
and I use [tableView reloaddata] many times, but there is nothing
happened, and I dont know why.So,please help me with this problem.
Thank you in advance.
and there is my tableViewController.h class:
#import <UIKit/UIKit.h>
#import "NoticeDetailViewController.h"
#interface NoticeViewController : UIViewController
<UITableViewDataSource,UITableViewDelegate>
{
NSMutableArray *allNoticeArray;
NSArray *addNoticeArray;
NSInteger totalNotice;
NSInteger pageIndex;
UITableView *tableView;
}
#property (nonatomic, retain) NSMutableArray *allNoticeArray;
#property (nonatomic, retain) NSArray *addNoticeArray;
#property NSInteger totalNotice;
#property NSInteger pageIndex;
#property (nonatomic, retain) UITableView *tableView;
- (NSMutableArray *)getNoticeList :(NSInteger)pageIndex;
#end
And tableViewController.m class:
#import "NoticeViewController.h"
#import "Notice.h"
#import "OAURLEncodingAdditions.h"
#interface NoticeViewController ()
#end
#implementation NoticeViewController
#synthesize allNoticeArray;
#synthesize addNoticeArray;
#synthesize pageIndex;
#synthesize tableView;
#synthesize totalNotice;
- (NSMutableArray *)getNoticeList :(NSInteger)pageIndex
{
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSString *userId = appDelegate.user.userId;
NSString *departmentId = appDelegate.user.departmentId;
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"https://xxx.xxx.xx.xx/FMS/Pages/Service/FMService.svc/GetAnnouncement?userId=%#&departmentId=%#&pageIndex=%d&pageSize=%d",userId,departmentId,self.pageIndex,1]];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setValidatesSecureCertificate:NO];
[request startSynchronous];
NSError *error = [request error];
if (!error)
{
NSString *responseString = [request responseString];
NSDictionary *responseDict = [responseString JSONValue];
NSArray *noticeArray = [responseDict objectForKey:#"d"];
NSMutableArray *arrayOfAllNotice = [[NSMutableArray alloc] init];
for (NSDictionary *noticeDic in noticeArray)
{
NSString *body = [noticeDic objectForKey:#"Body"];
NSString *departmentName = [noticeDic objectForKey:#"DepartmentName"];
NSString *noticeId = [noticeDic objectForKey:#"Id"];
NSString *isTop = [noticeDic objectForKey:#"IsTop"];
NSString *readState = [noticeDic objectForKey:#"ReadState"];
NSString *realName = [noticeDic objectForKey:#"RealName"];
NSString *title = [noticeDic objectForKey:#"Title"];
int noid = [noticeId intValue];
int isto = [isTop intValue];
int read = [readState intValue];
Notice *notice = [[Notice alloc] initWithBody:body
departmentName:departmentName
noticeId: noid
isTop:isto
readState:read
realName:realName
title:title];
[arrayOfAllNotice addObject:notice];
}
self.addNoticeArray = [[NSArray alloc] initWithArray:arrayOfAllNotice];
}
else
{
....
}
[allNoticeArray addObjectsFromArray:addNoticeArray];
NSLog(#"allNoticeArray count: %d",[allNoticeArray count]); //Here:When the last row clicked, the number changes:1->2
[self.tableView reloadData];
return allNoticeArray;
}
#pragma mark -
#pragma mark Table View Data Source Methods
- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSInteger theNumberOfRowsInSection;
if ( [allNoticeArray count] < (self.totalNotice))
{
theNumberOfRowsInSection = [allNoticeArray count]+1;
}
if ( [allNoticeArray count] == (self.totalNotice))
{
theNumberOfRowsInSection = [allNoticeArray count];
}
return theNumberOfRowsInSection;
}
- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
[self.tableView reloadData];
static NSString *NoticeListTableIdentifier = #"NoticeListTableIdentifier";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:NoticeListTableIdentifier];
if ( cell == nil )
{
cell = [[[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault reuseIdentifier:NoticeListTableIdentifier] autorelease];
}
if ( [allNoticeArray count] < (self.totalNotice) )
{
if ( [indexPath row] != [allNoticeArray count])
{
NSUInteger row = [indexPath row];
Notice *noticeOfTheRow = [allNoticeArray objectAtIndex:row];
NSString *title = noticeOfTheRow.title;
cell.textLabel.text = title;
}
else
{
cell.textLabel.text = #"More...";
}
}
if ( [allNoticeArray count] == (self.totalNotice) )
{
NSUInteger row = [indexPath row];
Notice *noticeOfTheRow = [allNoticeArray objectAtIndex:row];
NSString *title = noticeOfTheRow.title;
cell.textLabel.text = title;
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if ( [indexPath row] != [allNoticeArray count])
{
NSUInteger row = [indexPath row];
Notice *notice = [allNoticeArray objectAtIndex:row];
NSString *noticeDetailTitle = notice.title;
NoticeDetailViewController *noticeDetailViewController = [[[NoticeDetailViewController alloc] init] autorelease];
noticeDetailViewController.title = noticeDetailTitle;
ticeDetailViewController.noticeIdForGet = notice.noticeId;
[self.navigationController pushViewController:noticeDetailViewController animated:YES];
}
if ( [indexPath row] == [allNoticeArray count])
{
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
hud.labelText = #"reload...";
self.pageIndex ++;
[self getNoticeList:self.pageIndex];
[self.tableView reloadData];
[MBProgressHUD hideHUDForView:self.view animated:YES];
}
}
- (void)pushBack
{
[self dismissModalViewControllerAnimated:YES];
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.allNoticeArray = [[NSMutableArray alloc] init];
self.pageIndex = 1;
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
hud.labelText = #"reload...";
self.title = #"Notice";
UIBarButtonItem *leftButton = [[UIBarButtonItem alloc] initWithTitle:#"back"
style:UIBarButtonItemStyleBordered
target:self
action:#selector(pushBack)];
self.navigationItem.leftBarButtonItem = leftButton;
UIBarButtonItem *rightButton = [[UIBarButtonItem alloc] initWithTitle:#"reload"
style:UIBarButtonItemStyleBordered
target:self
action:#selector(reloadNotice)];
self.navigationItem.rightBarButtonItem = rightButton;
self.allNoticeArray = [self getNoticeList:self.pageIndex];
[MBProgressHUD hideHUDForView:self.view animated:YES];
}
#end
change:
if ( [indexPath row] == [allNoticeArray count])
to:
if ( [indexPath row] == [allNoticeArray count]-1)
The reason is that array (and row) indexing are base 0. So if an array has, say 3 objects, last object's index is 2
BTW,with the new language features, there's no need to declare the ivars in the interface. The compiler will take care of them if you have already declared the properties and synthesized them.
#interface NoticeViewController : UIViewController
<UITableViewDataSource,UITableViewDelegate>
{
NSMutableArray *allNoticeArray;
NSArray *addNoticeArray;
NSInteger totalNotice;
NSInteger pageIndex;
UITableView *tableView;
}
//...
#end

Resources