Objective-C: How to refresh a UITableView? - ios

I have some code that displays file name in my uitableview. however once deleting a file and refreshing i receive an error. Here is my code to display my file name, my delete button actions and the error:
Firstly when a button is pressed i run this code which works when adding a file to the table:
-(IBAction)refresh{
[[self mytable] reloadData];
}
Secondly I have this code to get and display the values the table is going to display. This works fine until the deletion and update occurs:
- (void)viewDidLoad
{
[super viewDidLoad];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
filePathsArray = [[[NSFileManager defaultManager] subpathsOfDirectoryAtPath:documentsDirectory error:nil]mutableCopy];
mytable.dataSource = self;
mytable.delegate = self;
}
-
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
if(!filePathsArray)
{
return 0;
}
if ([filePathsArray count] > 0)
return [filePathsArray count];
else
return 0;
}
-
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
//add code here for when you hit delete
NSString *currentFileName = filePathsArray[indexPath.row];
NSString *documentsDirectoryPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask,YES) objectAtIndex:0];
NSString *filePath = [documentsDirectoryPath stringByAppendingPathComponent:currentFileName];
fileURL = [NSURL fileURLWithPath:filePath];
NSLog(#"urlstring %#",fileURL);
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager removeItemAtPath:filePath error:NULL];
NSLog(#"successfully deleted");
}
}
-
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"MainCell"];
if (cell == nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"MainCell"];
}
NSLog(#"urlstring %#",[filePathsArray objectAtIndex:indexPath.row]);
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];
filePathsArray = [[NSArray alloc] initWithArray: [[[NSFileManager defaultManager] subpathsOfDirectoryAtPath:documentsDirectory error:nil]mutableCopy]];
return cell;
}
-
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
The error i receive is this:
*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayI objectAtIndex:]: index 6 beyond bounds [0 .. 5]'
*** First throw call stack:
(0x2049012 0x1473e7e 0x1ffeb44 0x3c3a 0x69b8fb 0x69b9cf 0x6841bb 0x694b4b 0x6312dd 0x14876b0 0x2c84fc0 0x2c7933c 0x2c79150 0x2bf70bc 0x2bf8227 0x2bf88e2 0x2011afe 0x2011a3d 0x1fef7c2 0x1feef44 0x1feee1b 0x23dc7e3 0x23dc668 0x5e0ffc 0x2212 0x2145)
libc++abi.dylib: terminate called throwing an exception
(lldb)
I receive this error due to:
NSLog(#"urlstring %#",[filePathsArray objectAtIndex:indexPath.row]);
but once removed it says the problem is with the next line. Can anybody help?

Because of the way you're setting data in filePathsArray, your tableView is rendering one extra cell more than needed.
After you delete a file, update your filePathsArray.
What happens is that in your commitEditingStyle method you delete a file, but you do not update the filePathsArray object to remove the subpath for that file.
The only place where you update filePathsArray is in cellForRowAtIndexPath which is called after numberOfRowsInSection
So basically:
E.g. your filePathsArray contains subpaths for 6 files.
You delete a file in commitEditingStyle but you don't update filePathsArray (which still contains 6 subpaths).
You press the button to reloadData
numberOfRowsInSection is called to get the number of cells to be displayed on your UITableView... This returns [filePathsArray count] which is still 6.
cellForRowAtIndexPath is now called for every row.
Inside the above method, you call filePathsArray = [[NSFileManager defaultManager] subpathsOfDirectoryAtPath:documentsDirectory error:nil]; so now your filePathsArray has 5 objects because of the deleted file.
But guess what.... Your UITableView has already started rendering 6 rows for the old filePathsArray count.
Now when it renders cell number 6 (indexPath.row = 5), it calls cell.textLabel.text = [filePathsArray[indexPath.row] lastPathComponent]; and the last index of your array is now 4. This causes the crash.
Simply do filePathsArray = [[NSFileManager defaultManager] subpathsOfDirectoryAtPath:documentsDirectory error:nil]; in your commitEditingStyle and the error should stop.
Also, try not modifying your data source object in cellForRowAtIndexPath. Take the filePathsArray = [[NSFileManager defaultManager] subpathsOfDirectoryAtPath:documentsDirectory error:nil]; call out of there as your array is now being updated in commitEditingStyle.

In tableView:cellForRowAtIndexPath:, remove this code: filePathsArray = [[NSFileManager defaultManager] subpathsOfDirectoryAtPath:documentsDirectory error:nil];
In tableView:commitEditingStyle:,add this code:
[filePathsArray removeObjectAtIndex:indexPath.row];
This should maintain the integrity of the data you're using to populate the table view (so you don't change the number of items when the table doesn't know about it and you do change it when the table thinks you have).

Related

Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayI objectAtIndex:]: index 0 beyond bounds for empty array

I have created two folders in my Documents directory.
I have a UITableView which shows the items in the folders.
Subfolder = #"/Sent";
It gives me a Threat 1: signs SIGABRT on the line:
NSString *last = [dataPath stringByAppendingPathComponent:[filePathsArray objectAtIndex:indexPath.row]];
I have two table views, this code below has been working fine until I added the 2 folders to the documents directory.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
if (tableView == _tblConnectedDevices){
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"CellIdentifier"];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"CellIdentifier"];
}
cell.textLabel.text = [_arrConnectedDevices objectAtIndex:indexPath.row];
return cell;
} else {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
if ([filePathsArray count] == 0){
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *dataPath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:#"%#",subFolder]];
filePathsArray = [[NSFileManager defaultManager] subpathsOfDirectoryAtPath:dataPath error:nil];
}
if ([filePathsArray count] > 0) {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *dataPath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:#"%#",subFolder]];
filePathsArray = [[NSFileManager defaultManager] subpathsOfDirectoryAtPath:dataPath error:nil];
NSString *last = [dataPath stringByAppendingPathComponent:[filePathsArray objectAtIndex:indexPath.row]];
NSString *last2 = [[last lastPathComponent] stringByDeletingPathExtension];
cell.textLabel.text = last2;
}
return cell;
}
}
When I open one folder with a file in it, it loads fine, after, if i open the folder with nothing in it, I get the below error.
If i first open the folder with nothing in it, its fine, then open the folder with something in it, its fine, then when I go back to the empty folder, again the same error.
What am I missing here?
*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayI objectAtIndex:]: index 0 beyond bounds for empty array'
You reassign filePathsArray in the middle of your method. You then access objects at an index without checking if it's inside the bounds of the array. That's most likely not correct.
if ([filePathsArray count] > 0) {
/* ... */
filePathsArray = [[NSFileManager defaultManager] subpathsOfDirectoryAtPath:dataPath error:nil];
NSString *last = [dataPath stringByAppendingPathComponent:[filePathsArray objectAtIndex:indexPath.row]];
The number of objects in filePathsArray can be less than indexPath.row after you have reassigned it.

Populating TableView with Plist Documents Directory in iOS

I'm a newbie to Objective-C so any help is greatly appreciated.
I have a TableView that is successfully pulling back the list from my Data.plist file within my Xcode project but I need it to pull from the Documents Directory.
I have seen many posts about this but can't seem to get it to work for me.
Here is my .m file below. Like I said, it pulls back the data but I need it to be dynamically changed based on my Documents plist copy.
Thanks in advance!
#synthesize content = _content;
- (NSArray *)content
{
if (!_content) {
_content = [[NSArray alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"Data" ofType:#"plist"]];
}
return _content;
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [self.content count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// Configure the cell...
cell.textLabel.text = [[self.content objectAtIndex:indexPath.row] valueForKey:#"Name"];
cell.detailTextLabel.text = [[self.content objectAtIndex:indexPath.row] valueForKey:#"Score"];
return cell;
}
Try this:
Step 1: In .h File declare a global variable
#property (nonatomic,retain) NSMutableDictionary *contents;
Step 2: In .m file set synthesis.
#synthesize contents;
Step 3: Move plist file from mainbudle into documents directory
-(void) createPlistDocuments
{
// Get path to documents directory
NSArray *arrayPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
// Finds the contained Documents directory
NSString *documentsDirectory = [arrayPaths objectAtIndex:0];
NSError *error;
// Create an object that we will later use to look for a file and return a boolean value on whether or not it exists
NSFileManager *manager = [NSFileManager defaultManager];
// File we want to move, stored in original top level directory
NSString *demoFile = [[NSBundle mainBundle] pathForResource:#"data" ofType:#"plist"];
// Define where we want it moved to and name it
NSString *demoFileMoved = [NSString stringWithFormat:#"%#/data.plist", documentsDirectory];
// Attempt the copy
if ([manager copyItemAtPath:demoFile toPath:demoFileMoved error:&error] != YES)
NSLog(#"Unable to move file: %#", [error localizedDescription]);
}
Step 4: Read plist data from document directory
- (void)viewDidLoad
{
[super viewDidLoad];
[self createPlistDocuments];
NSArray *paths = NSSearchPathForDirectoriesInDomains(
NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectoryPath = [paths objectAtIndex:0];
NSString *path = [NSString stringWithFormat:#"%#/data.plist",documentsDirectoryPath];
contents = [NSArray arrayWithContentsOfFile:path];
NSLog(#"%d", contents.count);
}
For brief explanation follow this sample... TechDevMobile(IOS-Message-Chat)

Objective-C: how to list files in individual UITableViewCells? [duplicate]

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;
}

ios - delete single files that are downloaded into the documents directory

Firstly = I apologize because I have already tried to ask this once before here
I am really struggling with this:
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete)
{
// Delete the row from the data source.
[_mainTableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}
By using the code above I know it is possible to delete an entry from an array that is displayed in a UITableView. However I am wanting to delete files form my Documents Directory that are downloaded by the user and no longer required.
Now I in the mean time and after more searching this code:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectoryPath = [paths objectAtIndex:0];
NSString *file = [[NSString alloc] init];
for(int i=0; i<[paths count]; i++)
{
file = [documentsDirectoryPath stringByAppendingFormat:#"/%#",_fileArray];
NSLog(#"%#", file);
}
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager removeItemAtPath:file error:NULL];
Allows me to list all the files that are in the array in my console and this code:
- (void)removeFile:(NSString*)fileName {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *fullPath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.mp3", fileName]];
[fileManager removeItemAtPath: fullPath error:NULL];
NSLog(#"image removed");
}
together with: [self removeFile: _filename]; allows me to delete a specific file.
so I am making head way. But I am really stuck when it comes to a user being able to swipe and delete a file. Of Course I do not know what file is going to be in the directory.
Secondly - How do I handle being able to load the tableView once all the files are deleted?
If I do that using this code:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
if ([paths count] > 0)
{
NSLog(#"Path: %#", [paths objectAtIndex:0]);
NSError *error = nil;
NSFileManager *fileManager = [NSFileManager defaultManager];
// Remove Documents directory and all the files
BOOL deleted = [fileManager removeItemAtPath:[paths objectAtIndex:0] error:&error];
}
I get the an termination error - I think that is because the directory has also been removed.
I know there is a bit of code here, but I really hope someone and guide me through this:-)
If i correctly understood, you want step by step guide.
Lets consider that you have a working UITableView (mainTableView) that take data from NSMutableArray (mainArray).
This will return document directory path.
-(NSString*)filePath{
NSString *path=[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject];
NSLog(#"%#",path);
return path;
}
Somewhere we need to init array ,i did it on viewDidLoad.
- (void)viewDidLoad
{
[super viewDidLoad];
mainDataArray=[[NSMutableArray alloc]init];
[self loadContentsOfDirectory:[self filePath]];
}
//here i am adding names of files from documents directory
-(void)loadContentsOfDirectory:(NSString*)path
{
NSError *error=nil;
NSArray *pathArray=[[NSFileManager defaultManager]contentsOfDirectoryAtPath:path error:&error];
if (error) {
NSLog(#"ERROR: %#",error);
}else{
if (pathArray) {
[mainDataArray removeAllObjects];
[mainDataArray addObjectsFromArray:pathArray];
}
}
}
#pragma mark UITableView_Methods
//delete file then if file is deleted , remove filename from array and remove cell
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath{
if (editingStyle == UITableViewCellEditingStyleDelete)
{
NSString *fileName=[mainDataArray objectAtIndex:indexPath.row];
NSError *error=nil;
NSString *pathToDelete=[[self filePath]stringByAppendingPathComponent:fileName];
BOOL succes=[[NSFileManager defaultManager]removeItemAtPath:pathToDelete error:&error];
if (error) {
NSLog(#"ERROR: %#",error);
}
// if file is succes deleted
if (succes) {
//remove this item from array
[mainDataArray removeObject:fileName];
//and remove cell
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationLeft];
}else{
UIAlertView *alertView=[[UIAlertView alloc]initWithTitle:#"Alert!" message:#"File can not be deleted" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles: nil];
[alertView show];
}
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return [mainDataArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *reusableCell=#"cell";
UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:reusableCell];
if (cell==nil) {
cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reusableCell];
}
cell.textLabel.text=[mainDataArray objectAtIndex:indexPath.row];
return cell;
}
I think your error is that you do not remove something maybe cell, object in array.
Hope this will help.
If you want to delete selected files from your Documents directory then.
First you have to get all files from Documents directory of your app like this
-(NSArray *)listFileAtPath:(NSString *)path
{
NSArray *directoryContent = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:NULL];
return directoryContent;
}
Then use return array from above function to display files to UITableView
NSArray *filesArray = [self listFileAtPath:documentDirectoryPath];
And finally when you delete selected files then you have to remove that file from Documents directory and also from filesArray for managing UITableView something like this:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete)
{
// Delete the row from the data source.
[_mainTableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
// Remove file from document directory
NSError *error = nil;
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL deleted = [fileManager removeItemAtPath:[paths objectAtIndex:0] error:&error];
// Remove file entry from filesArray
[filesArray removeObjectAtIndex:indexPath.row];
}
}
Hope will help you if you want to do something like this.

objectAtIndex:indexPath.row method always causes exception in IOS

Hi I always seem to get exception when I use objectAtInded method to retrieve NSString from an array. I am reading data from a dictionary which is in the "PropertyList.plist" file.My code is
- (void)viewDidLoad
{
[super viewDidLoad];
NSString *path = [[NSBundle mainBundle] pathForResource:#"PropertyList"
ofType:#"plist"];
names = [[NSDictionary alloc]
initWithContentsOfFile:path];
keys = [[[names allKeys] sortedArrayUsingSelector:
#selector(compare:)] retain];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSUInteger section = [indexPath section];
NSUInteger row = [indexPath row];
NSString *key = [keys objectAtIndex:section];
NSArray *nameSection = [names objectForKey:key];
static NSString *SectionsTableIdentifier = #"SectionsTableIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:SectionsTableIdentifier];
if(cell == nil)
{
cell = [[[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault reuseIdentifier:SectionsTableIdentifier] autorelease];
}
cell.textLabel.text = [nameSection objectAtIndex:row];
return cell;
}
The exception happens on the method "cellForRowAtIndexPath" in the line
cell.textLabel.text = [nameSection objectAtIndex:row];
The error message is
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFDictionary objectAtIndex:]: unrecognized selector sent to instance 0x6832440
The plist file is
Where ever I use "[nameSection objectAtIndex:row];" type of statement it always get exception.
The reason for this can be following
[names objectForKey:key];. This statement could give output a NSMutableDictionary type and you are taking a NSArray from that. OR
If it is an array then use the below code for getting the nameSection
NSMutableArray *nameSection = (NSMutableArray*)[names objectForKey:key];
// using (NSMutableArray*) before the code is for external typecasting to tell the compiler that the output is of NSMutableArray type.
Hope this helps.
EDIT:-
use the method below to get your dictionary from the plist file
-(NSMutableDictionary *) GetDictDataFromPlistFile:(NSString *) fileName
{
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); //1
NSString *documentsDirectory = [paths objectAtIndex:0]; //2
NSString *path = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.plist",fileName]]; //3
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath: path]) //4
{
NSString *bundle = [[NSBundle mainBundle] pathForResource:fileName ofType:#"plist"]; //5
[fileManager copyItemAtPath:bundle toPath: path error:&error]; //6
}
NSMutableDictionary *dictData = [[NSMutableDictionary alloc] initWithContentsOfFile:path];
return dictData;
}
Here, name contains only one key of root.
What you need for name is the value of key Root.
Please retry!
Like #scorpiozj said 'names' contains only key of 'Root'. So what I did I know is not a very good way to do it. I am sure there is some other way. I changed the 'viewDidLoad' method to this,
- (void)viewDidLoad
{
[super viewDidLoad];
NSString *path = [[NSBundle mainBundle] pathForResource:#"PropertyList"
ofType:#"plist"];
names = [[NSDictionary alloc]
initWithContentsOfFile:path];
keys = [names allKeys];
NSString *key = [keys objectAtIndex:0];
names = [names objectForKey:key];
keys = [[[names allKeys] sortedArrayUsingSelector:#selector(compare:)] retain];
NSLog(#"keys = %# names = %#",keys,names);
}
It works! Any idea how to do it better will be appreciated though.

Resources