objective c large random method, am i doing this right? - iphone

I've been building a simpler game with core graphics with random scripted encounters if that makes any sense and its started to become a huge method in the view controller.
-(void)spawnStuff{
CGPoint position;
CGPoint position1;
int chance = random()%10;
switch (chance) {
case 0:
[self spawnWall];
Position.y = 580;
Position.x = 160;
wall.center = Position;
[self spawnWall];
Position1.y = 480;
Position1.x = 80;
wall.center = Position1;
}
-(void)spawnWall{
UIImage* myImage = [UIImage imageNamed:#"Wall.png"];
Wall = [[Sprite alloc] initWithImage:myImage];
CGRect rect = CGRectMake(0, 0, 90, 50);
more initilization stuff }
and I might repeat this line of code 20 - 30 different with positions of these walls and with only 10 different scenario its about a 3rd of the code in the class, its starting to get a lil redonkulous I'm still very new to programming and giant methods kinda scare me. Is this the right way to approach this?

If you do this kind of stuff often, I would suggest keeping an array of possible actions, and then just randomly pick one when necessary. Something like the following should show you how to do that.
Note, that you can add/subtract from the array at will, which changes the available blocks... This just shows, at the bottom, randomly picking and executing a block 100 times.
You can add/remove block from the appropriate places in your code to keep it local. This should at least get you started...
// If we want to perform some action randomly, then we build an array
// of possibly actions (blocks), and then randomly pick one and execute it.
// Figure out what type of block you want...
typedef void(^ActionBlock)(void);
NSMutableArray *possibleActions = [NSMutableArray array];
[possibleActions addObject:^{
NSLog(#"Doing Action Foo");
}];
[possibleActions addObject:^{
NSLog(#"Doing Action Bar");
}];
[possibleActions addObject:^{
NSLog(#"Doing Action Baz");
}];
[possibleActions addObject:^{
NSLog(#"Doing Action FooBar");
}];
[possibleActions addObject:^{
NSLog(#"Doing Action Blarg");
}];
[possibleActions addObject:^{
NSLog(#"Doing Action Zip");
}];
// Now, when I want to pick an action to perform...
for (int i = 0; i < 100; ++i) {
ActionBlock block = [possibleActions objectAtIndex:arc4random_uniform(possibleActions.count)];
block();
}
EDIT
The line
typedef void(^ActionBlock)(void);
is a typedef, and defines a type for a specific kind of block. Granted, the syntax for functions and blocks is a bit hard to read. Maybe I should take a step back. I hope it does not offend you, and apologize in advance if it is patronizing in any way. It is similar to
typedef int IntType;
typedef void const * OpaqueType;
which are a bit easier to read. The first defines a type, IntType of type integer, and the second defines a type, OpaqueType, of type "pointer-to-const-void." You can then declare variables like...
IntType someInteger;
OpaqueType someOpaqueValue;
Now, in basic C, we can also declare function pointers. Lets say we have some functions...
int functionOne(int arg1, double arg2) {
// do whatever...
}
int functionTwo(int arg1, double arg2) {
// do whatever...
}
You can call that function easily enough...
int result = functionOne(42, 3.14159);
Well, you can also create a variable that points to the function, and you can call it like any other function.
int(*function)(int,double) = functionOne;
int result = function(42, 3.14159); // Calls functionOne
function = functionTwo;
result = function(42, 3.14159); // calls functionTwo
However, that syntax is a bit wearisome to type. So, especially for functions and blocks, we create typedefs. To create a typedef for a function, it's identical to creating a function pointer variable, but you just put the type in the place of the variable name. So...
typedef int(*MyFunction)(int, double);
declares a type that represents a pointer to a function that returns an int, and takes two parameters, and int and a double.
Now, the syntax for blocks is just like for function pointers, except trading a ^ for a *. So, out type...
typedef void(^ActionBlock)(void);
means that ActionBlock is a type that represents a block that returns void and takes no parameters.
So, you can declare variables of type ActionBlock, and assign them to blocks that have void return and no arguments. Which, in the example, is exactly what I did.
Note, that in the code, we create a bunch of blocks like this...
[possibleActions addObject:^{
NSLog(#"Doing Action Foo");
}];
The compiler allows you to leave out stuff that is obvious, so that code really says... Create a block, that takes no arguments, and has return type void, and then put it into the add it to the collection.
We do this multiple times, and then, when ready to invoke the functions, we just iterate over the collection. however, the compiler wants to know how to call the function/block, and all it gets from the collection is an . So, we want to cast the object we get to a type that tells the compiler it is a block that returns void, and takes no arguments.
When we do that, we can then call the function/block. So, let's look at that last piece again (with some comments), and a little bit less compact
for (int i = 0; i < 100; ++i) {
// We have a bunch of blocks stored in the array.
// We want to pick one at random, so we will get a random number
// between [0, size of our array).
uint32_t index = arc4random_uniform(possibleActions.count);
// Now, we have a random index into our array. Get the object in that position.
id randomObject = [possibleActions objectAtIndex:index];
// We have an opaque id type, but we know it's a block. Cast it to a block type.
ActionBlock block = randomObject;
// Now, we have our block, in a type that the compiler will let us invoke.
// Call it like any other function.
block();
}
EDIT
OK, here you go. Create an iVar, NSTimer *_timer. Schedule it in didLoad, and invalidate it in didUnload and dealloc
- (void)dealloc {
[_timer invalidate];
}
typedef void(^ActionBlock)(void);
- (void)callRandomFunction:(NSTimer*)timer {
// Our userInfo is actually our array of blocks
NSArray *actions = timer.userInfo;
ActionBlock block = [actions objectAtIndex:arc4random_uniform(actions.count)];
block();
}
- (void)viewDidLoad
{
[super viewDidLoad];
NSMutableArray *possibleActions = [NSMutableArray array];
// Create the list of possible functions that can be called...
// Now setup a timer that performs callRandomFunction: every second
// Pass the array of blocks as the userInfo of the timer.
_timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(callRandomFunction:) userInfo:possibleActions repeats:YES];
// Whatever else you need in here...
}
- (void)viewDidUnload
{
[_timer invalidate];
// Any other unload stuff...
[super viewDidUnload];
}

Related

Method returns 0 instead of the number I assigned to the variable

I'm trying to get the basics of iOS programming down. I have an app that shows a random number when I click a button.. At least, that's what I wanted to make. However, it doesn't seem to be working out.
I have the following basic method which should set the text of myLabel to the return value of generateRandomNumber. However, it always returns 0. I think the syntax I'm using here is correct since it works for the commented parts:
-(IBAction)myBtnPressed:(UIButton *)sender
{
//[myLabel setText:#"test"];
//[myLabel setText:[NSString stringWithFormat:#"%g / 15", 3.14]];
[myLabel setText:[NSString stringWithFormat:#"%g / 15", [myModel generateRandomNumber]]];
}
The last line sets the label to display 0/15. However, in my model, I have the following code ('static' for now):
-(double)generateRandomNumber
{
randomNumber = 1.34;
return randomNumber;
}
It doesn't return the 1.34 and I don't understand why it doesn't. Can someone clear this up?
Update
This is the code for my viewcontroller.m file:
#import "myViewController.h"
#implementation myViewController
-(MyModel *)myModel
{
if (! myModel) {
myModel = [[MyModel alloc] init];
}
return myModel;
}
-(IBAction)myBtnPressed:(UIButton *)sender
{
[myLabel setText:[NSString stringWithFormat:#"%g / 15", [myModel generateRandomNumber]]];
}
#end
Also, in the end, I want to make generateRandomNumber return a random number between 0 and 15. How would I do this? Would a simple line like:
int x = arc4random() % 16;
work for this? Or do I have to seed it in some way so it doesn't always return the same values when I run the application?
Thanks in advance.
It doesn't return the 1.34 and I don't understand why it doesn't. Can someone clear this up?
Almost certainly, you haven't allocated and initialised the myModel object. You can send messages to nil without crashing but the return value will be 0.
arc4random() doesn't need a seed.
Edit
Your init code looks OK but you are not calling int, in your myBtnPressed: method, you need
[myLabel setText:[NSString stringWithFormat:#"%g / 15", [[self myModel] generateRandomNumber]]];
Are you instantiating an object of your model type? I'm asking because you say that you have declared the function in myModel.h (Could be a typo).
And yes - to get a random number between 0 and X:
int rand = arc4random() % X;
And you don't need to seed the generator.
To return a double between 0 and 15:
// define this somewhere
#define ARC4RANDOM_MAX 0x100000000
// and then use this
double val = floorf(((double)arc4random() / ARC4RANDOM_MAX) * 15.0f);
random-thoughts-rand-vs-arc4random.html for more.
Did you ever alloc/create the myModel object?
I'm guessing that you didn't, and you're just trying to use the class as a 'methods' class that doesn't store anything (I know there's a name for it, but I'm self taught so my terminology is pretty horrible!)
You can do this in objective-c, but you've got to use different syntax. Instead of using minus signs for the method declaration, use "+":
+(double)generateRandomNumber;
and now your method should be usable!

Recursive call within a block completion in animateWithDuration?

I have a set of animations that need to operate sequentially with various checking done at each step. Because the size of the set is determined at run time, I expected to utilize a recursive call... but I am having trouble getting it to function within the 'block' paradigm.
The result is an EXEC_BAD_ACCESS regardless of whether I predeclared the block using
__block void (^myBlock)(BOOL) = ^(BOOL finished){ if (finished) [self nextStep];};
or not, as seen in the following code snippet. Upon debugging, it appears that the 'self' variable is indeed valid.
NSEnumerator* stepEnumerator;
-(void) mainRoutine {
stepEnumerator = [myArray objectEnumerator];
[self nextStep];
}
-(void) nextStep {
id obj;
if ((obj = [stepEnumerator nextObject])) {
// Do my checking at each location
....
// we have another spot to move to
[UIView animateWithDuration:animationDuration
animations:^{self.frame = newFrame;}
completion:^(BOOL finished){ if (finished) [self nextStep];}];
}
}
else {
// we are done, finish house cleaning
}
}
Any help is greatly appreciated.
Thanks!
The answer to the question posed is, yes, recursive calls within a block completion are valid.
#BillBrasky brought up a good point about the block losing scope. I do not know enough to say if this is required or not as I have not found it to be an issue with my situation. Everything appears to work correctly for me on each successive iteration through my recursive function.
The core issue with the code as I originally wrote it and submitted it is the use of the FastEnumerator. This is DEFINITELY lost when you leave the current function and venture out into another event loop / new section of the stack frame. I realized as I thought more about it that there is probably quite a bit going on behind the scenes to make FastEnumeration work and it is quite logical that leaving the method would destroy the setup.
As a fix, I replaced the NSEnumerator with a simple integer that I then increment each time through the recursive function. I am not a big fan of this as it could lead to Out of Bounds style issues where as the FastEnumerator will not, nor will for (obj in array), but I don't know of another solution. I think I will post that as a separate question...
Corrected code:
int index;
-(void) mainRoutine {
index = 0;
if (index < [myArray count]) {
[self nextStep];
}
}
-(void) nextStep {
// obtain the object from the array
id obj = [myArray objectAtIndex:index++];
// do my checking on the object
...
[UIView animationWithDuration:animationDuration
animations:^{self.frame = [view frame];}
completions:^(BOOL finished) {
if (finished && index < [myArray count]) {
[self nextStep];
}
else {
// We are done, clean up
...
}
}];
}
Thanks again #BillBrasky, you helped point me down the correct path to resolve this. I was too focused on the recursion and my quick analysis of my 'self' object looked fine because everything except for one item was fine. Couple that with the debugger breaking on the block, not the actual offending line and who knows how long I would have been staring at the code without seeing the real issue.
Cheers.
I'm new to blocks too, but I just got done with a similar issue. In my case, the EXEC_BAD_ACCESS was caused because the block had gone out of scope. I suspect that sometime in your 2nd recursion, the block gets created with an odd stack frame because it's executing inside another block.
My solution was to keep the blocks in a property marked copy, e.g.
#property (nonatomic,copy) BOOL (^callback)(DownloadProgress*);
This ensures that everything is retained in a copy in case the original block object goes out of scope and is GC'd.

NSMutableArray memory leaks in recursive method

I have a recursive method that allocates an NSMutableArray, runs a recursive call and then releases the NSMutableArray. the method takes an array of numbers and a target value and then finds what combinations of the numbers can sum up to equal the target value e.g. target: 10, numbers: 5,5,4. the method returns an array of NSNumbers 5 and 5.
My problem is that a mutable array is always showing as a leak in the leaks instrument even though i am releasing it.
here is the recursive method:
-(NSMutableArray *) getCombsHelper:(NSArray *)numbers target:(int)target partial:(NSMutableArray *)partial {
int s = 0;
for (NSNumber *number in partial) {
s += [number intValue];
}
if (s == target)
[results addObject:partial];
if (s >= target)
return results;
for (int i = 0; i < [numbers count]; i++) {
NSMutableArray *remaining = [[[NSMutableArray alloc] init] autorelease];
int n = [[numbers objectAtIndex:i] intValue];
for (int j = i+1; j<[numbers count]; j++) {
[remaining addObject:[numbers objectAtIndex:j]];
}
//this is the array that is showing up as a leak.
NSMutableArray *partialRec = [[NSMutableArray alloc] initWithArray:partial];
[partialRec addObject:[NSNumber numberWithInt:n]];
[self getCombsHelper:remaining target:target partial:partialRec];
[partialRec release]; //the mutable array is released after the recursive call.
}
return results;
}
even if i autorelease it i am still getting it as a leak. Could this be a false positive leak? or is there something wrong i cant catch?
That method is odd;
results appears to be an instance variable that accumulate the results? That is generally odd; typically, you'll have something that calculates state into an ivar and a plain accessor that retrieves the ivar.
To expand: your recursive method is relatively expensive compared to a straight getter method. Say you need results in three places; if this recursive method is the only way to retrieve results, every call will incur calculation overhead. If, instead, you had something like:
- (void)combsHelper:...
- (NSArray*) results
{
return results;
}
Then you could do the calculation once and retrieve the results many times without incurring overhead (while you could do something like if (!results) [self combsHelper:...] in your getter, that'll lead to the getter causing mutation of state which is generally to be avoided -- best to separate the two).
don't name methods getSomething:...; get as a prefix is limited to a very specific use pattern (generally, pass by reference retrieval of a value -- uncommon)..
What array is leaking? Keep in mind that Instruments shows you the point of allocation of the leak, not where the real leak happens. If something is retaining the object elsewhere without a balanced release, that'll be your leak.
The leak is outside of this method; partialRec is being added to the results array. Something is probably retrieving it from said array, retaining it, and not balancing that with a release
Perhaps the complaint is that you pass partialRec to the method, then add it to an array (results), which you return, but you don't catch your return value.
Adding it to the array will retain it.
Where does 'results' come from anyway? I don't see its declaration.
You probably have a problem on this line:
[self getCombsHelper:remaining target:target partial:partialRec];
You are passing partialRec to another method, and it is not autoreleased.

Dynamically declare function name?

I am creating a list of bar buttons with its action functions (sFuncName as below), it is dynamically changed.
When user clicks on a button, sFuncName will be called.
for(int i = 0; i < 3 ; i++){
NSString* sFuncName = [NSString stringWithFormat:#"OnFunc_%d:", i ];
barButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:systemItem target:self
action:NSSelectorFromString(sFuncName)];
}
The question is: have I got any way to dynamically declare sFuncName to respond to buttons?
Example:
for(int i = 0; i < 3 ; i++){
NSString* sFuncName = [NSString stringWithFormat:#"OnFunc_%d:", i ];
- (void)sFuncName: (id)sender; //sFuncName: OnFunc_0, OnFunc_1, OnFunc_2
}
I don't see the advantage of creating a method declaration dynamically, as the code within these methods wouldn't be dynamic either.
So you should rather declare a single method which would be called by every button, to which you pass a tag or a reference to the sender (button) or some other value that enables your method to tell which button has been tapped prior to the method being called. You could do something like this:
-(void)buttonPressed: (int)tag {
if (tag == 0) {
// Code for first button
}
if (tag == 1) {
// Code for second button
}
// prepare code for further buttons...
}
You really shouldn't do this, this is bad coding practice and i promise you at some point in development you will regret it. On the other hand what you CAN do, is process stuff with blocks (like functions you declare inline and on the stack).
You would declare a block inline something like that:
void (^doStuff)(int, char *) = ^(int arg0, char *arg1) {
printf("hello block");
};
doStuff(1, "a");
doStuff(2, "b");
...
What you can do is make a subclass of your button that executes a given block statement on click.
More on Blocks: developer.apple.com

Returning multiple values from a method in Objective-C

I asked a similar question, but I couldn't get it working exactly. I'm building an iPhone app, and there is a method that I want called from different files. I figured the easiest way would simply be to make a method in another file, and call the method from the other files.
Here are some problems. I need to return multiple values from the method, after passing it multiple values. For example, I'm passing it: (int, int, int, string, string). And it needs to return all of those values, after they have been changed. Someone showed me this code:
- (NSDictionary *)EndOfTurn:(int)varTurns withFatness:(int)varFatness
{
varTurns--;
if (varTurns <= 0) {
varFatness = varFatness - 5;
}
else {
varFatness += 2;
}
return [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:varFatness], #"FATNESS", [NSNumber numberWithInt:varTurns], #"TURNS", nil];
}
However, this code doesn't work, and I need some more information to really understand it. Let's assuming I'm passing it these values:
int varMoney;
int varNumSheep;
int varNumShepherds;
NSString *test1;
NSString *test2;
So I need to get all of these values back from the method.
How do I declare this in the header file? This should be in an Objective-C file, but could you give me the code for the entire file so I can see where it would go with the #implementation and #end, whatnot. Also, how would I call this method?
What about passing in the values as pointers?
For example:
- (void) getValuesForInt:(int *)int1 anotherInt:(int *)int2 aBool:(BOOL *)bool1 anotherBool:(BOOL *)bool2 {
if (*int1 == 42 && *int2 == 0) {
*int1 = 0;
*int2 = 42;
}
if (*bool1 == NO) {
*bool2 = YES;
}
}
Then you can invoke it like:
int int1 = 42;
int int2 = 0;
BOOL bool1 = NO;
BOOL bool2 = NO;
[self getValuesForInt:&int1 anotherInt:&int2 aBool:&bool1 anotherBool:&bool2];
NSLog(#"int1: %d int2: %d bool1: %d bool2: %d", int1, int2, bool1, bool2);
//prints "int1: 0 int2: 42 bool1: 0 bool2: 1"
Edit:
This works equally well with objects. You'll often see this used when dealing with NSError objects:
NSError *error = nil;
[anObject doSomething:foo error:&error];
Can be implemented as:
- (void) doSomething:(id)terrible error:(NSError **)error {
if ([terrible isEqual:reallyBad]) {
if (error != nil) { *error = [NSError errorWithDomain:#"domain" code:42 userInfo:nil]; }
}
}
You can use a block closure to pass back multiple values from a method like this. -rrh
[self heyFunctionGiveMeBackTwoValuesFromThisFruitArray:#[#"apple", #"orange", #"banana", #"apple"] findThisFruit:#"apple" closureFunction:^(int fruitCount, NSString* fruitString)
{
NSLog(#"Two values returned, int-fruitCount:%d, NSString-fruiteString:%#", fruitCount, fruitString);
}];
- (void)heyFunctionGiveMeBackTwoValuesFromThisFruitArray:(NSArray*)fruitsArray findThisFruit:(NSString*)findThisFruit closureFunction:(void (^)(int fruitCount, NSString *fruitString))passBackResultsUsingThisClosure
{
NSInteger fruitsFound = 0;
NSString* fruitsMessage = [NSString stringWithFormat:#"No %# Found", findThisFruit];
for (NSString* string in fruitsArray)
{
if ([string compare:findThisFruit] == NSOrderedSame)
{
fruitsFound++;
}
}
if (fruitsFound > 0)
{
fruitsMessage = [NSString stringWithFormat:#"You have %# on your list this many times:%d", findThisFruit, fruitsFound];
}
passBackResultsUsingThisClosure(fruitsFound, fruitsMessage);
}
Results:
Two values returned, int-fruitCount:2, NSString-fruiteString:You have apple on your list this many times:2
If you have that many different things that need to be returned from a method, either encapsulate it into an NSDictionary as others have suggested or consider just defining a class. You can declare the instance variables and properties to encapsulate the data, as needed.
Defining a class to encapsulate such information proves to be quite efficient and maximizes flexibility. If you need to refactor your app such that the collection of data gains new fields, needs to be saved for later, or might need to gain functionality, a class will ease these changes.
Since you can only return a single value from any method in C and C-derived languages, you simply need to return a single value that represents all of your other values. This is what your sample code is doing with an NSDictionary.
The sample code is correct, even if it's a bit contrary to common Objective-C style.
What you declare in the header file is simply the declaration of the method, that is:
#interface MyClass : NSObject
- (NSDictionary *)EndOfTurn:(int)varTurns withFatness:(int)varFatness;
#end
In the source file, then:
#implementation MyClass
// code, as given above
#end
If you only need to return primitive values, then returning a struct may be the optimal solution. You get compile-time error checking (e.g. as opposed to an NSDictionary where you could attempt to read an invalid key), while not requiring all the code/files involved in creating a class.
typedef struct myStruct {
int varMoney;
int varNumSheep;
int varNumShepherds;
} myStruct;
Apple uses structs in many of their methods too (e.g. CGPoint, CGRect).
The reason this won't work with objects is because ARC forbids this.
One slight improvement to the last point in some designs is to use a struct holding enum members. This gives you the compile-time checking already mentioned, something that looks like an object in the return value, and the benefit of clear cases if you need to check the values in the return.
The struct:
typedef struct _SIXRecorderStateChange {
SIXRecorderState oldState;
SIXRecorderState newState;
} SIXRecorderStateChange;
The client code:
SIXRecorderStateChange stateChange = [recorderState stop];
if (stateChange.newState == SIXRecorderStopped) {
...
...