Obj-C - Check arrays within array for value? - ios

I have a mutable array (self.arr1) that allows users to add objects to it. In this example, the self.arr1 is saved to NSUserDefaults, and looks like this:
(
(
(
"Park"
),
Corner Store
),
"Cafe"
),
"Brewery"
)
I'm using the below code to add objects to self.arr1 (ie. when button is tapped, add objects to self.arr1), and then add self.arr1 to NSUserDefaults. I then want to check if "Park" is present in NSUserDefaults the next time the user opens the app. Even though it is present, the code is executing as if it's not there. It's almost as if because I'm initializing a new array everytime the button is tapped, it doesnt see that Park is indeed present in self.arr1. How can I have my code check all values inside self.arr1?
If I don't initialize the array when the button is tapped, it doesnt allow me to add objects at all, and the array returns null.
ViewController.m
-(void)viewDidLoad {
if ([self.placeDefaults containsObject:self.locationName.text] {
// DO SOEMTHING
}
}
- (IBAction)collectPoints:(id)sender {
self.arr1 = [[NSMutableArray alloc] init];
[self.arr1 addObject:arrayOfPlaces];
self.placeDefaults = [NSUserDefaults standardUserDefaults];
[self.arr1 addObject:self.savedTitle];
[self.placeDefaults setObject:self.arr1 forKey:#"visitedPlaces"];
}

Your code is adding the existing array as a nested array and then adding the new single string to the end.
All you need to do is make a mutable copy of the existing array and then add the new value. Also there is no need to use properties when local variables will do.
- (IBAction)collectPoints:(id)sender {
NSMutableArray newArray = [[arrayOfPlaces mutableCopy];
[newArray addObject:self.savedTitle];
NSUserDefaults *placeDefaults = [NSUserDefaults standardUserDefaults];
[placeDefaults setObject:newArray forKey:#"visitedPlaces"];
}

Related

Clear arrays inside NSDictionary

I want to implement "expanded" behaviour on click on table view headers. For that, i have NSDictionary, which is have all data in form key -> array of values.
What i want is, create other dictionary, copy of initial, and remove all data in arrays inside it. So, in initial loading, our table will look like "closed" headers, after tap on each one, it will collaps and show values corresponding to given key. After tap on header aggain, it will "close" and hide values.
So, basically i want to:
1) enumerate through an NSDictionary and remove all data from array (or create new empty arrays)
2) dynamically add/remove data for given key
Is there easy way to achieve that?
How about this:
NSMutableDictionary *newDict = [NSMutableDictionary new];
for id aKey in tableDict {
newDict[aKey] = [NSMutableArray new];
}
tableDict = newDict;
[tableView reloadData];
Edit:
To clear a single key
tableDict[specificKey] = [NSMutableArray new];
To copy the array from one key into another:
tableDict[specificKey] = [((NSMutableArray *)tableDict[otherKey]) mutableCopy];

Pass data between 2 views without segues

I have 2 views, a login view and a main view.
I use SWRevealViewController, and I want automatically display my menu at the startup of the app. I know how display my menu but I don't know how display it just once at startup.
I want to pass a simple String between my Login view and my Main view but without segue, and made a simple test :
if (myPreviousView == "LoginView")
{
// display my menu
}
Another method would be to use NSUserDefault to store your string, which than can be accessed from anywhere within the application.
So, you put your string into NSUserDefaults in your first view:
// Initialize the NSUserDefaults object and an array for data storage
NSUserDefaults *defsData = [NSUserDefaults standardUserDefaults];
NSMutableArray *myArray = [[NSMutableArray alloc] init];
// Add your string to the custom array
NSString *myString = #"My string.";
[myArray addObject:myString];
// Put the array back into UserDefaults for later use
[defsData setObject:myArray forKey:#"Key"]; // Key can be anything
[defsData synchronize];
Now, the array (and the string in it) is available anywhere. So, when you navigate to your second view controller, just initialize an NSUserDefaults and access the string:
NSUserDefaults* defsData = [NSUserDefaults standardUserDefaults];
NSArray *myArray = [defsData objectForKey:#"Key"];
NSLog("This is my stored string: %#", [myArray objectAtIndex:0]);
You can modify the init method of your second view controller to take a custom attribute when you subclass it. So, lets say you created a standard UIViewController (.h and .m files). You can modify the init method of this new class to your liking in the .h file:
- (instancetype)initWithString:(NSString *)string;
And then replace the standard init with the new one in the .m:
- (instancetype)initWithString:(NSString *)string {
}
So, when you call your view controller into existence, you just use this new init method and pass the string you wanted like this:
UIViewController *viewController = [[UIViewController alloc] initWithString:myString];
[self presentViewController:viewController animated:NO completion:nil];
This is a programmatical approach of course, but it should be applied to interface builder easily (unfortunately, as I never use interface builder, I don't know how exactly, but as I said, it should be fairly straightforward to anyone who uses it).

I need an NSMutableDictionary, where the values will be arrays, that will be created while the app is running, and filled up later

So at runtime I initialize my NSMutableDictionary, and then when the user clicks on certain buttons, the app needs to get the name of this button and this name will be the key. Then he will click on another button, and this button's name will be put into an array, and the array will become the value of the first button name's key. However, later the user will keep doing this, and if he ends up clicking on a button that already is a value in the dictionary, then the second button he presses must be added to the array already associated with that key. Here is my code so far.
closestBeaconsDictionary is the main dictionary. closestBeaconName is a variable that makes up the keys, and pinNumberName is the value that must be put into an array. closestBeaconName and pinNumberName are constantly changing based on what buttons the user presses.
//first, check to see if the key already exists. If not, then add the key to
//closestBeaconsDictionary and then create an array and add this array to the dictionary
//and then add pinNumberName to this array.
if ([closestBeaconsDictionary objectForKey:pinNumberName] == nil)
{
NSMutableArray *closestPinsToBeacon = [[NSMutableArray alloc] init];
[closestPinsToBeacon addObject:pinNumberName];
[closestBeaconsDictionary setObject:closestPinsToBeacon forKey:closestBeaconName];
}
else
{
//what do I do here?? How do I access the dictionary that is at key:pinNumberName
//and then add an object to it?
}
So, my question is basically what do I put in the else statement? I'm confused because isn't closestPinsToBeacon basically destroyed after the block of code runs?
Try this:
if ([closestBeaconsDictionary objectForKey:pinNumberName] == nil)
{
NSMutableArray *closestPinsToBeacon = [[NSMutableArray alloc] init];
[closestPinsToBeacon addObject:pinNumberName];
[closestBeaconsDictionary setObject:closestPinsToBeacon forKey:closestBeaconName];
}
else
{
NSMutableArray *arr = [[NSMutableArray alloc] init];
arr = [[closestBeaconsDictionary objectForKey: closestBeaconName] mutableCopy];
[arr addObject:pinNumberName];
[closestBeaconsDictionary removeObjectForKey: closestBeaconName];
[closestBeaconsDictionary setObject:arr forKey: closestBeaconName];
}
Hope this helps.. :)

Contents of NSArray saved in NSUserDefaults gets overwritten whenever the view controller is called

A View Controller contains:
UITextField(Name).
UIButton(save).
Once I type any name and hit save, The name is added to an array which is stored using NSUserDefaults.
This View Controller is pushed from another View Controller and so when I go and come back to this View Controller, the contents of NSArray gets overwritten with the new names that i might specify. I'm not sure whats causing this but i'm suspecting that it has to do something with allocation and initialization of NSArray.
In my ViewDidLoad, I did NSMutableArray *namesList= [[NSMutableArray alloc]init];
And in my OnSave method,
[namesList addObject:nameTextField.text];
[[NSUserDefaults standardUserDefaults] setObject:namesList forKey:#"namesListArray"];
NSLog(#"items in array: %#",namesArray);
EDIT:
Screenshot of related View Controllers:
Here, when i click the ADD button, the second View Controller is pushed.
When i enter "kenneth" and hit save, the console says:
2014-03-03 11:03:46.219 SmartWatch[664:a0b] items in array: (
kenneth)
Now, without going back to the previous View Controller ,when i type another name say,"john" and hit save, the console says:
2014-03-03 11:15:43.646 SmartWatch[664:a0b] items in array: (
kenneth,
john)
Until now everything is good.
The problem occurs when i go back to the previous Controller and come back to the second View Controller.Now, when i type another name ,say "scott",the console says:
2014-03-03 11:19:50.815 SmartWatch[664:a0b] items in array: (
scott)
This means that the previous two names were overwritten. I want the array to retain "kenneth" and "john" too and "scott" should actually be appended to the array.
I think this happens because the array gets initialized when the second View Controller comes to the foreground again but I'm not sure of it and i dont know how to rectify this.
Hope the question is clear now. Thanks!
Try this,
NSArray *nameArray = [[NSUserDefaults standardUserDefaults] objectForKey:#"namesListArray"];
NSMutableArray * namesList;
if (!nameArray) {
namesList = [[NSMutableArray alloc] init];
} else {
namesList = [NSMutableArray arrayWithArray:nameArray];
}
On save
[namesList addObject:nameTextField.text];
[[NSUserDefaults standardUserDefaults] setObject: namesList forKey:#"namesListArray"];
[[NSUserDefaults standardUserDefaults] synchronize];
Make your nameList array as a property and in viewDidLoad
self.namesList = [[[NSUserDefaults standardUserDefaults] objectForKey:#"namesListArray"] mutableCopy];
if (nil == namesList)
{
self.namesList = [[NSMutableArray alloc]init];
}
onSave method
[self.namesList addObject:nameTextField.text];
[[NSUserDefaults standardUserDefaults] setObject:self.namesList forKey:#"namesListArray"];
Whether you are doing any functionality to store elements to nsarray in ViewWillAppear Method.If not please specify your code properly to help!
Add [[NSUserDefaults standardUserDefaults] synchronize]; at end of NSUserDefaults. Other wise problem is else where, you need to to put relevant code with output of NSUserDefaults.

NSMutableArray Allocate then replaceObjectAtIndex

I have a NSMutableArray that i define in the header file as:
#property (strong, nonatomic) NSMutableArray *tempPhotosArray;
Then i allocate as:
_tempPhotosArray = [[NSMutableArray alloc] init];
What i'd like to know is if i then go to replaceObjectAtIndex the program will complain on an out of bounds. I want to keep only a set number of items in that array, so is it possible to do a insert or replace? i.e. if at index 0 it is empty do an insert, if there is an object already replace it?
Thanks
i think i agree with Hani Ibrahim. Since you said you only want to keep a set number of objects in the array. So how many you want?
// add these code when you initialize the array
int aSetNumber = 5;
_tempPhotosArray = [[NSMutableArray alloc] init];
for (int i = 0; i < aSetNumber; i++)
{
[_tempPhotosArray addobject: [NSNull null]];
}
i guess then you can do whatever you want, i don't know what exactly you want to do in this case, but i would check if the object in that position is NSNUll, if so, replace that, if not, i don't know what you want them
//use these code when you trying to insert the real object
if([[_tempPhotoArray objectAtIndex:anIndex] isKindOfClass: [NSNull class]])
{
//replace it here
}
As to why you are getting an error, what everyone else wrote is accurate, but....
The description of what you want doesn't match what an NSArray is. It sounds like you want a list of up to 5 items and never more than 5. It might be that if you try to add a 6th item the "oldest" goes away. Like a "recently opened" file history. You can make this type of functionality with an NSArray, but that's not what it is out of the box.
I would suggest making your own object class. I'm not going to write all the code for you, because this sounds suspiciously like programming homework, but I will point you in the correct direction.
FivePack <-- our class
NSArray *storage; <-- where we house the data
// a public method which lets you add things.
- (void)addItem:(id)item {
int indexOfLastItemInArrayToSave = 4;
if (storage.length < 4)
indexOfLastItemInArrayToSave = length-1;
NSRange range = NSMakeRange(0, indexOfLastItemInArrayToSave);
NSArray *temp = [storage subArrayWithRange:range];
// now create a new array with the first item being "item" that
// was passed in and the rest of the array being the contents of temp.
// Then save that to storage.
}
What you want to do with the data and writing something to get it from your new object is up to you, because I'm not sure how you want to do it.
There are no objects in the array when you initially created it, so there is nothing to replace.
Like this?
if([_tempPhotosArray count] > 0)
//replace object
else
//add object to array

Resources