Random number generator method - objective-c

so I have this method that returns a letter (from A-Z) by creating a random number between 1-26 and then indexing a string array to pull out the letter. The only problem is that it does not generate a new letter when the method is called. How can I generate a new letter every time the method is called, like in a while loop. Here is my code:
-(NSString *)alphaGenerator{
NSUInteger randomLetterInteger = arc4random_uniform(26);
NSArray *alphabet = #[#"A",#"B",#"C",#"D",#"E",#"F",#"G",#"H",#"I",#"J",#"K",#"L",#"M",#"N",#"O",#"P",#"Q",#"R",#"S",#"T",#"U",#"V",#"W",#"X",#"Y",#"Z"];
NSString *alpha = alphabet[randomLetterInteger];
return alpha;
}
Also, how do I convert a number that is returned from the count method into a number that I can plug into the arc4random_uniform method? I receive the 'incompatible integer to pointer inversion initializing...' error. This is what I have for this:
-(NSUInteger)numOfDictions{
NSString *alpha = [self alphaGenerator];
NSUInteger numb = [cuisines[alpha] count];
NSUInteger *randomNumOfDictions = arc4random_uniform(numb);
return *randomNumOfDictions;
}

These two lines:
NSUInteger *randomNumOfDictions = arc4random_uniform(numb);
return *randomNumOfDictions;
should be:
NSUInteger randomNumOfDictions = arc4random_uniform(numb);
return randomNumOfDictions;
NSInteger is not an object type. It's a primitive type.

Related

Why would a function defined in the same class be considered undeclared? How to declare it properly?

I'm getting the error "undeclared identifier" on the commented line:
- (BOOL) isInIntArray:(NSInteger[])array theElem:(int)elem{
int i = 0;
NSInteger sizeOfArray = (sizeof array) / (sizeof array[0]);
while(i < sizeOfArray){
if(array[i] == elem){
return TRUE;
}
i++;
}
return FALSE;
}
- (int)getNextUnusedID{
int i = rand()%34;
while ([isInIntArray:idsUsed theElem:i]) { //here: Use of undeclared identifier 'isInIntArray'
i = rand()%34;
}
return i;
}
I really don't understand why, they are in the same .m file.
Why would that be?
Also, this code:
NSInteger sizeOfArray = (sizeof array) / (sizeof array[0]);
is giving me the warning:
Sizeof on array function will return Sizeof 'NSInteger *' (aka: 'int *') instead of 'NSInteger[]'"
How should I properly determine the size of an array?
It looks like you've missed out self from this line
while ([isInIntArray:idsUsed theElem:i])
This should be:
while ([self isInIntArray:idsUsed theElem:i])
As #CaptainRedmuff pointed out, you are missing the target object in method invocation, that is self.
//[object methodParam:x param:y];
[self isInIntArray:idsUsed theElem:i];
To your second Q. In C language you cannot determine the size of an array. That's why they are not used, since we have objects for this. I recommend you to use these:
NSMutableArray *array = [[NSMutableArray alloc] init]; // to create array
array[0] = #42; // to set value at index, `#` creates objects, in this case NSNumber
[array insertObject:#42 atindex:0]; // equivalent to the above
NSInteger integer = array[0].integerValue; // get the value, call integerMethod to get plain int
integer = [[array objectAtIndex:0] integerValue]; // equivalent to the above
[array containsObject:#42]; // test if given object is in the array
[array indexOfObject:#42]; // get index of object from array, NSNotFound if not found
array.count; // to get the number of objects
Important: These arrays have variable size and they are not limited! But you can access elements only at indexes 0..(n-1) (where n in number of objects) and you can set values only for indexes 0..n.
In other words, you can not do array[3] = #42; for empty array, you need to fill first 3 positions first (indexes 0, 1 and 2).
write this in .h file (declare the function)
- (BOOL) isInIntArray:(NSInteger[])array theElem:(int)elem;
and call the method using following way
while ([self isInIntArray:idsUsed theElem:i]) { //here: Use of undeclared identifier 'isInIntArray'
i = rand()%34;
}

How to add all decimal numbers in an NSMutableArray

I have a NSMutableArray which have some NSDecimalNumber in it, like (500,50.80,70,8000)
Now I want to add all those decimal numbers together.
I've tried to use
for (NSDecimalNumber *number in self.numbersArray)
{
NSDecimal *sum += [number decimalValue]
}
But failed.
A simple way to add all NSNumbers in an array is (similar to what #Mahonor said in a comment):
NSArray *myArray = ... // array of NSNumber (or NSDecimalNumber) objects
NSNumber *sum = [myArray valueForKeyPath:#"#sum.self"];
Contrary to what the Collection Operators: sum states, the numbers in the array are not converted to double, but to NSDecimal. Therefore, no precision is lost when adding decimal numbers. Even NSNumber objects which are not decimal numbers are converted to NSDecimal for the addition. The result of the summation is an instance of NSDecimalValue.
I verified (or tried to) that in two different ways. First, I ran this code
NSNumber *a = [NSNumber numberWithDouble:1.2];
NSNumber *b = [NSDecimalNumber decimalNumberWithString:#"-5.7"];
NSArray *myArray = #[a, b];
id sum = [myArray valueForKeyPath:#"#sum.self"];
and activated Objective-C message logging by setting the environment variable "NSObjCMessageLoggingEnabled=YES". As can be seen in the created "/tmp/msgSends-NNNN" file, decimalNumber (and not doubleValue) is sent to both number objects.
Second, I created a custom class implementing both decimalValue and doubleValue, and applied #sum.self to an array of objects of the custom class:
#interface MyClass : NSObject
#property (nonatomic, assign) double value;
#end
#implementation MyClass
- (NSDecimal)decimalValue
{
return [[NSNumber numberWithDouble:self.value] decimalValue];
}
- (double)doubleValue
{
return self.value;
}
#end
MyClass *a = [MyClass new]; a.value = 1.2;
MyClass *b = [MyClass new]; b.value = -5.7;
NSArray *myArray = #[a, b];
id sum = [myArray valueForKeyPath:#"#sum.self"];
By setting breakpoints in both methods, it is seen that only decimalValue is used for the summation (and valueForKeyPath:#"#sum.self" throws an exception if the class does not implement decimalValue).
One can also see that decimalValue is called from
-[NSArray(NSKeyValueCoding) _sumForKeyPath:]
and the assembler code for this method shows that NSDecimalAdd is uses to add the numbers.
Use - (NSDecimalNumber *)decimalNumberByAdding:(NSDecimalNumber *)decimalNumber
Take a look at NSDecimalNumber Class Reference
NSDecimalNumber *lNumber = [NSDecimalNumber zero];
for (NSDecimalNumber *number in self.numbersArray)
{
lNumber = [lNumber decimalNumberByAdding:number];
}
Manohar's suggestion in the comments is not bad. You can indeed use KVC collection operators to make a one-liner out of this: [myArray valueForKeyPath:#"#sum.doubleValue"];, but you potentially lose precision (depending on the numbers you have stored).
You're basically looking for "reduce" functionality; you need to chain calls to decimalNumberByAdding: so that each call has the succeeding element of the array as its argument. Doing this on an NSArray is easy enough, using performSelector:withObject:
#implementation NSArray (Reduce)
- (id)reduceUsingSelector: (SEL)sel
{
id res = [self objectAtIndex:0];
for( id obj in [self subarrayWithRange:(NSRange){1, [self count]-1}] ){
res = [res performSelector:sel withObject:obj];
}
return res;
}
#end
Use this like so: NSDecimalNumber * sum = [myArray reduceUsingSelector:#selector(decimalNumberByAdding:)];
The code you have isn't successful because NSDecimal is a struct, not an object; it shouldn't be declared as a pointer, and if it wasn't, you wouldn't be able to add it. That's not the right route to a solution.

How can I pass a C array to a objective-C function?

I'm not familiar with C. How can I pass a C array to a Objective-C function ?
I actually need an example of a class function converting NSArray to C arrays.
This is what I have so far:
+ (NSArray *)convertArray:(NSString*)array { //I don't think this is correct: the argument is just a NSString parameter and not an array
NSMutableArray * targetArray = [NSMutableArray array];
for (i = 0; i < SIZE; i++) //SIZE: I dunno how to get the size of a C array.
{
[targetArray addObject: [NSString stringWithString:array[i]];
}
return targetArray;
}
There are a few ways.
If your array size is fixed at compile-time, you can use the C99 static modifier:
-(void) doSomething:(NSString *[static 10]) arg
{
}
If not, you have to pass it as two separate arguments. One as a pointer to the first element of it, and the second as the length of it:
-(void) doSomething:(NSString **) arg count:(size_t) count
{
}
Now you can access your variables like any other array you may have.
Because you are dealing with a C-array of objective-c objects, you can actually use NSArray's built in constructor for turning a C-array into a NSArray:
NSArray *result = [NSArray arrayWithObjects:arg count:count];

Simple NSInteger and NSMutableArray question

I'm trying to access an array using another array integer value as an index.
NSInteger index=[appDelegate.randomRiddles objectAtIndex:appDelegate.randomRiddlesCounter];
int i = index;
questionText.text = [[appDelegate.currentRiddlesContent objectAtIndex:i] objectForKey:#"question"];
//where appDelegate.randomRiddlesCounter is an NSInteger and appDelegate.randomRiddles is a NSMutableArray
However I'm getting incompatible pointer to int conversion warning. How can I fix this above code? The warning I get is coming from the first line.
Try:
NSNumber *index = [appDelegate.randomRiddles objectAtIndex: appDelegate.randomRiddlesCounter];
int i = [index intValue];
questionText.text = [[appDelegate.currentRiddlesContent objectAtIndex: i] objectForKey: #"question"];
NSInteger is an integral type, not an object.
Try this:
int i = [index intValue];
An NSArray like object can only store Objective-C object pointers (i.e. everything that you can assign to an id)
With objectAtIndex you get the object, with indexOfObject:(id)anObject you get the corresponding index.
These two instructions are both valid:
id bla = [appDelegate.randomRiddles objectAtIndex:appDelegate.randomRiddlesCounter];
NSInteger index = [appDelegate.randomRiddles indexOfObject:myObject];
The second assumes that myObject is at least of type id
So you try to convert a pointer to an int. Therefore the warning is issued.

Is it more intelligent to use CFMutableArrayRef in this case?

I need to keep track of integer values in an array, and sometimes I need to modify a value in the array.
Right now I do this:
// Read an integer from the array
NSNumber* num = [NSNumber numberWithInteger:someInteger];
[numArray addObject:num];
To update a value:
// Update an integer in the array
NSNumber* num = [numArray lastObject]; // get old
NSInteger numInt = [numInt integerValue]; // convert
NSNumber* newNum = [NSNumber numberWithInteger:numInt + someAddition]; // create new
[numArray removeLastObject]; // remove old
[numArray addObject:newNum]; // set new
This is so bad. So many objects involved and all because NSNumber is immutable. Now I thought maybe I must step down into good old C and use CFMutableArrayRef? Can I store simple NSInteger values in there without all this overhead?
You could use replaceObjectAtIndex: withObject: command:
[numArray replaceObjectAtIndex:[array count]-1 withObject:newNum];
It's better than your method