Adding an object to a NSMutablearray doesn't work properly - objective-c

I have a situation where in a loop I'm trying to add an object to a NSMutableArray. At the end of the loop it is showing that 54 objects (as an example) are added to the array but when I'm trying to read the objects from the array, apparently they are all the same as each other and same as the last object that is inserted into the array.
Could anyone please help me with this issue.This is my code:
int counter=0;
for (int j=0; j<rows; j++)
{
Product *product ;
product = [[Product alloc] init];
int numberr= [product getImageNumber];
[wineList addObject:product];
counter = counter + 1;
}
After adding the objects,I'm testing the content of the array which I'm getting the same result for each item in the array
//testing
Product *producttest1 = wineList[1];
int numbertest1= [producttest1 getImageNumber];
Product *producttest2 = wineList[20];
int numbertest2= [producttest2 getImageNumber];
This is the definition of the Product class that I have :
#import "Product.h"
#implementation Product
int imageNumber;
bool isInCase;
-(id) init {
imageNumber = (arc4random() % 11) + 1;
isInCase = false;
return self;
}
-(int) getImageNumber {
return imageNumber;
}
-(void) setImageNumber:(int) number {
imageNumber = number;
}

Your -init method never initializes your class. Make a call to [super init].
-(id)init {
self = [super init];
if (self) {
imageNumber = (arc4random() % 11) + 1;
isInCase = false;
}
return self;
}

Your code should probably go like this,
int counter=0;
for (int j=0; j < rows; j++)
{
Product *product = [[Product alloc] init]; // Added variable declaration inside.
int numberr= [product getImageNumber];
[wineList addObject:product];
[product release]; // Added release for product
counter = counter + 1;
}

Related

Objective-C. access to property of item in array which consists of objects

I have the array which consists of objects:
ViewController *item1 = [ViewController new];
item1.name = #"Mary";
item1.Description = #"good girl";
ViewController *item2 = [ViewController new];
item2.name = #"Daniel";
item2.Description = #"bad boy";
ComplexArray= [NSArray arrayWithObjects: item1, item2, nil];`
i want to view in labels a name and description if name is equal Mary
for (int i = 0; i < [ComplexArray count]; i++) {
if (item[i].name isEqualString:#"Mary") {
_nameLabel.text= item[i].name;
_DescriptionLabel.text= item[i].Description;
}
}
Please help me
You basically had it. All I did was rename item to ComplexArray added [] around the isEqualToString call and added a break:
for (int i = 0; i < [ComplexArray count]; i++) {
ViewController *item = ComplexArray[i];
if ([item.name isEqualString:#"Mary"]) {
_nameLabel.text= item.name;
_DescriptionLabel.text= item.Description;
break; // Added
}
}
There are other ways, but this approach is fine.
BTW: variables should start, by convention, with a lowercase character.
Your problem is you didn't assign anything in item variable. Just update like this and it will work.
for (int i = 0; i < [ComplexArray count]; i++) {
ViewController *item = [ComplexArray objectAtIndex:i]; // you missed this line.
if ([item.name isEqualToString:#"Mary"]) { //you missed the opening "[" and closing "]"
_nameLabel.text= item.name;
_DescriptionLabel.text= item.Description;
}
}

Creating NSArray of repeated numbers

I want to initialize NSArray with given numbers of zeros. I need it to create an array of counters and in the end of the function return an index of the counter with highest value.
So the question is how to initialize NSArray of zeros of given length? Is there a good way to do it in 1-2 lines? Maybe there is a better way to count objects? How would you do it?
Thanks!
UPD: Here is the code of my existing function. It returns the maximum number of cards, which have the same rank.
+ (int)ranksMatched:(NSArray *)cards
{
NSMutableArray *ranksCounter = [[NSMutableArray alloc] initWithCapacity:[PlayingCard maxRank]];
for (int i = 0; i < [PlayingCard maxRank]; ++i) {
[ranksCounter addObject:[NSNumber numberWithInt:0]];
}
int maxIndex = 0;
int maxCount = 0;
for (PlayingCard *card in cards) {
int currentCount = [ranksCounter[card.rank] intValue] + 1;
if (maxCount < currentCount) {
maxCount = currentCount;
maxIndex = card.rank;
}
}
return maxCount;
}
I guess you want the group the cards by rank and return the rank of the largest group:
+ (int)ranksMatched:(NSArray *)cards
{
NSCountedSet *ranks = [NSCountedSet setWithArray:[cards valueForKeyPath:#"rank"]];
NSNumber *maxRank = nil;
NSUInteger maxCount = 0;
for (NSNumber *rank in ranks) {
NSUInteger rankCount = [ranks countForObject:rank];
if (rankCount > maxCount) {
maxRank = rank;
maxCount = rankCount;
}
}
return [maxRank intValue];
}
assuming you have
#interface PlayingCard : NSObject
#property (nonatomic, assign) int rank;
…
#end
And cardsis an array of PlayingCard.

Self and arrays problems

I am new to Objective C and I'm having trouble getting my head around a few things.
I am trying to make a big integer program, from which I read items entered in a string and put them into an individual elements in the array.
I am currently working on an add method which adds elements from both the arrays together to make a big number stored in a final array.
But I'm kind of confused about to get this array I made from the initWithString method into the array method. I have some understanding of self, but I don't really know how to use it in this sense.
#implementation MPInteger
{
}
-(id) initWithString: (NSString *) x
{
self = [super init];
if (self) {
NSMutableArray *intString = [NSMutableArray array];
for (int i = 0; i < [x length]; i++) {
NSString *ch = [x substringWithRange:NSMakeRange(i, 1)];
[intString addObject:ch];
}
}
return self;
}
-(NSString *) description
{
return self.description;
}
-(MPInteger *) add: (MPInteger *) x
{
//NSMutableArray *arr1 = [NSMutableArray arrayWithCapacity:100];
//NSMutableArray *arr2 = [NSMutableArray arrayWithCapacity:100];
//for (int i=0; i < 100; i++) {
//int r = arc4random_uniform(1000);
//NSNumber *n = [NSNumber numberWithInteger:r];
//[arr1 addObject:n];
//[arr2 addObject:n];
// }
self.array = [NSMutableArray initialize];
return x;
}
#end
int main(int argc, const char * argv[]) {
#autoreleasepool {
MPInteger *x = [[MPInteger alloc] initWithString:#"123456789"];
MPInteger *y = [[MPInteger alloc] initWithString:#"123456789"];
[x add: y];
}
}
So I want too add the x and y arrays, but I'm not sure how to get the arrays in the add method. Do I use self to represent one of the arrays and initialise it, and x to represent the other. I don't know if I'm going about it completely the wrong way. Some help to understand would be greatly appreciated.
When referring to self you're actually accessing the current instance of the class. In other languages this may be implemented as this instead. There are a couple ways of designing the approach you're going for but the simplest pattern is probably composition:
#interface MPInteger
{
NSMutableArray *digits;
}
#end
----------------------------------------------------------------------------
#implementation MPInteger
-(id) initWithString: (NSString *) x
{
// Create a new instance of this class (MPInteger) with a default
// constructor and assign it to the current instance (self).
self = [super init];
if (self) {
// Previously we initialized a string, but then threw it out!
// Instead, let's save it to our string representation:
self->digits = [NSMutableArray array];
for (int i = 0; i < [x length]; i++) {
NSString *ch = [x substringWithRange:NSMakeRange(i, 1)];
[self->digits addObject:ch];
}
return self;
}
// Depending on how you want to implement this function, it could return
// a new MPInteger class or update the current instance (self):
-(MPInteger *) add: (MPInteger *) x
{
NSArray *a = self->digits;
NSArray *b = x->digits;
// Have both strings for A + B, so use them to find C:
NSArray *c = ????;
// Return a new instance of MPInteger with the result:
return [ [ MPInteger alloc ] initWithString:c ];
}
#end
Notice that now the MPInteger class has an instance of an NSString object that will exist during the entire lifetime of the MPInteger object. To update/access this string, all you need to do is say:
self->digits

How to generate non repeating random number

I am trying to randomize numbers in an array. I am able to do that using arc4random() % [indexes count]
My problem is - If an array consists of 20 items, every time the array shuffles, in a batch of 5, different number should appear. Example :
first shuffle: 1,4,2,5,6.
second shuffle: 7,12,9,15,3
-(IBAction)randomNumbers:(UIButton *)sender
{
int length = 10; // int length = [yourArray count];
NSMutableArray *indexes = [[NSMutableArray alloc] initWithCapacity:length];
for (int i=0; i<5; i++)
[indexes addObject:[NSNumber numberWithInt:i]];
NSMutableArray *shuffle = [[NSMutableArray alloc] initWithCapacity:length];
while ([indexes count])
{
int index = arc4random() % [indexes count];
[shuffle addObject:[indexes objectAtIndex:index]];
[indexes removeObjectAtIndex:index];
}
// for (int i=0; i<[shuffle count]; i++)
NSLog(#"%#", [shuffle description]);
}
As per your requirement....kindly check this code
Make this a property
#synthesize alreadyGeneratedNumbers;
Add these methods in your .m
-(int)generateRandomNumber{
int TOTAL_NUMBER=20;
int low_bound = 0;
int high_bound = TOTAL_NUMBER;
int width = high_bound - low_bound;
int randomNumber = low_bound + arc4random() % width;
return randomNumber;
}
-(IBAction)randomNumbers:(UIButton *)sender
{
NSMutableArray *shuffle = [[NSMutableArray alloc] initWithCapacity:5];
BOOL contains=YES;
while ([shuffle count]<5) {
NSNumber *generatedNumber=[NSNumber numberWithInt:[self generateRandomNumber]];
//NSLog(#"->%#",generatedNumber);
if (![alreadyGeneratedNumbers containsObject:generatedNumber]) {
[shuffle addObject:generatedNumber];
contains=NO;
[alreadyGeneratedNumbers addObject:generatedNumber];
}
}
NSLog(#"shuffle %#",shuffle);
NSLog(#"Next Batch");
if ([alreadyGeneratedNumbers count] >= TOTAL_NUMBER) {
NSLog(#"\nGame over, Want to play once again?");//or similar kind of thing.
[alreadyGeneratedNumbers removeAllObjects];
}
}
Still I feel you need to some changes like
it will give you correct value, but what if user pressed 5th time?
out of 20 numbers you already picked 4 sets of 5 number, on on 6th time it will be in loop to search for next set of numbers and will become infinite.
So what you can do is, keep the track of shuffle and once it reaches the limit i.e, 20/5=4 disable the random button.
Declare array that contains already generated number in extension or header file
#property (strong, nonatomic)NSMutableArray *existingNums;
#property (assign, nonatomic)NSInteger maxLimit;
#property (assign, nonatomic)NSInteger minLimit;
Then implement given code in implementation file
#synthesize existingNums;
#synthesize maxLimit;
#synthesize minLimit;
- (NSInteger)randomNumber {
if(!existingNums)
existingNums = [NSMutableArray array];
while (YES) {
NSNumber *randonNum = [NSNumber numberWithInteger:minLimit+arc4random()%maxLimit];
if([existingNums containsObject:randonNum]) {
if([existingNums count] == (maxLimit - minLimit))
return -1; // All possible numbers generated in the given range
continue;
}
[existingNums addObject:randonNum];
return [randonNum integerValue];
}
return -1; // return error
}
Hope this will help you :)
This one works for me:
NSMutableArray *numbers = [NSMutableArray new];
BOOL addElement = YES;
int limit = 100; // Range from 0 to 36
int numElem = 10; // Number of elements
do
{
int ranNum = (arc4random() % limit) +1;
if ([numbers count] < numElem) {
for (NSNumber *oneNumber in numbers) {
addElement =([oneNumber intValue] != ranNum) ? YES:NO;
if (!addElement) break;
}
if (addElement) [numbers addObject:[NSNumber numberWithInt:ranNum]];
} else {
break;
}
} while (1);
NSLog(#"%#",numbers);
The problem with all these answers is that you need to review your previous generated random numbers and that takes extra time if you need a large number of random integers.
Another solution is using cryptography:
Generate a random key
Iterate between 0..n
Encrypt each integer and apply modulo the number of alternatives do you want to use to the output of the function.
There are some extra details to take into account that don't matter for your case.

NSMutableArray as global var causes crash

i have the following in the .h file as global var
NSMutableArray *garr;
and the below in the .m file
- (void)roundone {
if (!garr) {
garr = [[NSMutableArray alloc]init];
for (int x = 0; x < 900; x++) {
[garr addObject:[NSNumber numberWithInt: arc4random()%600]];
}
}
}
the problem in calling the var garr in any method however it returns the values in the nslog correctly but when i use the garr in the code the system crash!!! any ideas plz
-(IBAction)clicked:(id)sender{
NSLog(#"%#",garr);
//bubbleSort(array); // sort the array
int n = [garr count] ;
for (int i = 0; i < n-1; i++)
for (int j = 0; j < n-i-1; j++)
if ([[garr objectAtIndex: j] compare:[garr objectAtIndex: j+1]] ==
NSOrderedDescending)
//#define SWAP(arr, x, y)
do {
id oldX = [garr objectAtIndex: (j)];
// NSLog(#"%d %s",oldX ,oldX);
[garr replaceObjectAtIndex: (j) withObject: [garr objectAtIndex: (j+1)]];
[garr replaceObjectAtIndex: (j+1) withObject: oldX];
} while (0);
NSString *element;
NSEnumerator *iterator = [garr objectEnumerator];
while ((element = [iterator nextObject]) != nil)
NSLog(#"elments %#",element);
i dont what to complicate things in the code but the code works fine when the global var is inside the method but does not work when the garr outside the method
You should declare your global variables in the header, rather than defining them. Mark the variable extern, put a definition into a .m file, and initialize the variable to nil.
Header:
extern NSMutableArray *garr;
.m file:
NSMutableArray *garr = nil;
Rebuild everything, and the crash should be eliminated.