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];
Related
I've got the code below to fill up an array of notifications. This array is needed to fill up a menu in my iOS app with notifications.
// extract specific value...
NSArray *switchValues = [res objectForKey:#"data"];
NSLog(#"%#", switchValues);
for (NSDictionary *switchValue in switchValues) {
NSString *text = [switchValue objectForKey:#"text"];
NSLog(#"%#", text);
[self.notificationsArray addObject:text];
}
Further down the line I then do this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
NSMutableArray *titles = self.notificationsArray;
cell.textLabel.text = titles[indexPath.row];
return cell;
}
However, I keep getting an empty array. What am I doing wrong?
Why don't you do
[notificationsArray objectAtIndex:indexPath.row]
instead of
NSMutableArray *titles = self.notificationsArray;
cell.textLabel.text = titles[indexPath.row];
?
If you really dont want, at least do
NSMutableArray *titles = [NSMutableArray arrayWithArray:self.notificationsArray];
And in the first piece of code, what are the Console Logs? Are you sure you enter in the for loop?
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!
I am saving an object from core data to a cell as listed bellow. The URL is being saved to the cell correctly and working great. My problem is that, when a user taps on a cell, I would like the URL that is saved to that cell to be passed to my detailedViewController for use. I have some code that I have tried but the url is nil in the detailedViewController. If you have any better way of accomplishing the same thing, that would be fine. The code is listed bellow -
Here is where I save it to the cell:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"Cell";
PhotoCell *cell = (PhotoCell *)[self.tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (!cell) {
cell = [[PhotoCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier];
}
// Configure the cell...
FeedEntity *feed = [_fetchedResultsController objectAtIndexPath:indexPath];
NSData *data = feed.imageData;
self.feedImage = [UIImage imageWithData:data];
cell.thumbImage = self.feedImage;
NSData *stringData = feed.urlString;
self.stringForURL = [[NSString alloc] initWithData:stringData encoding:NSUTF8StringEncoding];
self.stringForURL = [self.stringForURL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
self.finalURL = [NSURL URLWithString:self.stringForURL];
cell.finalURL = self.finalURL;
return cell;
}
Here is where I retrieve the url from the cell and pass it to the detailedViewController:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSManagedObject *object = [[self fetchedResultsController] objectAtIndexPath:indexPath];
// Code to create detailed view and set properties
self.detailsViewController = [[DetailsViewController alloc] init];
NSIndexPath *path = [self.tableView indexPathForSelectedRow];
FeedEntity *feed = [_fetchedResultsController objectAtIndexPath:path];
NSData *stringData = feed.urlString;
NSString *stringURL = [[NSString alloc] initWithData:stringData encoding:NSUTF8StringEncoding];
NSLog(#"Here is the string before: %#", stringURL);
stringURL = [self.stringForURL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *urlForDetail = [NSURL URLWithString:self.stringForURL];
NSLog(#"Here is the url before it goes to the detailed: %#", urlForDetail);
self.detailsViewController.finalURL = urlForDetail;
[self.navigationController pushViewController:self.detailsViewController animated:YES];
}
Save the video (in didFinishPickingMediaWithInfo:):
self.videoURL = [info objectForKey:UIImagePickerControllerMediaURL];
NSData *videoData = [NSData dataWithContentsOfURL:self.videoURL];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingFormat:#"/vid1.mp4"];
self.urlForSave = [NSURL fileURLWithPath:path];
//Look at YES
[videoData writeToFile:path atomically:YES];
[self saveImageAndVideo];
Here is SaveVideoAndPhoto:
- (void)saveImageAndVideo {
NSManagedObjectContext *context = [self managedObjectContext];
FeedEntity *feedEntity = [NSEntityDescription insertNewObjectForEntityForName:#"FeedEntity" inManagedObjectContext:context];
NSData *imageData = UIImageJPEGRepresentation(self.thumbImage, 0.8f);
self.photoData = imageData;
NSString *stringForSave = [self.urlForSave absoluteString];
NSLog(#"URL before save: %#", stringForSave);
//NSData * stringData = [stringForSave dataUsingEncoding:NSUTF8StringEncoding];
[feedEntity setValue:imageData forKey:#"imageData"];
[feedEntity setValue:[NSDate date] forKey:#"timeStamp"];
[feedEntity setValue: stringForSave forKey:#"urlString"];
NSError *error = nil;
if (![self.managedObjectContext save:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
} else {
NSLog(#"URL's are being saved");
}
}
Your problem is in the code in cellForRowAtIndexPath:
self.finalURL = [NSURL URLWithString:self.stringForURL];
You are setting the URL as a property of SELF, which in this case is your viewController. You want to set it on the CELL. Change all that code when you create the cell from self.whatever to cell.whatever if you want to save them as properties of the cell. It might help you if you did some reading up on scope in objective-c.
Also, on a side note, there are a few things you are doing that are unnecessary. Firstly is this:
NSIndexPath *path = [self.tableView indexPathForSelectedRow];
You don't need to create an indexPath object inside this function, because you are already provided it by the function itself with the variable indexPath:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
Secondly, inside of didSelectRowAtIndexPath, if you want to get the url, you should be doing something like this:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// deselect the row if you want the cell to fade out automatically after tapping
[tableView deselectRowAtIndexPath:indexPath animated:YES];
// get a reference to the cell that the user tapped
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
// get the url from the cell, assuming your cell has a property called finalURL on it that you set some value
// to originally when it was created
NSURL *url = cell.finalURL;
// do something with that URL here...
}
Keep in mind this is slightly unorthodox. You really should get the information from your tableView's datasource. If you have an array of objects that you are using to populate your tableView, it's probably a better idea to simply get the object itself from our array with the given indexPath rather than save the information on the cell as a property and access it that way. I would highly suggest watching some tutorial videos or do some reading up, preferably in the iOS docs themselves, to try to learn best practices for UITableViews.
New to coding and trying to create a simple check list (like a shopping list) for part of my iOS programme. Selecting a cell changes the accessory icon ok and changing the BOOL value in the dictionary manually before running the simulator also changes the acc' icon fine. So the problem seems to be with the code for altering the BOOL value in the plist after a cell is selected. Any help would massively appreciated. As I said pretty new to it so apologies for any shoddy code or obvious mistakes.
*CODE EDITED SO NO LONGER READING AND WRITING LIST FROM MAIN BUNDLE
#import "CheckListViewController.h"
#import "ListItem.h"
#interface CheckListViewController ()
#end
#implementation CheckListViewController
{
NSMutableArray *eventList;
}
#synthesize tableView = _tableView;
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString* dataPath = [documentsDirectory stringByAppendingPathComponent:#"CheckList.plist"];
if ( ![[NSFileManager defaultManager] fileExistsAtPath:dataPath]) {
NSString* resourceaPath = [[NSBundle mainBundle] pathForResource:#"CheckList" ofType:#"plist"];
[[NSFileManager defaultManager] copyItemAtPath:resourceaPath toPath:dataPath error:NULL];
}
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"CheckList.plist"];
NSMutableDictionary* dict = [[NSMutableDictionary alloc] initWithContentsOfFile:path];
ListItem *listItem1 = [ListItem new];
listItem1.itemName = #"Read Guide";
listItem1.itemSelected = [dict valueForKey:#"Read Guide"];
.....
eventList = [NSMutableArray arrayWithObjects:listItem1, listItem2, listItem3, listItem4, listItem5, listItem6, listItem7, listItem8, nil];
[self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
//Return the number of rows in the section.
return eventList.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"SimpleTableItem";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
ListItem *listItem = [eventList objectAtIndex:indexPath.row];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
if (listItem.itemSelected == [NSNumber numberWithBool:YES]) {
(cell.accessoryType = UITableViewCellAccessoryCheckmark);
} else {
(cell.accessoryType = UITableViewCellAccessoryNone);
}
}
cell.textLabel.text = listItem.itemName;
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:[tableView indexPathForSelectedRow] animated:NO];
ListItem *listItem = [eventList objectAtIndex:indexPath.row];
UITableViewCell *cell = [tableView cellForRowAtIndexPath: indexPath];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"CheckList.plist"];
NSMutableDictionary* dict = [[NSMutableDictionary alloc] initWithContentsOfFile:path];
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
if (cell.accessoryType == UITableViewCellAccessoryNone) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
// Reflect selection in data model
[dict setObject:[NSNumber numberWithBool:YES] forKey:listItem.itemSelected];
[dict writeToFile:path atomically:YES];
} else if (cell.accessoryType == UITableViewCellAccessoryCheckmark) {
cell.accessoryType = UITableViewCellAccessoryNone;
// Reflect deselection in data model
[dict setObject:[NSNumber numberWithBool:NO] forKey:listItem.itemSelected];
[dict writeToFile:path atomically:YES];
}
}
#end
Sorry for the massive chunk of code but thought any of it could potentially be problematic.
It looks like the path you are saving to and load from are different. You are loading from a bundle path, and then saving to a relative path with writeToFile:atomically. If my guess is correct, the default path for that method is not back into the bundle, but the documents directory of the app. On iOS, you cannot write back to the main bundle, so there a very good chance the file is not being saved where you think it is.
I have a plist (images.plist) with the following contents
As you can see, each item has a numerical key, from 0-19. Each item also has two strings (fileName and fileInfo).
I'm trying to load all of the fileName's into a TableView. Here's my attempt:
RosterMasterViewController.h
#interface RosterMasterViewController : UITableViewController
#property (nonatomic, strong) NSDictionary *roster;
#end
RosterMasterViewController.m
#implementation RosterMasterViewController
#synthesize roster = _roster;
...
// This is in my 'viewDidLoad'
NSString *file = [[NSBundle mainBundle] pathForResource:#"images" ofType:#"plist"];
self.roster = [NSDictionary dictionaryWithContentsOfFile:file];
And here's how I'm trying to load the fileName into the Prototype Cells.
RosterMasterViewController.m
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"imageNameCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Configure the cell
cell.textLabel.text = [[[self.roster allKeys] objectAtIndex:indexPath.row] objectForKey:#"fileName"];
return cell;
}
NOTE
For the record, my CellIdentifier is correct, if I set the cell.textLabel.text to be #"HELLO!", then I will see "HELLO!" for each item in the NSDictionary. I'm having difficulty with the //Configure the cell section
Unfortunately this isn't working as I expected. I'm having difficulty since my keys are all numerical I think.
UPDATE
Trying to use what I've learned from the answers below, I have this:
// Configure the cell
NSLog(#"Key: %#", [NSNumber numberWithInt:indexPath.row]);
NSDictionary *dict = [self.roster objectForKey:[NSNumber numberWithInt:indexPath.row]];
NSLog(#"Dictionary: %#", dict);
NSString *fileName = [dict objectForKey:#"fileName"];
NSLog(#"FileName: %#", fileName);
cell.textLabel.text = fileName;
return cell;
But that's giving me results like:
2012-02-03 11:24:24.295 Roster[31754:f803] Key: 7
2012-02-03 11:24:24.295 Roster[31754:f803] Dictionary: (null)
2012-02-03 11:24:24.296 Roster[31754:f803] FileName: (null)
If I change this line:
NSDictionary *dict = [self.roster objectForKey:[NSNumber numberWithInt:indexPath.row]];
to:
NSDictionary *dict = [self.roster objectForKey:#"5"];
Then all of the cells will have the correct fileName for the 6th element. Any idea why [NSNumber numberWithInt:indexPath.row isn't working?
You can do this:
NSDictionary *dict = [self.roster objectForKey:indexPath.row];
NSString *fileName = [dict objectForKey:#"fileName"];
As pointed out by Oscar, self.roster it's a NSDictionary wich have inside of him dictionaries for each numeric key.
You must first retrieve the NSDictionary for the numeric key: NSDictionary *fileDictionary = [self.roster objectForKey:indexPath.row];
After that you must extract your filename from this last dictionary so you must request the string for the #"fileName" key.
NSString *fileName = [fileDictionary objectForKey:#"fileName"];
cell.textLabel.text = fileName;
return cell;
No sure if you solved the problem already, but below is how I solved this issue.
NSDictionary *dict =
[self.allItem objectForKey:[NSString stringWithFormat:#"%d",indexPath.row]];
I think the reason was [NSNumber numberWithInt:indexPath.row] is returning number/int value.
But objectForKey: is expecting to receive a string value.
Hope this help.