How do I append an object to NSMutableArray? - objective-c

I want to update an mutable array. i have one array "ListArray" with some keys like "desc", "title" on other side (with click of button.) i have one array name newListArray which is coming from web service and has different data but has same keys like "desc" "title". so i want to add that data in "ListArray" . not want to replace data just add data on same keys. so that i can show that in tableview.
..........So my question is how to add data in "ListArray". or any other way to show that data in tableview but replacing old one just want to update the data
NSMutableArray *newListArray = (NSMutableArray*)[[WebServices sharedInstance] getVideoList:[PlacesDetails sharedInstance].userId tokenValue:[PlacesDetails sharedInstance].tokenID mediaIdMin:[PlacesDetails sharedInstance].minId mediaIdMax:[PlacesDetails sharedInstance].maxId viewPubPri:#"Public_click"];
NSDictionary *getNewListDic = [[NSDictionary alloc] initWithObjectsAndKeys:newListArray,#"videoList", nil];
[listVidArray addObject:getNewListDic];
NSArray *keys = [NSArray arrayWithObjects:#"desc",#"url",#"media_id",#"img",#"status",#"media_id_max",#"fb_url",#"title", nil] ;
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
for(int i = 0 ; i < [listVidArray count] ; i++)
{
for( id theKey in keys)
{
// NSMutableArray *item = [NSMutableArray array];
NSLog(#"%#",theKey);
NSLog(#"%#",keys);
[dict setObject:[[[listVidArray objectAtIndex:i]valueForKey:#"videoList"] valueForKey:theKey] forKey:theKey];
// [dict setObject:[newListArray valueForKey:theKey] forKey:theKey];
}
}

If you the newListArray is totally different from the oldListArray, then clear the old one, and use the new data to fit it.
Otherwise, you need to merge the two arrays. One way is to check if a
data in newListArray is/is not in oldListArray and then decide
whether to add it into oldListArray.
When oldListArray is updated, call -reloadData of the tableView.

If I do not misunderstand your question, you may do something like this:
[listArray addObjectsFromArray:newListArray];
[_tableView reloadData];

Related

Objective C. NSMutable Dictionary adding value to existing key

Is there any way to add a value to an existing key on a NSMutableDictionary?
Here is snippet of my code
NSMutableArray *mainFeedList = [NSMutableArray array];
[mainFeedList addObjectsFromArray:feedList];
for(int i = 0; i < mainFeedList.count; i++){
NSMutableArray *allFeed = [NSMutableArray array];
NSString *categoryId = [mainFeedList[i] valueForKey: #"categoryId"];
[allFeed addObject:mainFeedList[i]];
if(allFeed != nil && allFeed.count > 0) {
[feedContent setObject:allFeed
forKey:[combinedCategories[(int)[categoryId integerValue]] valueForKey: #"name"]];
}
Sample scenario:
NSMutableDictionary *mDict = #{#"key1":#"value1",#"key2": #"value2"};
I know that
[mDict setObject:mArray forKey:#"key1"];
will set an object to key1 but what I need is
add another object to key1 without replacing existing object (i need it both)
A structure of any NSDictionary is "one key to one object". If you would like to build a structure which maps one key multiple objects, you need an NSDictionary that maps keys to collections, such as NSArray or NSMutableArray:
NSMutableDictionary *mDict = #{
#"key1": [#[ #"value1" ] mutableCopy]
, #"key2": [#[ #"value2" ] mutableCopy]
};
Now you can add values to keys without replacing the existing ones:
[mDict[#"key1"] addObject:#"value3"];
NSDictionary only allows a single object corresponding to a single key. If you would like to add multiple objects corresponding to a single key, if you have string type of object then you can use separators also to combine strings like:
[mDict setObject:[NSString stringWithFormat:#"%#,%#", [mDict objectforKey:#"key1"], #"value2"] forKey:#"key1"];
Otherwise, you have to take collections, which you have already defined in your question.
add another object to key1 without replacing existing object...
why not set an dict to key1?
before:
[dict setObject:#"a" forKey:#"key1"];
U wanna:
add #"b" to "key1", in dict;
why not like:
[dict setObject:#{#"a":#"subKey1", #"b":#"subKey2"} forKey:#"key1"];
I would suggest storing an array as a key in your dictionary like I do below :
// Setting the value for "key1" to an array holding your first value
NSMutableDictionary *mDict = #{#"key1":#["value1"],#"key2": #"value2"};
Now when I want to add a new value I would do this:
// Create temp array
NSMutableArray *temp = mDict[#"key1"];
// Add new object
[temp addObject:#"value3"];
// Convert temp NSMutableArray to an NSArray so you can store it in your dict
NSArray *newArray = [[NSArray alloc] initWithArray:temp];
// Replace old array stored in dict with new array
mDict[#"key1"] = newArray;
Furthermore, if you are not sure if an array is already stored for that key you can run a check and populate with an empty dictionary like below:
if (mDict[#"key1"] == nil) {
mDict[#"key1"] = #[];
}

So I've stored an NSDictionary object in an NSMutableArray, how do I know use the NSDictionary keys to grab these objects out of the array?

I have two UISlider's that represent minimum and maximum prices of items. I am passing these as well as other various data back to the previous controller.
I've used a protocol method and set the previous controller as a delegate to make it possible to pass values back to the controller.
I can easily grab the other objects out of the array because they're strings. I just use:
[_finalSelectionForRefinement containsObject:#"size"];
This is what I do in pushed controller:
// create dictionary with keys minimum and maximum that hold the
// position of the slider as a float
_dictionaryWithSliderValues =
[[NSDictionary alloc] initWithObjectsAndKeys:[NSNumber numberWithFloat:_minSliderPosition], #"minimum",
[NSNumber numberWithFloat:_maxSliderPosition], #"maximum", nil];
// store this in the array that is retrieved in previous controller
[_finalSelectionForRefinement addObject:_dictionaryWithSliderValues];
My question is how do I now use the minimum and maximum keys to grab the slider position float objects?
Thought I could use NSPredicate but the examples I've been coming across on blogs as well as youTube are of no help to my specific needs.
Would appreciate some help here
Regards
UPDATE - Short snipped of method in previous controller where I need to retrieve the slider minimum and maximum values:
-(PFQuery *)queryForCollection
{
PFQuery *query = [PFQuery queryWithClassName:#"Garments"];
if (_selectedRowInFilterPicker == 0) {
NSLog(#"ORDER BY RECOMMENDED");
[query orderByDescending:#"recommended"];
} else if (_selectedRowInFilterPicker == 1) {
NSLog(#"ORDER BY NEWEST ITEMS");
[query orderByDescending:#"createdAt"];
} else if (_selectedRowInFilterPicker == 2) {
NSLog(#"ORDER BY DESCENDING USING PRICE");
[query orderByDescending:#"price"];
} else if (_selectedRowInFilterPicker == 3) {
NSLog(#"ORDER BY ASCENDING USING PRICE");
[query orderByAscending:#"price"];
}
if ([_selectionFromRefineResultsController count] > 0) {
NSLog(#"Selection FROM REF MADE");
// Gender
if ([_selectionFromRefineResultsController containsObject:#"Male"]) {
[query whereKey:#"gender" equalTo:#1];
}
if ([_selectionFromRefineResultsController containsObject:#"Female"]) {
[query whereKey:#"gender" equalTo:#2];
}
}
// Here I need to check there is a minimum or maximum value in the array
// If there is I can user [query whereKey:#"price" greaterThan:MINVAL] and MAXVAL
// This will return items within the correct price range.
This queryForCollection method is called from within another method called performQuery which is called when the button of the second controller is tapped to pass data back to the controller that pushed it in the first place.
You should look at the documentation for NSMutableArray , NSArray and NSDictionary
Which will explain the instance methods for each.
But in a nutshell any object that you add should be in a NSDictionary so it has a value and a key. This includes any of your strings. Doing so simplifies how you search by using keys.
If the NSMutableArray contains objects that are not KVC then you will I think find it harder it go through the objects in one sweep.
Because NSmutableArray inherites from NSArray you can then use instance method valueForKey: on a NSmutableArray whose objects values or objects objects values have keys.
valueForKey:
Returns an array containing the results of invoking
valueForKey: using key on each of the array's objects.
(id)valueForKey:(NSString *)key
Rough Example:
NSMutableArray * finalSelectionForRefinement =[[NSMutableArray alloc]init];
NSDictionary *dictionaryWithSliderValues = [[NSDictionary alloc] initWithObjectsAndKeys:[NSNumber numberWithFloat:10], #"minimum", [NSNumber numberWithFloat:20], #"maximum", nil];
NSDictionary *stringValues = [[NSDictionary alloc] initWithObjectsAndKeys:#"the-size", #"size", #"the-hight", #"hight", nil];
[finalSelectionForRefinement addObject:dictionaryWithSliderValues];
[finalSelectionForRefinement addObject:stringValues];
NSLog(#"finalSelectionForRefinement = %#", [finalSelectionForRefinement valueForKey:#"maximum"] );
First off, you can of store everything in one NSDictionary which makes more sense. But I wanted to show you that the valueForKey: will search within each.
The other thing is valueForKey: will return an NSArray containing the results. any objects that it finds that do not match the key you are looking for will be returned as an NSNull object. i.e
finalSelectionForRefinement = (
20,
"<null>"
)
So you would need to still single your value out. One way is use a objectEnumerator like this:
NSEnumerator *enumerator = [[finalSelectionForRefinement valueForKey:#"maximum"] objectEnumerator];
id anObject;
while (anObject = [enumerator nextObject]) {
if(![anObject isKindOfClass:[NSNull class]])
{
NSLog(#"anObject = %#", anObject);
}
}
Which should return:
anObject = 20
There are most likely better ways of doing this. All of the above is just to give you one idea. And I suspect you could cut out a lot of the code by using bindings.
(also note this answer was being constructed before you question update)

Create Instance variables at runtime

I want to create instance variables dynamically at runtime, and I want to add these variables to a category. The number of the instance variables may change based on the configuration/properties file which I am using for defining them.
Any ideas??
Use Associative References - this is tricky, but that is the mechanism invented specifically for your use case.
Here is an example from the link above: first, you define a reference and add it to your object using objc_setAssociatedObject; then you can retrieve the value back by calling objc_getAssociatedObject.
static char overviewKey;
NSArray *array = [[NSArray alloc] initWithObjects:# "One", #"Two", #"Three", nil];
NSString *overview = [[NSString alloc] initWithFormat:#"%#", #"First three numbers"];
objc_setAssociatedObject (
array,
&overviewKey,
overview,
OBJC_ASSOCIATION_RETAIN
);
[overview release];
NSString *associatedObject = (NSString *) objc_getAssociatedObject (array, &overviewKey);
NSLog(#"associatedObject: %#", associatedObject);
objc_setAssociatedObject (
array,
&overviewKey,
nil,
OBJC_ASSOCIATION_ASSIGN
);
[array release];
I'd be inclined to just use a NSMutableDictionary (see NSMutableDictionary Class Reference). Thus, you would have an ivar:
NSMutableDictionary *dictionary;
You'd then initialize it:
dictionary = [NSMutableDictionary dictionary];
You can then save values to it dynamically in code, e.g.:
dictionary[#"name"] = #"Rob";
dictionary[#"age"] = #29;
// etc.
Or, if you are reading from a file and don't know what the names of the keys are going to be, you can do this programmatically, e.g.:
NSString *key = ... // your app will read the name of the field from the text file
id value = ... // your app will read the value of the field from the text file
dictionary[key] = value; // this saves that value for that key in the dictionary
And if you're using an older version of Xcode (before 4.5), the syntax is:
[dictionary setObject:value forKey:key];
Depends on exactly what you want to do, the question is vague but if you want to have several objects or several integers or so on, arrays are the way to go. Say you have a plist with a list of 100 numbers. You can do something sort of like this:
NSArray * array = [NSArray arrayWithContentsOfFile:filePath];
// filePath is the path to the plist file with all of the numbers stored in it as an array
That will give you an array of NSNumbers, you can then turn that into an array of just ints if you want like this;
int intArray [[array count]];
for (int i = 0; i < [array count]; i++) {
intArray[i] = [((NSNumber *)[array objectAtIndex:i]) intValue];
}
Whenever you want to get an integer from a certain position, lets say you want to look at the 5th integer, you would do this:
int myNewInt = intArray[4];
// intArray[0] is the first position so [4] would be the fifth
Just look into using a plist for pulling data, it will them be really easy to create arrays of custom objects or variables in your code by parsing the plist.

Load an element value of an array to another array Xcode Objective-C

Here I am getting the cityName1 with the city names like Piscataway, Iselin, Broklyn etc fetched from the tgpList1 array and I need to put the values into an array called item5.
There are 133 records fetched by the above iteration. The following code stores only the last record's cityName1 and not the entire list of city names though inside the loop.
I tried many ways but I am missing something.
tgpList1 is an array.
tgpDAO is an NSObject with two objects NSString *airportCode and NSString *cityName
NSArray *item5 = [[NSArray alloc]init];
for (int currentIndex=0; currentIndex<[tgpList1 count]; currentIndex++)
{
tgpDAO *tgpTable = (tgpDAO *)[self.tgpList1 objectAtIndex:currentIndex];
NSLog(#"The array values are %#",tgpList1);
NSString *cityName1 = tgpTable.cityName;
item5 =[NSArray arrayWithObjects:cityName1, nil];
}
Use mutable array.
{
NSMutableArray *item5 = [[NSMutableArray alloc]initWithArray:nil];
for (int currentIndex=0; currentIndex<[tgpList1 count]; currentIndex++) {
tgpDAO *tgpTable = (tgpDAO *)[self.tgpList1 objectAtIndex:currentIndex];
NSLog(#"The array values are %#",tgpList1);
NSString *cityName1 = tgpTable.cityName;
[item5 addObject:cityName1];
}
}
Instead of
item5 =[NSArray arrayWithObjects:cityName1, nil];
use
[item5 addObject:cityName1];
There are more ways of achieving that. However, this is the one that is designed for that purpose and the most "readable" from my pont of view.
If you need to clear the contents of item5 before then call
[item5 removeAllObjects];
right before the for loop.
What you were doing: arrayWithObjects allways creates a new array that ist made of the objects that are passed to it as aguments. If you do not use ARC, then you would create some serious memory leak with your code because arrayWithObjects creates and retains an object on every loop and on the next loop all references to the array object, that was just created, are lost without being released. If you do ARC then you do not have to worry about in this case.
NSMutableArray *myCities = [NSMutableArray arrayWithCapacity:2]; // will grow if needed.
for( some loop conditions )
{
NSString* someCity = getCity();
[myCities addObject:someCity];
}
NSLog(#"number of cities in array: %#",[myCities count]);

Add cell to an Array using data from a UIPickerView?

I have a UIPickerView with three components, and each component has NSIntegerMax for the numbers. So, I just need to get the data from each component, and send it to another ViewController called, CreationViewController. The three objects I need to send are strings, set up like so:
NSInteger supplyData = [supplypick selectedRowInComponent:0];
NSInteger mineralData = [supplypick selectedRowInComponent:1];
NSInteger vespeneData = [supplypick selectedRowInComponent:2];
So, I would like to add each cell in the format of this log:
NSLog(#"%i %# M:%i G:%i", supplyData, namer.text, mineralData, vespeneData);
All I need to know it what to put...
NSMutableArray * array = [[NSMutableArray alloc] init];
[array addObject: ];
^^HERE^^
This is all in one function. Please help! Thanks!
[array addObject:[NSString stringWithFormat:#"%i %# M:%i G:%i", supplyData, namer.text, mineralData, vespeneData]];