UITableView Repeats First Cell On Occasion - ios

My Code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = nil;
NSString *homeDir = NSHomeDirectory();
if(indexPath.section == 0){
homeDir = [NSString stringWithFormat: #"%#/%#", homeDir, #"Documents"];
}else{
homeDir = [NSString stringWithFormat: #"%#/%#", homeDir, #"Documents/Archived"];
}
NSFileManager *fm = [NSFileManager defaultManager];
NSArray *dirContents = [fm contentsOfDirectoryAtPath:homeDir error:nil];
dirContents = [[dirContents reverseObjectEnumerator] allObjects];
cell = [tableView dequeueReusableCellWithIdentifier:#"MyCell"];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"MyCell"];
}
UILongPressGestureRecognizer *lpgr = [[UILongPressGestureRecognizer alloc]
initWithTarget:self action:#selector(handleLongPress:)];
lpgr.minimumPressDuration = 1.3; //seconds
[cell addGestureRecognizer:lpgr];
int i = 0;
NSString *filename;
if([dirContents count] > 0){
filename = [[dirContents objectAtIndex:indexPath.row] lastPathComponent];
while(![[filename substringFromIndex: [filename length] - 3] isEqualToString:#"pdf"]){
i ++;
filename = [[dirContents objectAtIndex:indexPath.row + i] lastPathComponent];
}
}else{
filename = #" ";
}
cell.textLabel.text = filename;
return cell;
}
The issue I am having is that, on occasion, only the first cell returns repeatedly. If an array reads "Red, Blue, Green, Yellow" it appears as:
Red
Red
Red
Red
This happens only on occasion. Sometimes when refreshing the table, it displays correctly, only to later revert back to the incorrect display. What am I doing wrong?

I posted a comment above, but I'm going to try for an answer because I suspect this will fix your problem, if not just to show what is actually happening here.
A UITableView should have a datasource. In your original code you are creating this datasource (the array dirContents) every time the table view creates a new cell. It looks like your datasource is static, so you can create this outside of the UITableViewDataSource delegate method, and place it somewhere such as the viewDidLoad method. It's only an assumption of mine that this array is not being created in time to access the elements for your cell.
You can then confirm that your cell is grabbing the correct index from this array with a NSLog right before cell.textLabel.text = filename;.
Hopefully this helps you with your problem.

Marcel, you have to re-architect your code, you have put the code which gets file names from the directory in viewDidLoad and save these names in a global array and then in cellForRowAtIndex make use of this array.
For refreshing of tableView on each download, just reload uitableview as file is completely donwloaded. Hope it Helps!

Related

Updating uiprogress bar in cell rows

I am building an app that will allow users to download and read issues of a journal. I am using the Download Manager framework created by Robert Ryan and I modified the test project that came with the framework to have it work in my project (there are no issues with the framework). On each row in the table there is a Issue Cover Image (UIImageView), Download/Read label (UILabel), Issue Date label (UILabel), and a progress bar (UIProgressView) all are properties of a UITableViewCell. When a user taps the row, it initiates the download process of the issue which is reflected in the progress bar; after the download completes, the progress bar becomes hidden and the Download title of the label changes to Read, and when the user taps the row again to read the downloaded journal it opens a PDF viewer in a viewcontroller. I haven't added the Read functionality as yet. All this works fine except as a test I have 2 issues of the journal in the table each in a row with its ``. When I tap the first row, the progress bar reflects the download progress and it works fine. However, when I tap the second row, the download progress is reflected in the progress bar of the first row not the second row as expected (the progress bar remains static). It does download the second journal and everything works fine. It's just this unexpected behavior where the download progress of the second row is reflected in the progress bar in the first row. I still have to streamline the code and clean it up but the relevant code sections are below:
// optional method to indicate progress of individual download
//
// In this view controller, I'll update progress indicator for the download.
- (void)downloadManager:(DownloadManager *)downloadManager downloadDidReceiveData: (Download *)download;
{
for (NSInteger row = 0; row < [downloadManager.downloads count]; row++)
{
if (download == downloadManager.downloads[row])
{
[self updateProgressViewForIndexPath:[NSIndexPath indexPathForRow:row inSection:0] download:download];
break;
}
}
}
#pragma mark - Table View delegate and data source methods
// our table view will simply display a list of files being downloaded
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return[jitsArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"DownloadCell";
DownloadCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[DownloadCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
}
jits * jitsInstance = nil;
jitsInstance = [jitsArray objectAtIndex:indexPath.row];
cell.issue.text = jitsInstance.issue;
NSString * myCoverURL = [NSString stringWithFormat:#"%#", jitsInstance.coverimage];
UIImage* myImage = [UIImage imageWithData:
[NSData dataWithContentsOfURL:
[NSURL URLWithString: myCoverURL]]];
cell.coverimage.image = myImage;
[cell.progressView setProgress:0];
NSString * myURL = [NSString stringWithFormat:#"%#", jitsInstance.url];
NSString* documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *downloadFolder = [documentsPath stringByAppendingPathComponent:#"downloads"];
NSString * fileName = [[NSString alloc]initWithFormat:#"%#", [myURL lastPathComponent]];
NSString* foofile = [downloadFolder stringByAppendingPathComponent:fileName];
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:foofile];
NSLog(#"Search file path: %#", foofile);
if (!fileExists) {
[cell.downloadButton setTitle:#"Download" forState:normal];
[cell.progressView setHidden:NO];
NSLog(#"File does not exist!");
}
else if (fileExists){
NSLog(#"File exist!");
[cell.downloadButton setTitle:#"Read" forState:normal];
[cell.progressView setHidden:YES];
}
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
NSString *documentsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
NSString *downloadFolder = [documentsPath stringByAppendingPathComponent:#"downloads"];
jits * jitsInstance = nil;
jitsInstance = [jitsArray objectAtIndex:indexPath.row];
NSString * myURL = [NSString stringWithFormat:#"%#", jitsInstance.url];
self.downloadManager = [[DownloadManager alloc] initWithDelegate:self];
self.downloadManager.maxConcurrentDownloads = 4;
NSString *downloadFilename = [downloadFolder stringByAppendingPathComponent:[myURL lastPathComponent]];
NSURL *url = [NSURL URLWithString:myURL];
[self.downloadManager addDownloadWithFilename:downloadFilename URL:url];
self.cancelButton.enabled = YES;
self.startDate = [NSDate date];
[self.downloadManager start];
}
#pragma mark - Table view utility methods
- (void)updateProgressViewForIndexPath:(NSIndexPath *)indexPath download:(Download *)download
{
DownloadCell *cell = (DownloadCell *)[self.tableView cellForRowAtIndexPath: [NSIndexPath indexPathForRow:indexPath.row inSection:0]];
// if the cell is not visible, we can return
if (!cell)
return;
if (download.expectedContentLength >= 0)
{
// if the server was able to tell us the length of the file, then update progress view appropriately
// to reflect what % of the file has been downloaded
cell.progressView.progress = (double) download.progressContentLength / (double) download.expectedContentLength;
}
else
{
// if the server was unable to tell us the length of the file, we'll change the progress view, but
// it will just spin around and around, not really telling us the progress of the complete download,
// but at least we get some progress update as bytes are downloaded.
//
// This progress view will just be what % of the current megabyte has been downloaded
cell.progressView.progress = (double) (download.progressContentLength % 1000000L) / 1000000.0;
}
}
I think your issue may lie in the following code:
for (NSInteger row = 0; row < [downloadManager.downloads count]; row++)
{
if (download == downloadManager.downloads[row])
{
[self updateProgressViewForIndexPath:[NSIndexPath indexPathForRow:row inSection:0] download:download];
break;
}
}
What this seems like it's essentially doing is finding the first cell in the downloads array, calling updateProgressViewForIndexPath on that first cell it finds, then stopping. There are a number of ways to fix this issue, but the first that comes to mind is once you tell yourself to update the cell at that index path when the if-statement evaluates to true, remove that item from the downloadManager's downloads array, so next time through it won't be there. Give that a try and let me know if that works..
Also, on a side note... I would think that you don't want to do the following two lines every time a row is selected:
self.downloadManager = [[DownloadManager alloc] initWithDelegate:self];
self.downloadManager.maxConcurrentDownloads = 4;
It would seem to me that is something you'd want to do perhaps in your init method of your tableView so it only occurs once, rather than every time the user taps a row. Perhaps you're attempting to create and set as a property a new download manager every time? That sort of seems unorthodox to me. If I had access to the project I think I might be better help debugging. Any chance you'd want to share the project if my response didn't help?

When I add a new section (by stepper), the content of the cells in a section mixes with content of another section

I've a tableView with dynamic cells. Each section has 5 rows. In the first 4 rows for each row there is a text field. Instead in the fifth row there is an imageview (when I click on this row, I can choose a photo from my photo library, and this last will be put in imageView). The number of sections is decided at run-time using a stepper. The section 0 is fixed and contains a stepper. When I click on + button (on stepper) a section will be add. So everything is right but if I wrote before in the rows that contain the textfield, and then add one or more sections, the contents of these textfield are mixed with each other (and also between sections).
//In file.h I've declared #property (nonatomic) int numberOfComponents;
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1 + self.numberOfComponents;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (section == 0) {
return 1;
}
else{
return 4;
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == 0) {
NSString *CellIdentifier = #"cellStepper";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
UILabel *stepperLabel = (UILabel *)[cell viewWithTag:1];
stepperLabel.text = [NSString stringWithFormat:#"%i",self.numberOfComponents];
UIStepper *stepper = (UIStepper *)[cell viewWithTag:2];
stepper.minimumValue = 0;
stepper.maximumValue = 20;
stepper.stepValue = 1;
stepper.autorepeat = YES;
stepper.continuous = YES;
return cell;
}
if (indexPath.row == 4) {
NSString *CellIdentifier = #"cellProfileSnap";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
return cell;
}
NSString *CellIdentifier = #"cellDetail";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
UITextField *cellLabelComponent = (UITextField *)[cell viewWithTag:3];
cellLabelComponent.placeholder = #"detail";
return cell;
}
- (IBAction)stepperClik:(UIStepper *)stepper{
if (stepper.value == 0 && self.numberOfComponents == 0) {
if (stepper.value > self.numberOfComponents) {
self.numberOfComponents += 1;
}
else{
return;
}
}
if (stepper.value > self.numberOfComponents) {
self.numberOfComponents += 1;
}
else{
self.numberOfComponents -= 1;
}
[self.tableView reloadData];
}
Solved by Greg, but now there's another problem: I have a save button, which should save many arrays into a dictionary (containing the details of each section 5) as the number of sections.
Here the code of save button:
- (IBAction)saveButton:(id)sender{
NSMutableArray *arrComponents = [[NSMutableArray alloc] init];
for (int i = 0; i < self.numberOfComponents; i++)
{
NSMutableArray *component = [[NSMutableArray alloc] init];
for (int j = 0; j < [self.arrDetails count]; j++)
{
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:j inSection:i+1];
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath: indexPath];
if (j == 4){
UIImageView *imageComponent = (UIImageView *) [cell viewWithTag:4];
NSLog(#"%#",imageComponent.image);
if (imageComponent.image == Nil) {
[component addObject: nil];
}
[component addObject: imageComponent.image];
}
else{
UITextField *detailComponent = (UITextField *) [cell viewWithTag:3];
NSLog(#"%#",detailComponent.text);
if ([detailComponent.text isEqualToString:#""]) {
[component addObject:#""];
}
if (detailComponent.text != nil && i != 0)
[component addObject: detailComponent.text];
}
}
[arrComponents addObject: component];
NSLog(#"%#",arrComponents);
}
Where it is shown in the code / / ERROR HERE, at the fourth iteration of 5 iterations (number of rows in a section) of the latest iteration (last section read), the application crashes giving this message:
Terminating app due to uncaught exception
'NSInvalidArgumentException', reason: '*** -[__NSArrayM
insertObject:atIndex:]: object cannot be nil'
I believe your detailComponent is equal nil and you cannot save nil to the array. Before you call
[component addObject: detailComponent.text]; //ERROR HERE
do check:
if (detailComponent != nil && i != 0)
[component addObject: detailComponent.text];
It could happen because in your section 0 you haven't got any textfield.
//EDITED
The issue is happened here:
if (imageComponent.image == Nil) {
[component addObject: nil];
}
[component addObject: imageComponent.image];
Replace it with:
if (imageComponent.image == nil) {
[component addObject:[NSNull null]];
}
else {
[component addObject: imageComponent.image];
}
You cannot add nil to array if you want to add nil you should add object NSNull.
And you are missing else statement. Your code try to add nil to the array twice (if the image is nil) first time in your if statement ([component addObject: nil];) and second time just after your if statement: [component addObject: imageComponent.image];
// EDITED
Make the changes as suggested in comments in code below. I use the same dictionary, you should change the name because it suggest that it keeps just textfields values, but now it will store the images as well:
if (indexPath.row == 4) {
NSString *CellIdentifier = #"cellProfileSnap";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
//I believe this is where you keep your imageView
// get your image
UIImageView *imageComponent = (UIImageView *) [cell viewWithTag:4];
NSString *key = [NSString stringWithFormat:#"sec:%d,row:%d", indexPath.section, indexPath.row];
if (self.textValueDictionary[key])
imageComponent.image = self.textValueDictionary[key];
else
imageComponent.image = nil; //Your default value (probably you want to set up your plus image)
return cell;
}
The next step you need to make is where the user presses the plus image - you have to save the image in the dictionary. Put this code to your method where you get the image from user. This is a pseudo code so you have to adjust it a little bit:
// Get reference to the cell
UITableViewCell *cell = //have a look on textFieldDidEndEditing method. You have to work out how to get the cell (I cannot do that because I haven't got access to your code);
// Get index path
NSIndexPath *indexPath = [self.myTableView indexPathForCell:cell];
// Get section as a string
NSString *key = [NSString stringWithFormat:#"sec:%d,row:%d", indexPath.section, indexPath.row];
UIImage *img = //get your image here;
//make sure it's not nil before you save it to dictionary
//save it to dictionary
[self.textValueDictionary setValue:img forKey:key];
The last bit is saveButton: method there was mistake in my advices from yesterday. You're trying to get text and image directly from cells, and it works fine if the cells are visible. If you cannot see the cell system put it to reusable pool and you get nils.
To fix it you have to get the data from the dictionary:
Don't use:
UIImageView *imageComponent = (UIImageView *) [cell viewWithTag:4];
instead do:
NSString *key = [NSString stringWithFormat:#"sec:%d,row:%d", indexPath.section, indexPath.row];
UIImage *img = self.textValueDictionary[key];
// make sure is not nil before you save it. If it's nil add [NSNull nil] to your array as I explained before.
When you read text don't do it like that:
UITextField *detailComponent = (UITextField *) [cell viewWithTag:3];
get text from the dictionary:
NSString *key = [NSString stringWithFormat:#"sec:%d,row:%d", indexPath.section, indexPath.row];
NSString *str = self.textValueDictionary[key];
If it complain about data type use cast (UIImage*).
Remember to change your first loop to: for (int i = 1; i < self.numberOfComponents; i++) and when you get NSIndexPath change it to inSection:i instead inSection:i+1.
I haven't run this in Xcode so maybe there are some mistakes but you should be able to find and fix it.
Hope it will work for you.
It happens because you don't save the cellLabelComponent.text property and when you reloadData tableView reuses cell (which cause this problem).
You should save data you entered to your cellLabelComponent (for example in array, you can use UITextFieldDelegate) and in your cellForRowAtIndexPath: method you should assign saved values to desired field.
//EXTENDED
Conform to <UITextFieldDelegate> protocol in your .h file or class extension.
Add
#property (nonatomic, strong) NSMutableDictionary *textValueDictionary;
to your class extension and allocate it and init in viewDidLoad or init method:
self.textValueDictionary = [[NSMutableDictionary alloc] init];
Add this to cellForRowArIndexPath:
cellLabelComponent.placeholder = #"detail";
// Make your class to be delegate for UITextField
cellLabelComponent.delegate = self;
// I use NSString (section) as a key in my dictionary. You can use NSNumber if you like
if (self.textValueDictionary[[NSString stringWithFormat:#"%d", indexPath.section]])
cellLabelComponent.text = self.textValueDictionary[[NSString stringWithFormat:#"%d", indexPath.section]];
else
cellLabelComponent.text = #""; //Your default value
Add your UITextFieldDelegate methods:
- (void)textFieldDidEndEditing:(UITextField *)textField
{
// Get reference to the cell
UITableViewCell *cell = (UITableViewCell*)[[[textField superview] superview] superview];
// Get index path
NSIndexPath *indexPath = [self.myTableView indexPathForCell:cell];
// Get section as a string
NSString *section = [NSString stringWithFormat:#"%d", indexPath.section];
[self.textValueDictionary setValue:textField.text forKey:section];
}
You can use more delegate if you need.
It should be enough to make it works. It will work just when you have one UITextField in your table section if you have more you should use unique key in your dictionary (NSindexPath will work if you have more that one textfield in section but not more that one in row, just remember to convert it to NSNumber).
Let me know is it work.
//EXTENDED
If you have more that one UITextField per section you have to change the dictionary key. This solution above will work just if you have up to one row per section.
This solution (below) will work if you have many textfields per section but not more that one text field per cell (it will work for one textfield per section as well):
Change line in cellForRowAtIndexPath from:
if (self.textValueDictionary[[NSString stringWithFormat:#"%d", indexPath.section]])
cellLabelComponent.text = self.textValueDictionary[[NSString stringWithFormat:#"%d", indexPath.section]];
to:
NSString *key = [NSString stringWithFormat:#"sec:%d,row:%d", indexPath.section, indexPath.row];
if (self.textValueDictionary[key])
cellLabelComponent.text = self.textValueDictionary[key];
And change lines in textFieldDidEndEditing: method from:
NSString *section = [NSString stringWithFormat:#"%d", indexPath.section];
[self.textValueDictionary setValue:textField.text forKey:section];
to:
NSString *key = [NSString stringWithFormat:#"sec:%d,row:%d", indexPath.section, indexPath.row];
[self.textValueDictionary setValue:textField.text forKey:key];

Objective-C : Table cell just returns last information of matching data

I'm trying to insert data into the rows I've created, I will get all info in my Log but it only shows the last info in all of my rows. Could anyone suggest a way to avoid this error?
Please offer me some advice thanks!
You are never re-populating the cells, actually. You are creating the initial visible cells, and just reusing them with the same content.. please look below:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath
*)indexPath
{
static NSString *CellIdentifier = #"TestCell";
TestCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
// HERE YOU ONLY WANT TO INSTANTIATE THE CELL
NSArray *topObjects = [[NSBundle mainBundle] loadNibNamed:#"TestCell" owner:nil options:nil];
for (id currentObject in topObjects)
{
if([currentObject isKindOfClass:[TestCell class]])
{
cell = (TestCell *) currentObject;
break;
}
}
}
// HERE YOU WOULD ACTUALLY POPULATE THE CELL WITH DATA
NSArray *array = [server get_texts:10 offset:0 sort_by:0 search_for:#""];
NSMutableString *s = [[NSMutableString alloc] init];
for (testMetaData *m in array){
[s appendFormat:#"%# %# \n", m.title,m.note];
cell.title.text = m.title;
NSLog(#" title %# ", m.title);
}
return cell;
}
Some info about UITableView:
So, a properly setup tableView only allocates and uses a limited number of UITableViewCells. After allocating, say 5 cells (this number is determined by "How many cells can you see at any given time?"), it will take an already created cell that has been scrolled out of the visible area, and gives it back to you in that method you are using, so you can re-populate it. So, cell variable will not be nil at that time, and your server code never gets called.
I think it has to do with your for loop.
NSMutableString *s = [[NSMutableString alloc] init];
for (testMetaData *m in array){
[s appendFormat:#"%# %# \n", m.title,m.note];
cell.title.text = m.title;
NSLog(#" title %# ", m.title);
}
Your cell.title.text = m.titlewill get the last m.title info at the end of the for loop.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath
*)indexPath
{
//Load Cell for reuse
static NSString *CellIdentifier = #"TestCell";
TestCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell =[ [[NSBundle mainBundle] loadNibNamed:#"TestCell" owner:nil options:nil] lastObject];
}
//appending text and config cell
NSArray *array = [server get_texts:10 offset:0 sort_by:0 search_for:#""];
NSString *t = [array objectAtIndex:indexPath.row];
//Config cell - Not sure what you want. Maybe 10 different rows
cell.title.text = t;
return cell;
}

iOS UITableViewCells rows recycled and tag not working

I would like to seek some help in setting tag for buttons in cells. This is a question with a link to the previous I posted : iOS Using NSDictionary to load data into section and rows
However, though I could pass in data dynamically now, my renewal button on each of the rows could not seem to get the data and would only detect the same book title of each section when any of the rows in the section is selected.
Based on what I've read so far, it's because the button is being recycled hence, unable to detect which book is being selected properly. I've tried to set tag:
cell.renewButton.tag = indexPath.row;
How my code looks like now:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier = #"Cell";
UserCustomCell *cell = (UserCustomCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
cell.bookTitle.frame = CGRectMake(12, 0, 550, 40);
if (cell == nil) {
[[NSBundle mainBundle] loadNibNamed:#"UserCustomCell" owner:self options:nil];
cell = userCustomCell;
self.userCustomCell = nil;
cell.renewButton.tag = indexPath.row;
}
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
cell.bookTitle.frame = CGRectMake(12, 0, 550, 40);
cell.renewButton.frame = CGRectMake(600, 14, 68, 24);
}
[cell.renewButton useBlackActionSheetStyle];
//########## EDIT STARTS HERE
dataSource = [[NSMutableDictionary alloc] init]; // This would need to be an ivar
for (NSDictionary *rawItem in myArray) {
NSString *date = [rawItem objectForKey:#"date"]; // Store in the dictionary using the data as the key
NSMutableArray *section = [dataSource objectForKey:date]; // Grab the section that corresponds to the date
if (!section) { // If there is no section then create one and add it to the dataSource
section = [[NSMutableArray alloc] init];
[dataSource setObject:section forKey:date];
}
[section addObject:rawItem]; // add your object
}
self.dataSource = dataSource;
//NSLog(#"Data Source Dictionary: %#", dataSource);
NSArray *sections =[[dataSource allKeys] sortedArrayUsingSelector:#selector(caseInsensitiveCompare:)];
NSString *sectionTitle = [sections objectAtIndex:indexPath.section];
NSArray *items = [dataSource objectForKey:sectionTitle];
NSDictionary *dict = [items objectAtIndex:indexPath.row];
cell.bookTitle.text = [dict objectForKey:#"name"];
cell.detail.text = [NSString stringWithFormat:#"Due Date: %# Due Time: %#",
[dict objectForKey:#"date"], [dict objectForKey:#"time"]];
cell.renewButton.tag = indexPath.row;
return cell;
}
but it doesn't work at all. Would be sooooo grateful for any suggestions :) Thank you!!
P.S: My copy of xcode is not updated, only till version4. Saw some people mentioning storing of tag status in DataModel but it's only available in newer versions. :)
You cannot use the button tags, as these will be the same as those of the cells they have been recycled from. Instead, use the indexPath to determine on which row you are and use that directly. No need to go through the button tag.
I could not see your cell.renewButton being assigned a selector method (the method that should be triggered on tapping the button).
[cell.renewButton addTarget:self action:#selector(renewButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
Also, I would specify a tag number with an offset, as tag of 0 is almost like not tagging at all. First row of tableView will give indexPath.row = 0.
Above your code,
#define OFFSET 100 /* Or any number greater than 0 */
In cellForRowAtIndexPath,
...
[cell.renewButton addTarget:self action:#selector(renewButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
cell.renewbutton.tag = indexPath.row + OFFSET;
...
In the renewButtonPressed method,
-(void)renewButtonPressed:(id)sender
{
tappedNum = [sender tag] - OFFSET;
/* do your stuff */
}
tappedNum will give you the row that the button is tapped, starting with 0.

List Contents of Directory in a UITableView

I am trying to list the contents of Ringtones directory in a TableView, however, I am only getting the last file in the directory in ALL cells, instead of file per cell. This is my code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
Profile_ManagerAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
cell.hidesAccessoryWhenEditing = YES;
}
cell.accessoryType = UITableViewCellAccessoryNone;
//cell.textLabel.text = #"No Ringtones";
//cell.textLabel.text = #"Test";
NSString *theFiles;
NSFileManager *manager = [NSFileManager defaultManager];
NSArray *fileList = [manager directoryContentsAtPath:#"/Test"];
for (NSString *s in fileList){
theFiles = s;
}
cell.textLabel.text = theFiles;
return cell;
}
It loads fine, no errors, when I use NSLog it lists all the files in the directory just fine. I even tried [s objectAtIndex:indexPath.row] but i get objectAtIndex: error. Anyone have any ideas?
I actually love asking questions on here, cause in less than 10 minutes, I answer my own question!
This is how I got the above code to work:
NSMutableArray *theFiles;
NSFileManager *manager = [NSFileManager defaultManager];
NSArray *fileList = [manager directoryContentsAtPath:#"/Test"];
for (NSString *s in fileList){
theFiles = fileList;
}
cell.textLabel.text = [theFiles objectAtIndex:indexPath.row];
return cell;
I just made the NSString an NSMutableArray, and that allowed me to use the objectAtIndex. Now to trim the file extension!
You should remove NSString,NSMutableArray and for loop.. the final code should be like this:
NSFileManager *manager = [NSFileManager defaultManager];
NSArray *fileList = [manager directoryContentsAtPath:#"/Test"];
cell.textLabel.text = [fileList objectAtIndex:indexPath.row];
return cell;
BTW, this fileList and manager created repeatedly for each cell.. So it is better to make it a global variable for UITableViewController and assign only 1
Your for loop is just iterating over the files and setting theFiles to the current path. So at the end of the loop, theFiles will just be the last string in the collection.
Try something like:
cell.textLabel.text = [fileList objectAtIndex:indexPath.row];

Resources