Writing new keys to a .plist file based on textField - ios

What I want to do is to populate a pickerView from an array based on a .plist, which can be added to from a textField. I've got it to work, but it only adds one key and replaces it when a new one is added. For instance if I add "hello", and then try to add another one, it replaces hello with something else.
- (IBAction)setContext:(id)sender {
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *path = [[NSBundle mainBundle] pathForResource:#"fullArray" ofType:#"plist"];
NSString *textFieldText = textField.text;
NSMutableDictionary *rootDict = [[NSMutableDictionary alloc] initWithContentsOfFile:path];
[rootDict setValue:textField.text forKey:textField.text];
NSString *writablePath = [documentsDirectory stringByAppendingPathComponent:#"fullArray.plist"];
[rootDict writeToFile:writablePath atomically: YES];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); //1
NSString *plistPath = [documentsDirectory stringByAppendingPathComponent:#"fullArray.plist"]; //3
NSDictionary *dictionary = [[NSDictionary alloc] initWithContentsOfFile:plistPath];
NSArray *array = [dictionary allKeys];
arrayContext = [[NSMutableArray alloc] initWithArray:array];
[pickerView selectRow:0 inComponent:0 animated:YES];
[textField endEditing:YES];
[pickerView reloadAllComponents];
}
How can I fix this?

Ok, you are creating a new NSMutableDictionary every time you pick something in the picker, the correct approach is:
Create a NSMutableDictionary as a property.
Every time you pick, create a new string for the key, maybe using [NSString stringWithFormat:].
use [mutableDictionary setObject:forKey] for set a new object in the mutant dictionary, with the new created key.

Related

how to search specific data in plist ios

Hello I believe that this is a simple issue, I'm a newbie in objective c so please help me.
I have a populated data in plist and i want to make a simple search ( uitextfield and uibutton) how will i make this? Here's my plist:
<plist version="1.0">
<array>
<dict>
<key>ID</key>
<integer>0</integer>
<key>title</key>
<string>Toyota Gen. Santos</string>
<key>address</key>
<string>National Hwy., City Heights, General Santos City, South Cotabato</string>
<key>tel</key>
<string>(083) 554 2994</string>
<key>latitude</key>
<real>6.119086</real>
<key>longitude</key>
<real>125.159881</real>
<key>img</key>
<string>locator_gmap_marker.png</string>
</dict>
....
</array>
</plist>
Thanks! Here's my method for loading plist
//read plist
-(NSString *) dataFilePath{
NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDirectory = [path objectAtIndex:0];
return [documentDirectory stringByAppendingPathComponent:#"locations.plist"];
}
- (void)readPlist{
//read plist
NSString *filePath = [self dataFilePath];
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
NSArray *array = [[NSArray alloc] initWithContentsOfFile:filePath];
NSLog(#"%#\n",array);
}
}
The [self readPlist] will be placed at the veiwDidLoad method. the output will be seen at the NSLOG - all item I have stored in the plist. What i hope to achieved is to get a specific data by searcheing on a UITextfield with a UIbutton and will be seen at a UIlabel.
This code to iterate the dictionaries from the plist i got it from this How to search in a plist to retrieve a value for a specific key, here's the code from event button:
//event button
//Read locations details from plist
NSString *path = [[NSBundle mainBundle] pathForResource:#"locations" ofType:#"plist"];
NSArray *locations = [NSArray arrayWithContentsOfFile:path];
for (NSDictionary *row in locations){
NSNumber *tel = [row objectForKey:#"tel"];
NSNumber *address = [row objectForKey:#"address"];
NSString *title = [row objectForKey:#"title"];
self.titleLbl.text = title;
self.addrsLbl.text = address;
self.telLbl.text = tel;
}
Here's the code i remade in event button. Thanks to
Bijoy Thangaraj, Tark for reference and rmaddy for helping out.
How to search in a plist to retrieve a value for a specific key
Search on Arrays inside Plist in Xcode
- (IBAction)eventSearch:(UIButton *)sender {
//Read locations details from plist
NSString *path = [[NSBundle mainBundle] pathForResource:#"locations" ofType:#"plist"];
NSArray *locations = [NSArray arrayWithContentsOfFile:path];
//convert string to number
NSNumberFormatter * f = [[NSNumberFormatter alloc] init];
[f setNumberStyle:NSNumberFormatterDecimalStyle];
NSNumber *IDnum = [f numberFromString:self.idTxtField.text];
for (NSDictionary *row in locations) {
NSNumber *itemID = [row objectForKey:#"ID"];
if(IDnum == itemID){
NSString *tel = [row objectForKey:#"tel"];
NSString *address = [row objectForKey:#"address"];
NSString *title = [row objectForKey:#"title"];
self.titleLbl.text = title;
self.addLbl.text = address;
self.telLbl.text = tel;
}
}
NSLog(#"accessed!");
self.idTxtField.text = #"";
}

iOS Adding Array to Plist Document Root

Okay so after feedback I am doing this changes to my code it's working but just adding and replacing the first one?
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(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);
if ([paths count] > 0)
{
NSString *selectedPath = [[paths objectAtIndex:0]
stringByAppendingPathComponent:[NSString stringWithFormat:#"%#-%#",user_id, fixture_id]];
// Read both back in new collections
self.mySelectionsArray = [NSArray arrayWithContentsOfFile:selectedPath];
NSLog(#"Players Selected = %#", self.mySelectionsArray);
}
NSDictionary *tempDic = [[[self.listOfPlayersArray objectAtIndex:indexPath.section] objectForKey:#"contacts"] objectAtIndex:indexPath.row];
NSString *avatar = [tempDic objectForKey:#"avatar"];
NSString *avatarSmall = [tempDic objectForKey:#"avatar_small"];
NSString *first_name = [tempDic objectForKey:#"first_name"];
NSString *last_name = [tempDic objectForKey:#"last_name"];
NSDictionary *innerDic;
innerDic = [NSDictionary dictionaryWithObjects:
[NSArray arrayWithObjects: avatar, avatarSmall, first_name, last_name, nil]
forKeys:[NSArray arrayWithObjects:#"avatar", #"avatar_small", #"first_name", #"last_name", nil]];
self.mySelectionsArray = [NSMutableArray arrayWithObject:[NSDictionary dictionaryWithDictionary:innerDic]];
// [self.mySelectionsArray insertObject:innerDic atIndex:0];
[self.mySelectionsArray addObject:innerDic];
[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]];
NSLog(#"Path: %#",arrayPath);
// Write array
[self.mySelectionsArray writeToFile:arrayPath atomically:YES];
}
[self dismissViewControllerAnimated:YES completion:nil];
}
Which is now checking for array and pulling it down then adding the object
The plist looks like this after selecting a player;
{
"first_name" = Ollie;
"last_name" = Akroyd;
},
{
"first_name" = Ollie;
"last_name" = Akroyd;
}
)
Stated your code, mySelections is empty, I guess you want to add innerDic to it; moreover you are saving mySelections instead of userSelections.
You should add innerDic to mySelections and save userSelections to resolve your issue.
EDIT
Instead of
self.mySelectionsArray = [NSMutableArray arrayWithObject:[NSDictionary dictionaryWithDictionary:innerDic]];
which overrides the read array, add the object:
[self.mySelectionsArray addObject:innerDic];
self.mySelectionsArray must be mutable, so instead of
self.mySelectionsArray = [NSArray arrayWithContentsOfFile:selectedPath];
write
self.mySelectionsArray = [[NSArray arrayWithContentsOfFile:selectedPath] mutableCopy];

Writing/loading to/from file

Im trying to learn how to save/load images, and i just don't get why this wont work. Im writing a screenshot to the filesystem like this:
if ([[UIScreen mainScreen] respondsToSelector:#selector(scale)])
UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, NO, [UIScreen mainScreen].scale);
else
UIGraphicsBeginImageContext(self.view.bounds.size);
[self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
NSData * data = UIImagePNGRepresentation(image);
NSArray *directories = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [directories objectAtIndex:0];
NSString *key = [documentsDirectory stringByAppendingPathComponent:#"screenshots.archive"];
[data writeToFile:key atomically:YES];
And in the "init" medthod in my UITableView subclass, i do this:
pics = [[NSMutableDictionary alloc]initWithContentsOfFile:[self dataFilePath]];
dataFilePath method:
- (NSString *)dataFilePath
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
return [documentsDirectory stringByAppendingPathComponent:#"screenshots.archive"];
}
To test if this works i have this delegate method:
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return pics.count;
}
I test it by taking a screenshot, and then initializing my UITableview subclass, but it show no rows. What am i doing wrong?
There are a few key issues with the code that are causing it to not work. You're storing the image data directly to the file and trying to read it back as a dictionary. You'll want to wrap the image in an array first, and write the array to the file. Then you'll want to read the file into an array for the table to display. To sum up the changes:
Change
[data writeToFile:key atomically:YES];
to
NSMutableArray *storageArray = [NSMutableArray arrayWithContentsOfFile:key];
if(!storageArray)
storageArray = [NSMutableArray arrayWithObject:data];
else
[storageArray addObject:data];
[storageArray writeToFile:key atomically:YES];
and change
pics = [[NSMutableDictionary alloc]initWithContentsOfFile:[self dataFilePath]];
to
pics = [[NSArray alloc] initWithContentsOfFile:[self dataFilePath]];

How do I find the filepath for my plist?

I am trying to load a plist into a UITableView. I am new to working with pLists and tableViews, but I know i need to use something along these lines. My problem is though that where "filePath" is, i don't actually know how to put in my pList?
list = [NSArray arrayWithContentsOfFile:filePath];
Any other suggestions with code how to to do this other than getting the file path would be greatly appreciated. Such as do i need to put anything in my .h file? Thanks.
Assuming you've already added a .plist to your project, I've created a class you can add to your project that will get and save information to a given .plist. It's a functioning singleton, so you can call it from anywhere.
First, create a new NSObject file called "GetAndSaveData", then post the following code into .h:
#interface GetAndSaveData : NSObject{
NSMutableDictionary *allData;
NSString *path;
}
+(GetAndSaveData *)sharedGetAndSave;
-(NSMutableArray *)arrayForKey:(NSString *)dataList;
-(void)setData:(NSMutableArray *)array ForKey:(NSString *)dataList;
#end
and the following code into .m:
static GetAndSaveData *sharedGetAndSave;
#implementation GetAndSaveData
-(id)init{
self = [super init];
NSError *error;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); //1
NSString *documentsDirectory = [paths objectAtIndex:0];
path = [documentsDirectory stringByAppendingPathComponent:#"data.plist"];
if (![fileManager fileExistsAtPath: path])
{
NSString *bundle = [[NSBundle mainBundle] pathForResource:#"data" ofType:#"plist"];
[fileManager copyItemAtPath:bundle toPath: path error:&error];
}
allData = [[NSMutableDictionary alloc] initWithContentsOfFile: path];
return self;
}
-(NSMutableArray *)arrayForKey:(NSString *)dataList{
NSMutableArray *array = [allData objectForKey:dataList];
return array;
}
-(void)setData:(NSMutableArray *)array ForKey:(NSString *)dataList{
[allData setObject:array forKey:dataList];
[allData writeToFile:path atomically:YES];
if(![allData writeToFile:path atomically:YES])
{
NSLog(#".plist writing was unsuccessful");
}
}
+(GetAndSaveData *)sharedGetAndSave{
if (!sharedGetAndSave) {
sharedGetAndSave = [[GetAndSaveData alloc] init];
}
return sharedGetAndSave;
}
+(id)allocWithZone:(NSZone *)zone{
if (!sharedGetAndSave) {
sharedGetAndSave = [super allocWithZone:zone];
return sharedGetAndSave;
} else {
return nil;
}
}
-(id)copyWithZone:(NSZone *)zone{
return self;
}
#end
You can change the functions up to get and save different types of data. You can use it in view controllers by importing the .h file, and doing the following:
myMutableArray = [[GetAndSaveData sharedGetAndSave]arrayForKey:myKey];

memory leak in NSArray, trace for long time

There are memory leaks in the below self.listOfCustDetail and self.listOfCustomer
-(void) calCustList {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *plistPath = [NSString stringWithFormat:#"%#/%#", documentsDirectory,#"customer.plist"];
self.listOfCustDetail = [[[NSMutableArray alloc] init] autorelease];
self.listOfCustomer = [[[NSMutableArray alloc] init] autorelease];
self.customers = [[[NSMutableDictionary alloc] initWithContentsOfFile:plistPath] autorelease];
[self.listOfCustomer removeAllObjects];
[self.listOfCustDetail removeAllObjects];
[self.listOfCustomer addObject:#"新紀錄"];
[self.listOfCustDetail addObject:#""];
for (id key in self.customers) {
NSString *s = [NSString stringWithFormat:#"%#,%#,%#,%#", [[self.customers objectForKey:key] objectAtIndex:0], [[self.customers objectForKey:key] objectAtIndex:1], [[self.customers objectForKey:key] objectAtIndex:2], [[self.customers objectForKey:key] objectAtIndex:3]];
[self.listOfCustomer addObject:key];
[self.listOfCustDetail addObject:s];
}
}
How are your properties definied? do they retain? If they do retain, there is no actual mistake in the piece of code, that you are showing.
How often is that method called? If it is called very often you could use a custom NSAutoreleasePool.
Also the following two lines are not needed on a newly initalized array:
[self.listOfCustomer removeAllObjects];
[self.listOfCustDetail removeAllObjects];
Are you showing the actual sourcecode?
I would like to suggest,enable ARC(auto reference counting) in Project because you no need To release arrays

Resources