Remove items from array to ensure no duplicate strings [closed] - ios

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I need to be able to pull 100's of strings from a plist and display them in a label within my project. I have managed to get this to work pulling data from two different arrays within my plist and then generating a random string to display.
What i want to do now is ensure that no two strings are displayed twice in one session and also be able to set a counter system up that after 5 goes it displays a message.
I was thinking of doing a simple counter for the display message after x amount of turns however when it comes to not displaying duplicates from the array im a little lost. I need it to only basically remove an item from the array (not the plist every time the user presses the button)
- (IBAction)truth:(id)sender {
NSString *path = [[NSBundle mainBundle] pathForResource:
#"test" ofType:#"plist"];
NSDictionary *plistDict = [[NSDictionary alloc] initWithContentsOfFile:path];
NSMutableArray *plistArray = plistDict[#"truth"];
NSDictionary *plistDict2 = [[NSDictionary alloc] initWithContentsOfFile:path];
NSMutableArray *plistArray2 = plistDict2[#"dare"];
plistArray = [plistArray arrayByAddingObjectsFromArray:plistArray2];
NSLog(#"%#", plistArray);
int randV = arc4random() % plistArray.count;
self.joke.text = plistArray[randV];
NSLog(#"dictionary: %#, array: %#", plistDict, plistArray);
}

The problem you have is that every time you are getting a message, you are reading the plists again and recreating plistArray
The correct way would be to save plistArray into a local variable (a property) and only populate it the first time.
Then, if you want to remove an item, you call `[plistArray removeObjectAtIndex: randV];
Edit: code
// In .h file
#property (strong, nonatomic) NSMutableArray * plistArray;
- (IBAction)truth:(id)sender {
if (!self.plistArray) {
NSString *path = [[NSBundle mainBundle] pathForResource:
#"test" ofType:#"plist"];
NSDictionary *plistDict = [[NSDictionary alloc] initWithContentsOfFile:path];
NSArray * plistArray1 = plistDict[#"truth"];
NSDictionary *plistDict2 = [[NSDictionary alloc] initWithContentsOfFile:path];
NSArray *plistArray2 = plistDict2[#"dare"];
self.plistArray = [[plistArray1 arrayByAddingObjectsFromArray:plistArray2] mutableCopy];
}
NSLog(#"%#", plistArray);
int randV = arc4random() % self.plistArray.count;
self.joke.text = self.plistArray[randV];
[self.plistArray removeObjectAtIndex:randV];
NSLog(#"dictionary: %#, array: %#", plistDict, self.plistArray);
}
#property

Create an NSMutableSet from plistArray and each time you retrieve one remove it from the set. Presto!
EDIT: Add code
NSMutableSet *jokes = [[NSMutableSet alloc] initWithArray:plistArray];
NSString *joke = [jokes anyObject];
[jokes removeObject:joke];
Disclaimer: As the documentation says, anyObject is not guaranteed to be random. I believe you can work something out for yourself here. E.g.
NSString *joke = [[jokes allObjects] objectAtIndex:arc4random() % [jokes count]];

[plistArray removeObjectAtIndex: randV];

Related

iOS - extracting data from a plist not working

This is a routine exercise. I have done it a number of times in my current project and it has worked fine. I copied the code line for line, same initializations. My plist data goes into a dictionary but then it does not go into its respective arrays in their initializations. I have a method called initArraysPlist
-(void)initArraysPlist{
NSString *path1 = [[NSBundle mainBundle] pathForResource:#"trainerProfile" ofType:#"plist"];
// Load the file content and read the data into arrays
NSDictionary *dict1 = [[NSDictionary alloc] initWithContentsOfFile:path1];
trainerNames = [dict1 objectForKey:#"Names"];
trainerIcons = [dict1 objectForKey:#"Icons"];
trainerFactSheet= [dict1 objectForKey:#"Fact Sheet"];
trainerFocus = [dict1 objectForKey:#"Focus"];
trainerContactInfo= [dict1 objectForKey:#"Contact Info"];
}
Ive done this a few times and it currently works in my code. all the values are correct. Ive checked it many times. when
Please read the comments for the each line.
NSString *path1 = [[NSBundle mainBundle] pathForResource:#"trainerProfile" ofType:#"plist"]; // **check if your plist is actually added in Bundle.If its there move to second line , if not then add plist in bundle.**
NSDictionary *dict1 = [[NSDictionary alloc] initWithContentsOfFile:path1];// **if plist is added in bundle , then check if you are getting value for dict1 . If no then you might be making some mistake in plist structure.**
For more clarifications please post your plist if possible.
Please try this code it may be helpful to you
// Read plist from bundle and get Root Dictionary out of it
NSDictionary *dictRoot = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"data" ofType:#"plist"]];
// Your dictionary contains an array of dictionary
// Now pull an Array out of it.
NSArray *arrayList = [NSArray arrayWithArray:[dictRoot objectForKey:#"catlist"]];
// Now a loop through Array to fetch single Item from catList which is Dictionary
[arrayList enumerateObjectsUsingBlock:^(id obj, NSUInteger index, BOOL *stop) {
// Fetch Single Item
// Here obj will return a dictionary
NSLog(#"Category name : %#",[obj valueForKey:#"category_name"]);
NSLog(#"Category id : %#",[obj valueForKey:#"cid"]);
}];

Adding score and current date to plist

I have to retain the score and current date for a game in a plist . I created a dictionary with two arrays:
- (void)viewDidLoad
{
[super viewDidLoad];
dateArray=[[NSMutableArray alloc]init];
scoreArray=[[NSMutableArray alloc]init];
[self.tableView setDelegate:self];
[self.tableView setDataSource:self];
[self getDate];
NSString *path = [[NSBundle mainBundle] pathForResource:#"score" ofType:#"plist"];
NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:path];
int lastItemIndex = scoreArray.count;
[scoreArray insertObject:[dict objectForKey:#"scoreElements"] atIndex:lastItemIndex];
}
-(IBAction) saveData
{
NSString *plistPath =[[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:#"Score.plist"];
NSMutableArray* plistDict = [[NSMutableDictionary alloc] initWithContentsOfFile:plistPath];
[plistDict setValue:self.scoreLabel.text forKey:#"scoreElements"];
[plistDict writeToFile:plistPath atomically: YES];
}
This code is good only for the last game played, but I want to fill the tableView with the old scores as well. How can I do it?
Instead of using
[scoreArray insertObject:[dict objectForKey:#"scoreElements"] atIndex:lastItemIndex];
why don't you use
[scoreArray addObject: dict["scoreElements"];
Also when you are saving using below code, it will always set new value to "scoreElements" overriding old ones.... so you have to use array as well.
[plistDict setValue:self.scoreLabel.text forKey:#"scoreElements"];
You could use NSUserDefaults to store stuff and retrieve it later on.
Check out the reference about this class at Apple :
nsuserdefault apple

How do I write helper functions to read/write my NSDictionary to my Property List? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 9 years ago.
Improve this question
I am working on an iPhone app that allows certain data to be read from and saved to a property list, but my read function isn't working properly. If I am correct in my thinking, I should simply be able to reverse the procedure I took for reading to write the write helper function. I was able to use [NSArray* dic valueForKey] successfully but my NSLog statements are printing nothing. The program isn't crashing, but it isn't displaying logged values in the output window either. I am not sure I found my filePath correctly, created the dictionary or the array. I am aware I have to call my init function in the main viewcontroller as well but am having difficulty doing so.
My function declarations in the data header are as follows:
#property (nonatomic, copy) NSMutableArray *listOfGroups;
+ (AllData*) myGroupList;
-(NSString*) plistFilePath;
-(NSMutableArray*) withNSMutableArrayInit: (NSMutableArray*) arr;
My functions in the data implementation are as follows:
-(NSString *) plistFilePath
{
//---1.Find the property list filePath
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString* documentsDir = [paths objectAtIndex:0];
NSString* path = [documentsDir stringByAppendingPathComponent:#"Group.plist"];
return documentsDir;
//---2. Create a dictionary and initialize with contents of file.---
NSDictionary *dictionary = [[NSMutableDictionary alloc]initWithContentsOfFile:documentsDir];
//---3. Create an array of type arrayWithArray:[dictionary allValues].---
NSArray* array= [NSArray arrayWithArray:dictionary];
return [self plistFilePath];
}
- (NSMutableArray*) WithNSMutableArrayInit: (NSMutableArray*) arr
{
[self plistFilePath];
for (NSDictionary *dic in arr)
{
NSString *groupName = [dic valueForKey:#"groupName"];
NSLog(groupName);
NSString *createDate = [dic valueForKey:#"createDate"];
NSString *totalAmount = [dic valueForKey:#"totalAmount"];
NSString *totalPeople = [dic valueForKey:#"totalPeople"];
NSArray* participantList = [dic valueForKey:#"ParticipantList"];
for (NSDictionary *dic in arr)
{
NSString *participantName = [dic valueForKey:#"participantName"];
NSLog(participantName);
NSString *relatedParticipantList = [dic valueForKey:#"relatedParticipantList"];
NSString *relatedAmountList = [dic valueForKey:#"relatedAmountList"];
}
NSArray* recordList = [dic valueForKey:#"recordList"];
for (NSDictionary *dic in arr)
{
NSString *recordCategory = [dic valueForKey:#"recordCategory"];
NSLog(recordCategory);
NSString *recordDateTime = [dic valueForKey:#"recordDateTime"];
NSString *recordAmount = [dic valueForKey:#"recordAmount"];
}
}
return [self listOfGroups];
}
Your plistFilePath method is returning early with the user documents path, rather than the file path. Did you mean to do that? It looks like a bug.
Not to mention you'll have an infinite loop if you fixed that bug, by calling [self plistFilePath] at the final (currently unreachable) return statement.

Write data to .plist

I know the question might look similar to many previously-asked questions, but I haven't been able to understand what to do after reading all those questions and answers.
I want to write a number of words that have wordNames and wordDefinitions, and some ID and a date ID. I have the following code, but I have two questions about the dictionary using an array with different data types, and the way of defining keys for the dictionary.
Please correct me if the whole .plist file I'm making is wrong.
Thanks in advance.
- (IBAction)addWord:(id)sender
{
NSString *destinationPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
destinationPath = [destinationPath stringByAppendingPathComponent:#"Box.plist"];
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath:destinationPath])
{
NSString *sourcePath = [[NSBundle mainBundle] pathForResource:#"Box" ofType:#"plist"];
[fileManager copyItemAtPath:sourcePath toPath:destinationPath error:nil];
}
// Load the Property List.
NSMutableArray* wordsInTheBox = [[NSMutableArray alloc] initWithContentsOfFile:destinationPath];
NSString *wordName = word.name;
NSString *wordDefinition = word.definition;
NSInteger deckID;
NSDate addedDate;
//is this correct to have an array of different types?
NSArray *values = [[NSArray alloc] initWithObjects:wordName, wordDefinition, deckID, addedDate, nil];
//How and where am I supposed to define these keys?
NSArray *keys = [[NSArray alloc] initWithObjects: NAME_KEY, DEFINITION_KEY, DECK_ID_KEY, DATE_KEY, nil];
NSDictionary *dict = [[NSDictionary alloc] initWithObjects:values forKeys:keys];
[wordsInTheBox addObject:dict];
[wordsInTheBox writeToFile:destinationPath atomically:YES];
}
initWithContentsOfFile: always returns an immutable array. You should to this:
NSMutableArray *wordsInTheBox = [[NSMutableArray alloc] initWithArray:[NSArray arrayWithContentsOfFile:destinationPath]];
What I don't entirely understand is where the word variable is defined. Is it an ivar?
If you're using the latest version of Xcode (4.4 or 4.5) I recommend using the much simpler literals for creating a dictionary.
NSDictionary *dict = #{NAME_KEY : wordName,
DEFINITION_KEY : wordDefinition,
DECK_ID_KEY : deckID,
DATE_KEY : addedDate};
But I don't see a problem with your dictionary definition either. It should work.
You have to make sure NAME_KEY, DEFINITION_KEY etc. are defined somewhere. All caps are usually only used for preprocessor macros, so you could do something like this:
#define NAME_KEY #"Name"
#define DEFINITION_KEY #"Definition"
You could also simply use the strings directly in your dictionary:
NSDictionary *dict = #{#"Name" : wordName,
#"Definition" : wordDefinition,
#"DeckID" : deckID,
#"Date" : addedDate};
But using macros isn't a bad idea either.

iPhone programming, loading plist data, access it

I have a plist in the following form:
Root (array)---> item 1 (dictionary) ----> Sch (string)
---> Name (string)
----> price (number)
----> item 2 (dictionary)----> .....same as item 1
How can I access each row (item1 to ...) and the its child (Sch, Name etc.)? One at a time?
I use:
NSString *path = [[NSBundle mainBundle] bundlePath];
NSString *finalPath = [path stringByAppendingPathComponent:#"Data.plist"];
NSDictionary *plistData = [[NSDictionary dictionaryWithContentsOfFile:finalPath] retain];
to load the file. How should I go about accessing each child?
What I am trying to do is, I have a NSString *message, what I want to do is to search the whole plist for matching string and display the whole item 1. Any suggestion?
When you initialize a collection from a plist, the type is the root level object. Therefore you would not initialize a dictionary but an array like so:
NSArray *plistData = [[NSArray arrayWithContentsOfFile:finalPath] retain];
Then you would access it like this:
NSString *sch;
NSString *name;
NSString *price;
for (NSDictionary *aDict in plistData) {
sch = [aDict objectAtKey:"Sch"];
name = [aDict objectAtKey:"Name"];
price = [aDict objectAtKey:"price"];
//.. do whatever
}
Here is a link to a discussion that provided a very good example of how to access your data and which type of storage schemes would be more beneficial under certain circumstances. #TechZen's solution is on target, I just thought this question would add an additional resource. Hope this helps!

Resources