I am trying to setup a UITableView that displays the data from the Documents Directory.
I am a bit lost for code, as I have tried many examples from Google and forums etc.
I am creating my app without Storyboard, so it is all in code.
I have got the UITableView displayed, so the delegates and DataView are set - I just need the content.
I have this code to show you, but it is not showing any data:
- (void)viewDidLoad
{
[super viewDidLoad];
_firstViewWithOutNavBar = [[UIView alloc] init];
_firstViewWithOutNavBar.frame = CGRectMake(self.view.frame.origin.x, 0, self.v iew.frame.size.width, self.view.frame.size.height);
_firstViewWithOutNavBar.backgroundColor = [UIColor whiteColor];
[self.view addSubview:_firstViewWithOutNavBar];
UITableView *tableView = [[UITableView alloc] init];
tableView.frame = CGRectMake(self.view.frame.origin.x, 0, self.view.frame.size.width, self.view.frame.size.height);
tableView.delegate = self;
tableView.dataSource = self;
[_firstViewWithOutNavBar addSubview:tableView];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//alloc and init view with custom init method that accepts NSString* argument
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:indexPath.row];
NSString*pathToPass = [documentsDirectory stringByAppendingPathComponent:
[tableView cellForRowAtIndexPath:indexPath].textLabel.text]; //pass this.
NSLog(#"%#", pathToPass);
//_nsarray = [[NSArray alloc] initWithContentsOfFile:pathToPass];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [_nsarray count];
NSLog(#"%#", _nsarray);
}
- (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];
}
cell.textLabel.text = [NSString stringWithFormat:#"%#",[_nsarray objectAtIndex:indexPath.row]];
return cell;
}
Any help would be great.
The array _nsarray which is used as table view data source in numberOfRowsInSection and cellForRowAtIndexPath, is never initialized in your code. You should do something like
NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
_nsarray = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:docPath error:NULL];
in viewDidLoad.
Did you place the breakpoints in numberOfRowsInSection method to check whether this method has been invoked or not. As I can see in your code you don't have initialize your _nsarray and didn't add any object in that array.
So basically your array contains 0 objects so no row will be created.
In your numberOfRowsInSection method You have placed the nslog after the return statement and this will never be executed please place it before the return statement so that you can actually see the array values.
I hope this will help you.
Related
My main goal is to be able to click on a table view item and load a video. The table view is populated with the contents of the documents directory and I have been able to do this successfully and add the filename to the cell's label, I have done this with the following code:
void)viewDidLoad
{
[super viewDidLoad];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0]; // Get documents folder
NSString *dataPath = documentsDirectory;
filePathsArray = [[NSFileManager defaultManager] subpathsOfDirectoryAtPath:dataPath error:nil];
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [filePathsArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"SimpleTableCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
cell.textLabel.text = [filePathsArray objectAtIndex:indexPath.row];
return cell;
}
However the part I am finding difficult is opening the file part. This is my code so far:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"didSelectRowAtIndexPath");
myURL=[NSURL URLWithString:[filePathsArray objectAtIndex:indexPath.row]];
MPMoviePlayerController *moviePlayerController = [[MPMoviePlayerController alloc] initWithContentURL:myURL];
[self.view addSubview:moviePlayerController.view];
moviePlayerController.fullscreen = YES;
[moviePlayerController play];
[self setController:moviePlayerController];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
What happens when a user clicks on a UITableView cell is that the video player opens full screen and it just says "loading..." the entire time and the video does not load, no errors are reported either in the debugger. What should the variable myURL be set equal to? Any help would be greatly appreciated.
Finally figured it out after a while there was two problems it was only fetching the name not the full file directory e.g. var/mobile... and there was a problem with the video player too, this is the working code for anyone wanting to do the same as me:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"didSelectRowAtIndexPath");
NSString *currentFileName = [filePathsArray[indexPath.row] lastPathComponent];
NSString *documentsDirectoryPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *filePath = [documentsDirectoryPath stringByAppendingPathComponent:currentFileName];
//Play the movie now
NSURL *videoURL =[NSURL fileURLWithPath:filePath];
MPMoviePlayerViewController *videoPlayerView = [[MPMoviePlayerViewController alloc] initWithContentURL:videoURL];
videoPlayerView.moviePlayer.fullscreen=TRUE;
[self presentMoviePlayerViewControllerAnimated:videoPlayerView];
[videoPlayerView.moviePlayer play];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
A NSURL is different from a path as in it contains the protocol used to access the resource.
For example, the http:// in the http://stackoverflow.com
I guess the problem is that you're creating a URL from a path string, try this:
NSString *urlStr = [NSString stringWithFormat:#"file://%#", [filePathsArray objectAtIndex:indexPath.row]];
myURL = [NSURL URLWithString:urlStr];
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.
This question already has answers here:
Objective-C: how to add a new cell for each filename in UiTableView?
(2 answers)
Closed 9 years ago.
Bellow I have some code that retrieves files from the documents directory where my application is stored on the idevice. It then successfully retrieves that path to the file which is a mp4 because that is what I am storing. And does this by displaying the filename in a cell of the UiTableView I have created . However the code only displays one file in one cell. But I want to list multiple files individually in there own cell so eventually the user can individually select that cell depending on the video file they want.
Here is the code that retrieves and displays the file directory of the file but does not list more then one file in the table:
- (void)viewDidLoad
{
[super viewDidLoad];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
filePathsArray = [[NSFileManager defaultManager] subpathsOfDirectoryAtPath:documentsDirectory error:nil];
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
if(!filePathsArray) // if data loading has been completed, return the number of rows ELSE return 1
{
if ([filePathsArray count] > 0)
return [filePathsArray count];
else
return 1;
}
return 1;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"MainCell"];
if (cell == nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"MainCell"];
}
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
filePathsArray = [[NSFileManager defaultManager] subpathsOfDirectoryAtPath:documentsDirectory error:nil];
cell.textLabel.text = [filePathsArray[indexPath.row] lastPathComponent];
return cell;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
if(!filePathsArray)
{
if ([filePathsArray count] > 0)
return [filePathsArray count];
else
return 1;
}
return 1;
}
Should read:
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return [filePathsArray count];
}
You should be returning [filePathsArray count]; from your numberOfRowsInSection method under normal circumstances. Right now you're actually returning 1 from that method in all cases. I'm not sure what exactly you're trying to do with the logic at the top of your numberOfRowsInSection method, but I think you should start by just replacing the whole body of the method with return [filePathsArray count];.
One more thing: You have a comment in there "if data loading has completed," but all the work in the code you posted is going synchronously on the main thread. By the time your viewDidLoad method has completed your filePathsArray is initialized. You don't need to do anything tricky to account for a case where filePathsArray is still nil, unless you're worried about the table view loading data before the view controller's view has actually loaded. But that would be very weird.
Why are you initializing filePathsArray over and over again first under viewDidLoad and then under tableview.
This is how I would write the code.
- (void)viewDidLoad
{
[super viewDidLoad];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
//initializing array and getting values the first time when page loads.
filePathsArray = [[NSFileManager defaultManager] subpathsOfDirectoryAtPath:documentsDirectory error:nil];
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
//return whatever the count of this array is. no need to do any if! checks
return [filePathsArray count];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"MainCell"];
if (cell == nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"MainCell"];
}
cell.textLabel.text = [filePathsArray[indexPath.row] lastPathComponent];
return cell;
}
I am facing a problem where the didselectrowatindexpath is not getting called.
My tableview is set in viewdidload as follows:
- (void)viewDidLoad
{
//[super viewDidLoad];
self.tableView.delegate = self;
self.tableView.dataSource = self;
[self.tableView reloadData];
self.detailViewController = (klViewController *)[[self.splitViewController.viewControllers lastObject] topViewController];
}
Now my cellForRowAtIndexPath gets called and I am reusing the cells as follows:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"menuSelection1";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
AmbassadorInfoData * data = [self.LoadMenuItems objectAtIndex:indexPath.row];
cell.textLabel.text = data.treeName;
return cell;
}
I have checked other answers and mostly said that there could be the use of didDeselectRowAtIndexPath might be used. But this is not the case here.
Now my problem is in my split view controller whenever I select any option the corresponding detail view doesn't get displayed and is blank. None of my methods in the rootview controller (klViewController) gets called. What could be the reason for this?
Following are the all methods related to UITableView. It is implemented in the same class as in viewDidLoad
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [self.LoadMenuItems count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"menuSelection1";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
AmbassadorInfoData * data = [self.LoadMenuItems objectAtIndex:indexPath.row];
cell.textLabel.text = data.treeName;
return cell;
}
-(NSArray *)LoadMenuItems
{
NSMutableArray * menuData = [[NSMutableArray alloc] initWithCapacity:5];
AmbassadorInfoData * data = [[AmbassadorInfoData alloc] init];
data.treeName = #"Ambassador Info";
data.treeDescription = #"This is temp data.";
NSString * file = [[NSBundle mainBundle] pathForResource:#"oak" ofType:#"jpg"];
data.treePhoto = [UIImage imageWithContentsOfFile:file];
[menuData addObject:data];
data=nil;
data = [[AmbassadorInfoData alloc] init];
data.treeName = #"AmbassadorInternalList";
data.treeDescription = #"This is temp data.).";
file = [[NSBundle mainBundle] pathForResource:#"DouglasFir" ofType:#"jpg"];
data.treePhoto = [UIImage imageWithContentsOfFile:file];
[menuData addObject:data];
data=nil;
data = [[AmbassadorInfoData alloc] init];
data.treeName = #"Text 3";
data.treeDescription = #"This is temp data.";
file = [[NSBundle mainBundle] pathForResource:#"SugarMaple" ofType:#"jpg"];
data.treePhoto = [UIImage imageWithContentsOfFile:file];
[menuData addObject:data];
data=nil;
data = [[AmbassadorInfoData alloc] init];
data.treeName = #"Text 4";
data.treeDescription = #"This is temp data.";
file = [[NSBundle mainBundle] pathForResource:#"RedMaple" ofType:#"jpg"];
data.treePhoto = [UIImage imageWithContentsOfFile:file];
[menuData addObject:data];
data=nil;
data = [[AmbassadorInfoData alloc] init];
data.treeName = #"Text 5";
data.treeDescription = #"This is temp data.";
file = [[NSBundle mainBundle] pathForResource:#"Pine" ofType:#"jpg"];
data.treePhoto = [UIImage imageWithContentsOfFile:file];
[menuData addObject:data];
menuItems = [[NSArray alloc] initWithArray:(NSArray *)menuData];
data=nil;
return menuItems;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
AmbassadorInfoData * selectedItem =(AmbassadorInfoData *)[self.menuItems objectAtIndex:[self.tableView indexPathForSelectedRow].row];
detailObject = selectedItem;
[detailViewController setDetailItem:detailObject];
}
#end
It could be that your program is stuck in a long running operation because of the way you're using LoadMenuItems. Every time numberOfRowsInSection and cellForRowAtIndexPath is called, you're recreating the entire array -- this is bad. You should call LoadMenuItems once, in viewDidLoad perhaps, and once you've created that array, use it, not a call to LoadMenuItems when you need to get data out. I don't know if this is what is causing your problem, but you should definitely fix it, and see if it makes a difference.
Try these modifications:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"TableView methods are called! problem is getting AmbassadorInfoData object")
AmbassadorInfoData * selectedItem =(AmbassadorInfoData *)[self.menuItems objectAtIndex:indexPath.row];
if (!selectedItem) NSLog(#"Unable to get Ambassador object, check your menuItems");
[self.detailViewController setDetailItem:selectedItem]; //notice "self."
}
also, uncomment [super viewDidLoad];
EDIT:
it appears that you are using the code you don't understand, in this case i am suggesting to learn some basics....here's a great site that helped me understand things quite a few times
and this is a guide from Apple: Table View Programming Guide
I am trying to display plist data in tableview.
My problem is that after scrolling down i lost my previously fetched data.
Actually i am using custom cell so i think this is happen.
Code for Source and delegate of table is below.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [tableData count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *kCellID = #"Cell";
OffersCustomCell *cell = (OffersCustomCell *)[mytableView dequeueReusableCellWithIdentifier:kCellID];
if (cell == nil)
{
NSString *path = [[NSBundle mainBundle] pathForResource:#"OffersList" ofType:#"plist"];
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"OffersCustomCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
cell.titleLabel.font = [UIFont fontWithName:#"Formata-Regular" size:13.0f];
cell.saveLabel.font = [UIFont fontWithName:#"Formata-Bold" size:14.0f];
cell.nowLabel.font = cell.titleLabel.font;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
NSDictionary *dict = [tableData objectAtIndex:indexPath.row];
NSLog(#"%#",dict);
cell.titleLabel.text = [dict objectForKey:#"title"];
cell.nowLabel.text = [dict objectForKey:#"price"];
cell.saveLabel.text = [dict objectForKey:#"rondel"];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[mytableView deselectRowAtIndexPath:indexPath animated:YES];
}
Did you set the height for each cell
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
CGFloat height = 0;
//calculate height for each cell
return height;
}
Use this UITableView delegate method to set height of the cells.
you can use another class that is store your data and reload time you used that class and restore your data correctly and efficiently.
I solved it. :)
only problem is no retaining memory for UItableview.
tableData = [[NSArray arrayWithObjects:[dic objectForKey:#"Response"], nil] retain];