The Situation:
I am trying to display a list of files from my app's Documents Directory (iOS) in a UITableView.
The Problem:
When the view loads, instead of listing all the files, it only lists one file (the first one alphabetically)
The Code:
cell.textLabel.text = [NSString stringWithFormat:#"Cell Row #%d", [indexPath row]];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSPredicate *filter = [NSPredicate predicateWithFormat:#"self ENDSWITH '.txt'"];
NSArray *fileListAct = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:documentsDirectory error:nil];
NSArray *FileList = [fileListAct filteredArrayUsingPredicate:filter];
cell.textLabel.text = [NSString stringWithFormat:#"%#",[FileList objectAtIndex:indexPath.row]];
NSLog(#"File List: %#", FileList);
All of the code performs as it should, and even the last NSLog line lists ALL of the file names, but for some reason in the UiTableView it only lists the first file name.
More Info:
I've tried creating a do loop for the last cell.textlabel.text line, but that also requires a while statement (and I couldn't think of what the condition would be).
Any ideas on how to make the UITableView display all file names vs. just the first one?
You need to setup a global NSArray for fileList. The you need to create the array in either viewDidLoad or viewWillAppear:
Example
This is a rough example, and how I would do it, although it hasn't been tested, it should work.
#interface MyViewController () {
NSMutableArray *FileList;
}
#end
#implementation MyViewController
- (void)viewDidLoad:(BOOL)animated
{
[super viewDidLoad];
FileList = [[NSMutableArray alloc] init];
}
/* Setup the array here */
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSPredicate *filter = [NSPredicate predicateWithFormat:#"self ENDSWITH '.txt'"];
NSArray *fileListAct = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:documentsDirectory error:nil];
FileList = [fileListAct filteredArrayUsingPredicate:filter];
}
/* Set the number of cells based on the number of entries in your array */
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [FileList count];
/* this is probably what you are missing and is definitely
the reason you are only seeing 1 cell. */
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
cell.textLabel.text = [NSString stringWithFormat:#"%#",[FileList objectAtIndex:indexPath.row]];
}
#end
Related
I retrieve all data from an sqlite database. I can get them to populate the table view. When I click on a row the webview opens but doesn't show the pdf file.The view is just plain white background. no crash, no errors, simply doesn't show anything.
This is my code. Not sure what I'm doing wrong.
#import "PdfTableVC.h"
#import "PdfVC.h"
#interface PdfTableVC ()
#end
#implementation PdfTableVC {
NSMutableArray *listOfPdf;
}
#synthesize pdfTable;
- (void)viewDidLoad {
[super viewDidLoad];
[self initDatabase];
[self getPoints];
}
#pragma mark - View lifecycle
-(void)initDatabase{
BOOL success;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *writableDBPath = [documentsDirectory stringByAppendingPathComponent:#"my.db"];
success = [fileManager fileExistsAtPath:writableDBPath];
if (success)
{
return;
}
NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"my.db"];
success = [fileManager copyItemAtPath:defaultDBPath toPath:writableDBPath error:&error];
if (!success)
{
NSAssert1(0, #"Failed to create writable database file with message '%#'.", [error localizedDescription]);
}
}
-(void)getPoints{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"my.db"];
if (sqlite3_open([path UTF8String], &database) == SQLITE_OK)
{
const char *sql = "SELECT * FROM file_geositi";
sqlite3_stmt *searchStatement;
if (sqlite3_prepare_v2(database, sql, -1, &searchStatement, NULL) == SQLITE_OK)
{
listOfPdf = [[NSMutableArray alloc] init];
while (sqlite3_step(searchStatement) == SQLITE_ROW)
{
NSString *pdf = [NSString stringWithUTF8String:(char *)sqlite3_column_text(searchStatement,0)];
[listOfPdf addObject:pdf];
}
}
sqlite3_finalize(searchStatement);
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return [listOfPdf count];
}
//Table View cell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *simpleTableIdentifier =#"pdfCell";
UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if(cell == nil){
cell=[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
cell.textLabel.text = [listOfPdf objectAtIndex:indexPath.row];
return cell;
}
//Detail View items
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"showPDF"]) {
NSIndexPath *indexPath = [self.pdfTable indexPathForSelectedRow];
PdfVC *destViewController = (PdfVC *)segue.destinationViewController;
destViewController.dataPdf= [listOfPdf objectAtIndex:indexPath.row];
}
}
PdfVC.h
#import <UIKit/UIKit.h>
#interface PdfVC : UIViewController
//UIWebView
#property (nonatomic, strong) IBOutlet UIWebView *webView;
#property (nonatomic, strong) NSString *dataPdf;
#end
PdfVC.m
#import "PdfVC.h"
#interface PdfVC ()
#end
#implementation PdfVC
#synthesize webView;
#synthesize dataPdf;
- (void)viewDidLoad {
[super viewDidLoad];
//No sure about this and in fact makes the app crash
NSString *pdfName = [NSString stringWithFormat:#"%#", [self.dataPdf description]];
NSString *path = [[NSBundle mainBundle] pathForResource:pdfName ofType:#"pdf"];
NSURL *url = [NSURL fileURLWithPath:path];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[webView loadRequest:request];
}
#end
Any help? Thanx
Ok, so after having a look at your code, I found the following things:
You are storing your PDF names in a SQLite database (I don't really
understand the purpose of doing this, but let's say you need to) with
the names 'pdf_1', 'pdf_2' and 'pdf_3', but these are not matching
with your actual file names of PDF's in your supporting files folder
which are 'PDF 1' etc.
Secondly, you are passing just the name of the PDF extracted from the database onto the PdfVC, which actually does nothing, you have to actually load the PDF into the webView here, so it actually does nothing.
Solution:
Rename your PDF's from 'PDF 1' etc to 'pdf_1' etc. so that they match with the actual names stored in your database, or rename the entries in your database to match the file names of the PDF.
Secondly, place the following code into your viewDidLoad method of the PdfVC view controller:
NSString *path = [[NSBundle mainBundle] pathForResource:dataPdf ofType:#"pdf"];
NSURL *targetURL = [NSURL fileURLWithPath:path];
NSURLRequest *request = [NSURLRequest requestWithURL:targetURL];
[webView loadRequest:request];
All this code is doing is that it picks up the right PDF from the resources using the name stored in the property dataPdf (passed via the segue) and then loads that PDF into the webView.
I would recommend you to re-consider the purpose of an actual database here, since all you are doing is storing the names of the PDF's into the table. It may not be required at all, and you could maintain an NSArray of the PDF names in your PDFTableVC view controller.
Hope this answers your question.
So im trying to write something with a UITableView that segues into a UITextview.
and in the UITextview there is a button to clear the text.
i have 2 questions.
right now im getting a error
Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<textViewController 0x6e69760> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key clearButton.'
the breakpoint says this is thrown when performSegue is called inside didSelectRowAtIndexPath
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self performSegueWithIdentifier:#"segueIdentifier" sender:self];
}
here
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if( [segue.identifier isEqualToString:#"fileSelected"]){
textViewController *nextViewController = segue.destinationViewController ;
nextViewController.title = #"newView";
[nextViewController setText:[[NSString alloc] initWithData:[self readFromFile:#"textfile.txt"] encoding:NSUTF8StringEncoding]];
}
}
and also. im trying to set the textview text with data i read from a file in the file systems
heres the read and write functions, which is not working...
-(NSData*) readFromFile:(NSString *)filename{
NSString* content = #"";
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [NSString stringWithFormat:#"%#/%#", documentsDirectory, filename];
content = [[NSString alloc] initWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
return [content dataUsingEncoding:NSUTF8StringEncoding];
}
-(void) saveToFile:(NSString *)filename withData:(NSData *)data{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentationDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [NSString stringWithFormat:#"%#/%#",documentsDirectory,filename];
[data writeToFile:filePath atomically:YES];
}
did i do something wrong during the segue, to cause the exception? if you need any other pieces of code, ill put it up .
thanks in advance
Check that you have a segue actually named "segueIdentifier". That would be a first step.
This problem appeared for me after the segue and was caused by a broken connection between view and controller:
(the lower one is broken)
You just have to remove the connection and add it again.
Currently i'm using these codes to save my images into NSDocumentDirectory. I use this counter as the naming convention for them.
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)selectedImage editingInfo:(NSDictionary *)editingInfo
{
[self.popoverController dismissPopoverAnimated:YES];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [paths objectAtIndex:0];
NSString *savedImagePath = [documentsDir stringByAppendingPathComponent:[NSString stringWithFormat:#"%d.png", counter]];
UIImage *image = imageView.image;
NSData *imageData = UIImagePNGRepresentation(image);
[imageData writeToFile:savedImagePath atomically:NO];
}
I use this method because it's easier for me to retrieve all of them by using a loop. I want to retrieve all the images from the NSDocumentDirectory so that i can display them in another view. The following codes show how i retrieve them.
-(NSMutableArray *)GetImage:(NSMutableArray *)arrayImgNames
{
NSMutableArray *tempArray;
for(int i=0;i<[arrayImgNames count]; i++)
{
NSArray *paths1 = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths1 objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent: [arrayImgNames objectAtIndex:i]];
[tempArray addObject:[[UIImage alloc] initWithContentsOfFile:filePath]];
return tempArray;
}
}
However, i do not wish to use the counter as a naming convention for my images. I want to use proper names for them but if i do so, i will have to change my method of retrieving all the images.
Is there any other way that i can retrieve all images other than this method i mentioned?
You can retrieve files using next approach:
NSURL *url = [[AppDelegate sharedAppDelegate] applicationDocumentsDirectory];
NSError *error = nil;
NSArray *properties = [NSArray arrayWithObjects: NSURLLocalizedNameKey, NSURLLocalizedTypeDescriptionKey, nil];
NSArray *files = [[NSFileManager defaultManager] contentsOfDirectoryAtURL:url
includingPropertiesForKeys:properties options:(NSDirectoryEnumerationSkipsPackageDescendants)
error:&error];
In files paths to all files of documents directory will be stored. Next code will help you to get there names:
NSURL *url = [files objectAtIndex:index];
NSString *localizedName = [url lastPathComponent];
I have a bunch of mp3's displayed in a UITableView which are located in my apps documents directory.
When I select the row, I want the file to load into AVAudioPlayer and Play.
Can anyone suggest how I would go about doing this?
Any help would be greatly appreciated.
Thanks!
I finally figured this out:
NSArray *songs;
AVAudioPlayer *player;
- (void)viewDidLoad
{
[self.player prepareToPlay];
// Point to Document directory
NSString *path = [NSHomeDirectory() stringByAppendingPathComponent:#"Documents"];
NSError *error = nil;
NSArray *array = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:&error];
if (array == nil) {
// Handle the error
}
self.songs = array;
//[array release];
//self.title = #"Song List";
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *applicationDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *filePath = [applicationDocumentsDirectory stringByAppendingPathComponent: [songs objectAtIndex:indexPath.row]];
NSURL *url = [NSURL fileURLWithPath:filePath];
player = [[AVAudioPlayer alloc]initWithContentsOfURL:url error:nil];
[player play];
}
I've got a little problem with an Application i am designing at the min but i'm a complete beginner, first of all a little information on what i am trying to accomplish.
I have a plist which populates an NSMutableArray which contains many values each one has a string and a BOOL inside, i can make the program save a copy of the file upon opening the app and load the data into the tableview along with an accessoryview of a checkmark.
now the checkmark works ok and you can select different items and the checkmark only appears on those items none of the others and if you inspect the log the details for each of the items check BOOL is changed but when i come to save a second time the checkmark state is not persisted for when i open the application a second time it just saves it as a 0 everytime.
here is some of my code, any help would be appreciated.
Thanks
Brad
- (void)viewDidLoad {
BOOL success;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:#"CustomChecklist.plist"];
success = [fileManager fileExistsAtPath:filePath];
NSLog(#"STATUS OF SUCCESS %d",success);
if (!success) {
NSString *path = [[NSBundle mainBundle] pathForResource:#"OriginalChecklist" ofType:#"plist"];
success = [fileManager copyItemAtPath:path toPath:filePath error:NULL];
self.dataArray = [NSMutableArray arrayWithContentsOfFile:filePath];
NSLog(#"IF STATEMENT CREATING THE FILE");
}else {
self.dataArray = [NSMutableArray arrayWithContentsOfFile:filePath];
NSLog(#"IF STATEMENT READING THE FILE");
}
NSLog(#"location information %#", filePath);
[super viewDidLoad];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *kCustomCellID = #"MyCellID";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kCustomCellID];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kCustomCellID] autorelease];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.selectionStyle = UITableViewCellSelectionStyleBlue;
}
NSMutableDictionary *item = [dataArray objectAtIndex:indexPath.row];
cell.textLabel.text = [item objectForKey:#"text"];
[item setObject:cell forKey:#"cell"];
BOOL checked = [[item objectForKey:#"checked"] boolValue];
UIImage *image = (checked) ? [UIImage imageNamed:#"checked.png"] : [UIImage imageNamed:#"unchecked.png"];
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
CGRect frame = CGRectMake(0.0, 0.0, image.size.width, image.size.height);
button.frame = frame; // match the button's size with the image size
[button setBackgroundImage:image forState:UIControlStateNormal];
// set the button's target to this table view controller so we can interpret touch events and map that to a NSIndexSet
[button addTarget:self action:#selector(checkButtonTapped:event:) forControlEvents:UIControlEventTouchUpInside];
button.backgroundColor = [UIColor clearColor];
cell.accessoryView = button;
return cell;
}
- (void)viewWillDisappear:(BOOL)animated
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *savePath = [documentsDirectory stringByAppendingPathComponent:#"CustomChecklist.plist"];
NSLog(#"View Will Disappear SAVE location information %#", savePath);
[dataArray writeToFile:savePath atomically:YES];
}
BOOL is not an object, it is a primitive type. Therefore, it cannot be saved (properly) in an array or dictionary. You need to use the NSNumber class to wrap it:
[NSNumber numberWithBool:checked] //this should be added to the dictionary
I am writing this from my phone, so I can't really see all of your code. But I just wanted to say that what you are trying to achieve can probably be solved by using NSUserdefaults instead of saving a file. Have you looked into that?
Oh, and just like Evan said, bool isn't an object. Only objects can be stored in an array.
Is there a reason you are adding the cell to your dictionary? A UITableViewCell is not a property list compatible object, so it could keep your array from saving properly.