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.
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.
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
I have a UITextField and when the user hits a save button, the text should be saved into a plist file with the following code:
-(IBAction)saveButtonPressed
{
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); //1
NSString *documentsDirectory = [paths objectAtIndex:0]; //2
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"Data.plist"]; //3
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath: path]) //4
{
//5
NSString *bundle=[[NSBundle mainBundle] pathForResource:#"Data" ofType:#"plist"];
[fileManager copyItemAtPath:bundle toPath: path error:&error]; //6
}
NSMutableDictionary *data = [[NSMutableDictionary alloc] initWithContentsOfFile: path];
//here add elements to data file and write data to file
[data setObject:[inkTextField text] forKey:#"inkText"];
BOOL didWrite=[data writeToFile: path atomically:YES];
if(didWrite==YES)
NSLog(#"didWrite");
else NSLog(#"nope");
[data release];
}
Then I have a UITableView and I want to load the string value of plist into the cell text field with the following code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"CellViewController"];
if (cell == nil) {
// Load the top-level objects from the custom cell XIB.
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"CellViewController" owner:self options:nil];
// Grab a pointer to the first object (presumably the custom cell, as that's all the XIB should contain).
cell = [topLevelObjects objectAtIndex:0];
}
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); //1
NSString *documentsDirectory = [paths objectAtIndex:0]; //2
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"Data.plist"]; //3
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath: path]) //4
{
//5
NSString *bundle=[[NSBundle mainBundle] pathForResource:#"Data" ofType:#"plist"];
[fileManager copyItemAtPath:bundle toPath: path error:&error]; //6
}
NSMutableDictionary *savedInks = [[NSMutableDictionary alloc] initWithContentsOfFile: path];
//load from savedStock example int value
NSString *value;
value = [[savedInks objectForKey:#"inkText"]stringValue];
[savedInks release];
inkTitle.text=value;
return cell;
}
When I save, I get a the log outputs didWrite, so I know it saved properly. However when I visit the tableView, I get a crash with the following error:
2011-08-19 13:56:45.717 MyApp[36067:b303] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSCFString stringValue]: unrecognized selector sent to instance 0x4bb5fa0'
So I thought it was something to do with this line:
value = [[savedInks objectForKey:#"inkText"]stringValue];
so I tried
value = [savedInks objectForKey:#"inkText"];
but that also causes a crash but with no message. What am I doing wrong?
You should remove the 'stringValue', as you're already returning a NSString value.
In the next line, you're releasing 'savedInks', before retaining 'value'. Swap the release with the line below it and see if that works.:
NSString *value;
value = [savedInks objectForKey:#"inkText"];
inkTitle.text=value;
[savedInks release];
When savedInks is released, all of the objects within the dictionary are released as well. Setting inkTtile.text should perform a retain on value automatically.
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.