Get value from an array of objects in iOS - ios

I am newly to iphone. I am working on an application where we need to calculate the value from an array of objects.
I have created a NSObject class "Catalogue", which includes catalogue_Value and catalogue_quantity. Now, suppose if we have two catalogue object in my array, then i need to calculate the total value.
here is my code :
int initialTotalPoints = 9999;
int totalUsedPoints = 0;
for (int i = 0; i<[arrayCheckout count];i++)
{
Catalogue *catalog = [[Catalogue alloc] init];
catalog = [arrayCheckout objectAtIndex:i];
NSLog(#"checkout voucher %d is = %d*%d", i, catalog.catalogue_Value,catalog.catalogue_quantity);
totalUsedPoints = catalog.catalogue_Value * catalog.catalogue_quantity;
}
initialTotalPoints = initialTotalPoints-totalUsedPoints;
The problem is due to the for loop, always it is taking "totalUsedPoints" of my last array object. But in actually, i need to add "catalog.catalogue_Value,catalog.catalogue_quantity" in my "totalUsedPoints" as per my total array objects. Please help me to solve this problem. Thanks!

If you just want to sum up quantity*value per catalog
int totalPoints = 0;
for (int i = 0; i<[arrayCheckout count];i++) {
Catalogue *catalog = [arrayCheckout objectAtIndex:i];
totalPoints += catalog.catalogue_Value * catalog.catalogue_quantity;
}
// totalPoints is now the sum of each arrays catalogue_Value*catalogue_quantity
You could check out Blockskit, a nice package to make array iterations easier

There is nothing specific to objective c here. Every loop you are overwriting totalUsedPoints with a new value. You then do nothing with it, and it gets overwritten again. At the end of the loop it will only contain the last value assigned to it.
I think what you are looking for is:
totalUsedPoints += catalog.catalogue_Value * catalog.catalogue_quantity;
+= is equal to:
totalUsedPoints = totalUsedPoints + catalog.catalogue_Value * catalog.catalogue_quantity;
meaning it will be assigned with the previous value, plus the new value

This is computer science 101 stuff, not unique to Objective-C. Others have already posted info on what you were doing wrong and how to fix it. I wanted to point out another flaw in your code. Take a look at these 2 lines:
Catalogue *catalog = [[Catalogue alloc] init];
catalog = [arrayCheckout objectAtIndex:i];
In the first line you create a new, empty Catalogue object and save a pointer to it in the variable catalog. In the very next line you fetch an object from your arrayCheckout object and save a pointer to it in your catalog variable. You end up discarding the object you created one line before.
This is like building a brand new car, putting it in front of your house, then junking it and fetching an existing car from a numbered parking space in a parking lot.
In ARC the empty Catalogue object you create in the first object will get deallocated on the very next line, so you aren't leaking memory, but it's pointless and wasteful to create an object that you immediately discard. (Memory allocation is one of the slowest tasks in an OS like iOS. It has to make a kernel call)
If your program was using manual reference counting then you would have leaked the Catalogue object. It would never get deallocated. Those two lines should read like this:
Catalogue *catalog;
catalog = [arrayCheckout objectAtIndex:i];
Or even as 1 line:
Catalogue *catalog = [arrayCheckout objectAtIndex:i];

Related

NSMutable dictionary not working properly

I am developing an iPad application and for this application I have one function as below :-
-(void)testcurrentest:(NSMutableDictionary *)keydictionary{
NSArray *allKeys = [keydictionary allKeys];
if ([allKeys count] > 0) {
for(int i = 0;i< allKeys.count;i++){
[_currenies removeAllObjects];
NSString *product = [NSString stringWithFormat:#"%#", [keydictionary objectForKey:allKeys[i]]];
int kl = [productPriceSeasonCode intValue];
for(int i =0;i<kl;i++){
[_currenies addObject:#"0"];
}
NSLog(#"................%#",_currenies);
[_currencydictionary1 setObject:_currenies forKey:allKeys[i]];
NSLog(#"full dictionary...%#",_currencydictionary1);
}
}
}
Here, NSLog print the currencies array based on the kl integer values but when I'm trying to set the NSMutableDictionary the currencies but mutable array always show the latest array values.
You are using the same array for all values, they should be unique objects if you don't want change of one value to affect the other values. Initialise _currenies on every loop step or use its deep copy when preparing a new object.
A bit of code:
[_currenies removeAllObjects]; // < The same array you've added to dict on previous loop steps
Creating a new array at each loop step would create a unique object for all key-value pair:
_currenies = [NSMutableArray array]; // < Note it is not retained, apply memory management depending on your project configuration
Your code is a garbled mess. As others have pointed out, you are using the same loop index, i, in 2 nested loops, making it very hard to tell your intent. Don't do that, ever. It's horrible programming style.
You are also creating a string "product" that you never use, and fetching the same integer value of productPriceSeasonCode on every pass through the outer loop. I suspect you meant to fetch a value that varies with each entry in your keydictionary.
Then, you have an array, _currenies, which you empty on each pass through your outer loop. You then add a number of "0" strings to it, set a key/value pair in your _currencydictionary1 dictionary to the contents of that array, and then repeat. Since you re-use your _currenies array each time, every key/value pair you create in your _currencydictionary1 dictionary points to the exact same array, which you keep changing. At the last iteration of your outer loop, all the entries in your _currencydictionary1 will point to your _currenies array, which will contain the last set of contents you put there.
Create a new array for each pass through your outer array, and add that newly created array to your _currencydictionary1. You want a unique array in each key/value pair of your _currencydictionary1.
In short, NSMutableDictionary is working just fine. It's your code that isn't working properly.
Not an answer but comments don't have formatting.
The question should provide more information on the input and desired output.
First simplify your code and it should be easier to find the error:
-(void)testcurrentest:(NSMutableDictionary *)keydictionary{
NSArray *allKeys = [keydictionary allKeys];
for(NSString *key in allKeys) {
[_currenies removeAllObjects];
int kl = [productPriceSeasonCode intValue];
for(int i =0; i<kl; i++){
[_currenies addObject:#"0"];
}
NSLog(#"................%#",_currenies);
_currencydictionary1[key] = _currenies;
NSLog(#"full dictionary...%#",_currencydictionary1);
}
}
Note: product was never used.

Objective-C how to pull several random items out of NSArray without getting duplicates? [duplicate]

This question already has answers here:
Getting a random object from NSArray without duplication
(3 answers)
Closed 7 years ago.
I have an array of random properties I would like to assign to equipment within the game I'm developing.
The code that I use below is returning an NSArray. I'm interested if there's way to get item indices from that array without getting duplicate values. The obvious solution is to create a mutable array with the returned array, do random, remove item that was returned and loop until the number of items is received.
But is there a different way of getting X random items from NSArray without getting duplicates?
//get possible enchantments
NSPredicate *p = [NSPredicate predicateWithFormat:#"type = %i AND grade >= %i", kEnchantmentArmor,armor.grade];
NSArray* possibleEnchantments = [[EquipmentGenerator allEnchantmentDictionary] objectForKey:#"enchantments"];
//get only applicable enchantments
NSArray *validEnchantments = [possibleEnchantments filteredArrayUsingPredicate:p];
NSMutableArray* mutableArray = [NSMutableArray arrayWithArray:validEnchantments];
NSDictionary* enchantment = nil;
if(mutableArray.count>0)
{
//got enchantments, assign number and intensity based on grade
for (int i = 0; i<3;i++)
{
enchantment = mutableArray[arc4random()%mutableArray.count];
[mutableArray removeObject:enchantment];
//create enchantment from dictionary and assign to item.
}
}
You can shuffle the array using one of the following techniques:
What's the Best Way to Shuffle an NSMutableArray?
Non repeating random numbers
Then, take the first X elements from the array.
Many years ago, I was working on card game and I realized that shuffling the deck was an inefficient way to get random cards. What I would do in your shoes is pick a random element, and then replace it with the element at the end of the array, like so:
#interface NSMutableArray (pickAndShrink)
- (id) pullElementFromIndex:(int) index // pass in your random value here
{
id pickedItem = [self elementAtIndex:index];
[self replaceObjectAtIndex:index withObject:[self lastObject]];
[self removeLastObject];
return pickedItem;
}
#end
The array will shrink by one every time you pull an element this way.
You could use a random number generator to pick a starting index, and then pick the subsequent indices based on some kind of math function. You would still need to loop depending on how many properties you want.
Eg:
-(NSMutableArray*)getRandomPropertiesFromArray:(NSArray*)myArray
{
int lengthOfMyArray = myArray.count;
int startingIndex = arc4random()%lengthOfMyArray;
NSMutableArray *finalArray = [[NSMutableArray alloc]init]autorelease];
for(int i=0; i<numberOfPropertiesRequired; i++)
{
int index = [self computeIndex:i usingStartingIndex:startingIndex origninalArray:myArray];
[finalArray addObject:[myArray objectAtIndex:index]];
}
return finalArray;
}
-(int)computeIndex:(int)index usingStartingIndex:(int)startingIndex
{
//You write your custom function here. This is just an example.
//You will have to write some code to make use you don't pick an Index greater than the length of your array.
int computedIndex = startingIndex + index*2;
return startingIndex;
}
EDIT: Even your computeIndex function could use randomness in picking the subsequent indices. Since you have a startingIndex, and another index, you could use that to offset your function so that you never pick a duplicate.
EDIT: If your array is very large, and the subset you need to pick is small, then rather than shuffle the entire array (maybe more expensive), you could use this method to pick the number of items you need. But if your array is small, or if the number of items you need to pick are almost the size of the array, then the godel9's solution is better.
You can use a mutable array and then remove them as the are selected, use something like random()%array.count to get a random index. If you don't want to modify the array then copy it with [array mutableCopy].

Problems with objectAtIndex of NSMutableArray

I am developing a game for iPhone in which I have 2 arrays.
One with the objects "living" in the game, and when these objects "die" they are placed in another array to be removed from the first one in the end of the first loop.
This is necessary because if the object dies in the loop and it is removed immediately from the first array, the index is lost and sometimes gives an invalid address access.
Then I have an NSMutableArray that contains objects to be removed from the living objects array.
In the array with objects to remove, I am constantly adding and removing items. Sometimes when I use objectAtIndex with the array with items to remove, it is retuning me other object.
For example in the first moment _enemiesToRemove has 2 objects:
([0]-> 0x0a8b5120, [1]->0x18f3a090)
for(int i = [_enemiesToRemove count] - 1; i >= 0 ; i--){
fish = [_enemiesToRemove objectAtIndex:i];
[self removeEnemy:fish];
}
and then
int i = [_enemiesToRemove count] - 1
gives i=1 but when it is doing
[_enemiesToRemove objectAtIndex:i]
it is returning me other object with address 0xbfffcd58 and it should be [1]->0x18f3a090
What is happening here, somebody knows? It is not happening always. It happens randomly.

Searching NSMutableArray v.s. Sqlite search query

I have an app with a relatively large SQLite database, containing around 15,000 rows. At the start of the app, I run a SELECT * FROM TABLE query and populate a NSMutableArray *data containing elements of a class ProverbRow. Each ProverbRow object corresponds to one row of data from the database and contains NSStrings and NSIntegers corresponding to each cell of the database. So, effectively the NSMutableArray *data object is a copy of the SQLite database.
Now, to the question...
I want to add a search functionality in the app like this example :
When the user types in "abc" and taps search, I want to get all the elements of data where the NSString *proverb inside the ProverbRow object contains the string "abc" as the substring. So, the strings like "abcde", "qqqabcqqq", etc. should be obtained.
Currently, to accomplish this, I am firing a query like this : SELECT * FROM PROVERB WHERE PRONUNCIATION LIKE abc. The objects which I get back from the query are stored in another NSArray for further use.
Now, if there are only a small number of objects getting returned, then this query completes fast enough, but with larger number of rows, it takes a lot of time.
I was wondering whether there is a quicker way to accomplish this apart from firing the query. Is it possible to use the already populated data object and run it through a loop and equating the substring or something like that? My main concern is to reduce the time search takes.
Thanks!
15 k is tiny. Just do a linear scan of the in-memory objects.
The following test finds the xyz at the end of the alphabet 15000 times. Repeating this process 100 times took 4.7 s on my iPhone 5. That's 47 ms for a full scan that returns every element.
NSMutableArray * data = [[NSMutableArray alloc] initWithCapacity:15000];
for (int i = 0; i < 15000; ++i)
[data addObject:#[#"abcdefghijklmnopqrstuvwxyz", #123]];
NSLog(#"Starting test");
int count = 0;
for (int i = 0; i < 100; ++i) {
NSIndexSet * s = [data indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
NSString * s = obj[0];
return [s rangeOfString:#"xyz"].location != NSNotFound;
}];
count += s.count;
}
NSLog(#"Finished test: %d", count); // Outputs 1500000
Let me reiterate: 15 k is tiny.

Cocos2d/iOS: can't understand how to interpet a pointer address

I have a NSMutableArray containing 200 bullets (sublcass of CCSprite) created as following:
capacity=200;
bullets = [[NSMutableArray alloc] initWithCapacity:capacity];
// Create a number of bullets up front and re-use them whenever necessary.
for (int i = 0; i < capacity; i++)
{
Bullet* bullet = [Bullet bulletWithScreenRect:screenRect];
bullet.visible = NO;
bullet.bulletId=i;
[bullets addObject:bullet];
[self addChild:bullet];
}
I created a for loop to iterate them and added a breakpoint to see if the address was the same.
for (int i = 0; i < capacity; i++)
{
Bullet* bullet = [bullets objectAtIndex:i];
CCLOG(#"%i %i", i, bullet.bulletId);
}
The result is that the pointer "bullet" always refers to the same address in memory for all 200 bullets (0x1336c8a0). I added a property in bullet (int:bulletId) to try identify if they are different objects or not but it seems so. I don't understand why the pointer has always to the same address (does it refer to the same address? or is it just the pointer memory address?).
Here is where I get the 0x1336c8a0 address from the Bullet* pointer:
I would look in the bulletWithScreenRect method of the Bullet class. I assume this is a factory method, but maybe it just returns the same static object. You could alloc and init the Bullet object yourself, and then I assume there is a way to set the screen rectangle separately.
In other words, change:
Bullet* bullet = [Bullet bulletWithScreenRect:screenRect];
To something like this:
Bullet* bullet = [[Bullet alloc] init];
bullet.screenRect = screenRect; // Not sure if this setter is present.
At the very least, just for a sanity check you can change the constructor of the Bullet class, to ensure you are creating separate instances. Like I said, check the contents of the bulletWithScreenRect method to see what it is really doing. That seems like the culprit to me.
Well that means that you only have one instance of Bullet in your array. In that case, your problem is definitely in your bulletWithScreenRect method, which returns a cached instance instead of a new one.
The address you're seeing the debugger is the address to which the pointer is pointing not the address of the pointer, which would be more or less useless. Since the address to which the pointer is pointing is always the same, it's clear that we're talking about the same object.
To test what I've just said, you could print the address and compare it to the value you get in the debugger:
NSLog(#"Pointer own address: %p", &bullet);
NSLog(#"Address to where the pointer is pointing: %p", bullet); //this is what you should get in the debugger

Resources