I'll try to preface this as clearly as possible. I have a simple .plist stored in the Documents folder with two different keys. I'm using an AlertView UITextField to receive user input which should be added to the correct key. Using the setObject:forKey returns NSMutableArray may not respond to setObject:forKey. With my current code below I can write to my .plist but the problem is it's changed from a Dictionary to a simple Array. How would I implement a writeToFile for a specific key with this setup? Or on the flip side, am I approaching this from the wrong direction?
In my h
#interface RootViewController: UIViewController <UITableViewDelegate, UITableViewDataSource, MFMailComposeViewControllerDelegate> {
UINavigationBar *navBar;
UITableView *myTable;
NSMutableArray *info;
}
#property(nonatomic, retain) NSMutableArray *info;
#end
And in my m. Yes this is being done without the use of IB completely in code
//************* Add New Cell To TableView When OK is Chosen
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
UITextField *newDevice = [alertView textFieldAtIndex:0];
NSLog(#"newDevice - %#",newDevice.text);
if (alertView.tag == 1 && buttonIndex == 1){
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"stuff.plist"];
[self.info writeToFile:path atomically:YES];
[myTable reloadData]
UPDATE
A little insight on how I've managed to put myself into this situation
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"stuff.plist"];
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithContentsOfFile:path];
self.info = [dict objectForKey:#"Area"];
Above code is how I've managed to populate my TableView so I'm possibly going about this wrong. NSMutableDictionary Doesn't respond to removeObjectAtIndexPath and I'd like to be able to delete a cell from my TableView.
I'm assuming you want to update the key Area in the property list, but keep other properties unchanged.
To accomplish this, keep the dictionary representation around, e.g.,
NSMutableArray *info;
NSMutableDictionary *dict; // add instance variable
and
dict = [NSMutableDictionary dictionaryWithContentsOfFile:path]; // remove local variable
Then, when writing:
[dict setObject:info forKey:#"Area"];
[dict writeToFile:path atomically:YES];
(You could also make dict a property, and you could remove the info variable, instead implementing its accessors to work on the key in the dictionary.)
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"stuff.plist"];
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] initWithContentsOfFile:path];
UITextField *newDevice = [alertView textFieldAtIndex:0];
NSLog(#"newDevice - %#",newDevice.text);
if (alertView.tag == 1 && buttonIndex == 1){
NSMutableArray *existing = dictionary[#"Area"];
[existing addObject:newDevice.text];
[dictionary setObject:existing forKey:#"Area"];
[dictionary writeToFile:path atomically:YES];
[self.info addObject:newDevice.text];
[myTable reloadData];
Related
I have an Array.
Inside my array have 8 object seriated:
- text
- text
- link Url Image.
- link Url Image.
- text
- link Url Image.
- link Url Image.
- text
I had downloaded all image and save to document folder.
And now, How can I get all image from document folder and show in tableViewCell seriated same myArray?
I used this code to get all image from document folder.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *myPath = [paths objectAtIndex:0];
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *directoryContents = [fileManager contentsOfDirectoryAtPath:myPath error:nil];
NSMutableArray *subpredicates = [NSMutableArray array];
[_arrMessageFree addObject:[NSPredicate predicateWithFormat:#"SELF ENDSWITH '.png'"]];
[_ar addObject:[NSPredicate predicateWithFormat:#"SELF ENDSWITH '.jpg'"]];
NSPredicate *filter = [NSCompoundPredicate orPredicateWithSubpredicates:subpredicates];
NSArray *onlyImages = [directoryContents filteredArrayUsingPredicate:filter];
But, I cannot show both text and image seriated in myArray.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
//after cell initialization add following code
for (UIView *subview in [cell.contentView subviews])
{
[subview removeFromSuperview];
}
UIImage *img=[UIImage imageWithContentsOfFile:[onlyImages objectAtIndex:indextPath.row]];
[cell.contentView addSubview:img];
}
As you have told, you are able to get the image names into onlyImages array after the following line:
NSArray *onlyImages = [directoryContents filteredArrayUsingPredicate:filter];
So let's use it to fetch and create UIImages:
UIImage *temp = nil;
for (int i = 0; i < [onlyImages count]; i++) {
temp = [UIImage imageNamed:[onlyImages objectAtIndex:i]]; // so now you have your image loaded into `temp` UIImage object
}
Hope this was helpful!
Cheers!
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)
I am loading an array of items from a plist. A user can select any item and add it to a new array of items which is shown on screen.
I am doing this but a user can also delete a player from any row. My problem is when a user deletes the object it shuffles the list up. Where as I want to keep that row blank.
My deletion code:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
NSString *user_id = [prefs objectForKey:#"user_id"];
NSString *fixture_id = [prefs objectForKey:#"fixture_id"];
// Get path to documents directory
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
[self.usersSelectionArray removeObjectAtIndex:indexPath.row];
if (self.usersSelectionArray == nil) {
// disable swipe to delete?
}
[tableView deselectRowAtIndexPath:indexPath animated:YES];
if ([paths count] > 0)
{
// Path to save array data
NSString *arrayPath = [[paths objectAtIndex:0]
stringByAppendingPathComponent:[NSString stringWithFormat:#"%#-%#",user_id, fixture_id]];
// Write array
[self.usersSelectionArray writeToFile:arrayPath atomically:YES];
}
// If blank array delete the file as not required
if (self.usersSelectionArray.count == 0) {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:#"%#-%#", user_id, fixture_id]];
NSError *error;
if(![[NSFileManager defaultManager] removeItemAtPath:path error:&error])
{
//TODO: Handle/Log error
}
}
[self.tableView reloadData];
}
It also checks if the count is 0 and deletes the plist, re-creates on load if required.
So you want to remove an object from your data array, but keep an empty cell for it in the table?
In that case I recommend replacing the removed object with an NSNull instance.
[myMutableArray replaceObjectAtIndex:index withObject:[NSNull null]];
You can then check if the object for a cell is NSNull and return an empty cell in the cellForRowAtIndexPath: data source method.
id object = // get the correct object from your data array, depending on the index
BOOL isEmpty = [object isKindOfClass:[NSNull class]];
if (isEmpty) {
// return empty table cell
else {
// return a normal cell
}
Instead of [self.usersSelectionArray removeObjectAtIndex:indexPath.row];, try [self.usersSelectionArray replaceObjectAtIndex:indexPath.row withObject:[NSNull null]];. That will keep the row but it will contain practically nothing
I have a UITableView which is populated by the array keys from a plist via this code:
-(void)viewWillAppear:(BOOL)animated
{
// get paths from root direcory
NSArray *paths = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES);
// get documents path
NSString *documentsPath = [paths objectAtIndex:0];
// get the path to our Data/plist file
NSString *plistPath = [documentsPath stringByAppendingPathComponent:#"Data.plist"];
NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithContentsOfFile:(NSString *)plistPath];
viewerKeys = [dictionary allKeys];
[self.tableView reloadData];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"ViewerName"];
UILabel *label = (UILabel *)[cell viewWithTag:1000];
label.text = [viewerKeys objectAtIndex:indexPath.row];
return cell;
}
I'm trying to enable a swipe to delete on each row in the table view, and of course this means I have to delete the row as well as the array in the plist. This is what I've tried so far:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
NSArray *paths = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES);
// get documents path
NSString *documentsPath = [paths objectAtIndex:0];
// get the path to our Data/plist file
NSString *plistPath = [documentsPath stringByAppendingPathComponent:#"Data.plist"];
NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithContentsOfFile:(NSString *)plistPath];
NSString *key = [viewerKeys objectAtIndex:indexPath.row];
[dictionary removeObjectForKey:[NSString stringWithFormat:#"%#", key]];
NSArray *indexPaths = [NSArray arrayWithObject:indexPath];
[tableView deleteRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationAutomatic];
}
However it isn't writing the data back to the plist and I get this error:
Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (2) must be equal to the number of rows contained in that section before the update (2), plus or minus the number of rows inserted or deleted from that section (0 inserted, 1 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).
This is what my plist looks like:
<plist version="1.0">
<dict>
<key>(null)</key>
<array>
<string>Username</string>
<string>Password</string>
<string>http://www.google.com</string>
<string>/whatever</string>
</array>
<key>Hello</key>
<array>
<string>admin</string>
<string></string>
<string>https://www.whatever.com</string>
<string>/things</string>
</array>
</dict>
</plist>
Any help would be great!
Your problem is you are removing that object from the dictionary only. your viewerKeys still hold removed objects key. You need to update viewerKeys before calling deleteRowsAtIndexPaths:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
NSArray *paths = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES);
// get documents path
NSString *documentsPath = [paths objectAtIndex:0];
// get the path to our Data/plist file
NSString *plistPath = [documentsPath stringByAppendingPathComponent:#"Data.plist"];
NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithContentsOfFile:(NSString *)plistPath];
NSString *key = [viewerKeys objectAtIndex:indexPath.row];
[dictionary removeObjectForKey:[NSString stringWithFormat:#"%#", key]];
[dictionary writeToFile:plistPath atomically:YES];
viewerKeys = [dictionary allKeys];
NSArray *indexPaths = [NSArray arrayWithObject:indexPath];
[tableView deleteRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationAutomatic];
}
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.