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];
Related
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"];
}
I am trying to check if the NSMutableArray has a specific object, before adding the object to it, if exists then don't add.
i looked over many posts explaining how to do this, managed to implement it like this, but it always gives me that the object "doesn't exist", though i already added it !
//get row details into FieldLables Object
AllItemsFieldNames *FieldLabels = feedItems[row];
// object to hold single row detailes
AllItemsFieldNames *SelectedRowDetails = [[AllItemsFieldNames alloc] init];
SelectedRowDetails.item_name = FieldLabels.item_name;
//SelectedRowDetails.item_img = FieldLabels.item_img;
SelectedRowDetails.item_price = FieldLabels.item_price;
//NSLog(#"item has been added %#", SelectedRowDetails.item_name);
//NSLog(#"shopcartLength %lu", (unsigned long)SelectedFieldsNames.count);
if([SelectedFieldsNames containsObject:SelectedRowDetails])
{
NSLog(#"Already Exists!");
}
else
{
NSLog(#"Doesn't Exist!");
[SelectedFieldsNames addObject:SelectedRowDetails];
}
I can display all object from the NSMutableArray into a table, what i need to do in the above code is stop the addition of duplicate objects.
The first method listed on the NSArray documentation under the section "querying an array" is containsObject:. If it's not working, that suggests that your implementation of isEqual: is not correct. Make sure you follow the note in the documentation:
If two objects are equal, they must have the same hash value. This
last point is particularly important if you define isEqual: in a
subclass and intend to put instances of that subclass into a
collection. Make sure you also define hash in your subclass.
You might also consider using an NSSet since you can't add duplicates to that. Of course, this would also require a working version of isEqual:.
Sets are composed of unique elements, so this serves as a convenient way to remove all duplicates in an array.
here some sample,
NSMutableArray*array=[[NSMutableArray alloc]initWithObjects:#"1",#"2",#"3",#"4", nil];
[array addObject:#"4"];
NSMutableSet*chk=[[NSMutableSet alloc ]initWithArray:array]; //finally initialize NSMutableArray to NSMutableSet
array= [[NSMutableArray alloc] initWithArray:[[chk allObjects] sortedArrayUsingSelector:#selector(compare:)]]; //after assign NSMutableSet to your NSMutableArray and sort your array,because sets are unordered.
NSLog(#"%#",array);//1,2,3,4
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.. :)
Complicated wording for something that is relatively simple. Where is an array of pictures defined if, it itself is a particular array item?
I have a set of arrays which are passed through a tableView to a DetailedViewController. One of which is images. On this DetailedView I would like to be able to implement a swipe gesture on a UIImageView so I can swipe through what essentially is an array of images inside of a particular array item.
PseudoCode:
Array 1:
array1-string1
array1-string2
array1-string3
Array 2:
array2-string1
array2-string2
array3-string3
Array 3:
array3-picture1
array3-picture2
array3-picture3
Each array stores a different set of data corresponding to the position in the array. eg: Array1 is all the names, Array2 is all the descriptions, Array3 is all the pictures.
The detailedView displays one set of data. eg. array1-string1, array2-string1, array3-picture1.
Correct me if i'm wrong but in order to use the swipe gesture (for a particular set of data) I need an array of images as the array3-picture1 item.
Would I specify this array when I initially declare all the arrays, in order for it to be hooked to an IBAction on the final detailedViewController, keeping in mind that this is called on a specific segue to the tableView.
OR
Simply declare the array as just an array at the start and specify the values of it somewhere else.
Sorry if that makes no sense, but dealing with this has been doing my head in!
I'd begin by considering this input data as not yet in object form. You can create an NSObject subclass or a dictionary grouping related data. For example (using dictionary):
NSMutableArray *objects = [NSMutableArray array];
NSAssert(array1.count == array2.count == array3.count, #"arrays must be of equal length");
NSInteger count = array1.count;
for (NSInteger i=0; i<count; i++) {
NSDictionary *d = #{ #"name": array1[i], #"description": array2[i], #"image": array3[i] };
[objects addObject:d];
}
This objects array can be the model for your table view, maybe presenting the names at the top level. Upon selection, segue to a detail view, passing data like this:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"DetailSegue"]) {
MyDetailViewController *vc = segue.destinationViewController;
NSIndexPath *selectedIndexPath = [self.tableView indexPathForSelectedRow];
vc.object = self.objects[selectedIndexPath.row];
}
}
Then the detail vc does it's business by referring to the public property which I assumed in the above to be called object. e.g.:
self.descriptionLabel.text = self.object[#"description"];
All,
I have about 3000 words with definitions that I am loading into a TableView. Right now, it's just a sorted list of words, sans the sections because I haven't added them yet.
I need to add sections to my TableView data (A,B,C ...) and there seems to be several ways to do this so before I jump into this I am looking for some confirmation or correction if I am going down the wrong rabbit hole.
Currently the data that the TableView reads is stored as objects in an NSMutableArray per this code:
//AppDelegate.m
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
//...
NSMutableArray *wordArray = [[NSMutableArray alloc] init];
//Loop through result set from DB and populate objects
while([rs next]){
[wordArray addObject:[Word wordWith:[rs stringForColumn:#"word"]
Definition:[rs stringForColumn:#"definition"]
SectionIndex:[rs stringForColumn:#"sectionIndex"]]];
}
MainViewController *mainViewController =
[[MainViewController alloc] initWithNibName:#"MainView" bundle:nil];
mainViewController.listContent = wordArray;
//...
}
Each object has a section index value ([A-Z0-9]) so I already know which section each word goes in, I know what the sections need to be and I can easily derive a count of objects for each section. All the words have been sorted via SQL before the NSMutableArray was populated so that's already handled.
Can I create multiple sections with the one NSMutableArray or do I need to do something different?
Thanks
You could store your words into arrays inside a NSDictionary holding keys for each letter.
Number of sections would return
[[dictionary allKeys] count];
Title for section
NSArray * keys = [dictionary allKeys];
[keys objectAtIndex:sectionIdx]
Number of rows in section would return
NSArray * keys = [dictionary allKeys];
[(NSArray *)[dictionary objectForKey:[keys objectAtIndex:sectionIdx]] count];
Each word would be
NSArray * keys = [dictionary allKeys];
[(NSArray *)[dictionary objectForKey:[keys objectAtIndex:sectionIdx]] objectAtIndex:indexPath.row];
I have found that you sometimes want to add sorting to your lists and then, another approach might be interesting. Put all your models (Word's in your example) in a dictionary with some unique value of the model as the key.
Implement a sorting method, that you run every time the underlying dictionary changes. The sorting method will use e.g. keysSortedByValueUsingComparator on the dictionary and supply a different blocks for different sort orders. Let the sorting method create section arrays and add keys in the arrays that corresponds to the keys in the dictionary.
You do not store anything twice and you get different sort orders by just providing different sort blocks (that can look at any properties of your model class).