New To Mac-Forums?

Welcome to our community! Join the discussion today by registering your FREE account. If you have any problems with the registration process, please contact us!

Get your questions answered by community gurus Advice and insight from world-class Apple enthusiasts Exclusive access to members-only contests, giveaways and deals

Join today!

 
Start a Discussion
 

Mac-Forums Brief

Subscribe to Mac-Forums Brief to receive special offers from Mac-Forums partners and sponsors

Join the conversation RSS
OS X - Development and Darwin Discussion and questions about development for Mac OS X.

Objective - c program help (source included)


Post Reply New Thread Subscribe

 
Thread Tools
JoshMcg

 
Member Since: Jun 06, 2008
Posts: 27
JoshMcg is on a distinguished road
Mac Specs: Blackbook - 2.4 GHZ Core 2 Duo - 2 GB RAM - 250 GB HDD

JoshMcg is offline
I am just learning objective-c. I have stephen kochan's new book on pre-order (anyone know when that should be out?) and I am just building simple programs for practice.

I made a program that calculates the first 13 numbers of Fibonacci's sequence, but now I am trying to make the program calculate one further number in the sequence per button push and I can't figure out how to do it. Here is the code I have so far. The error I get is that the variables in the else statement are undefined. I know that variables are protected and they can't be accessed from different functions (I guess the else statement makes it a different function?) but how do I get around this problem?

Code:
#import "control.h"

@implementation control
- (IBAction)generate:(id)sender 
{
	
	
	if (buttonPress != 1)
	{
		buttonPress = 1;
		int a = 0;
		int b = 1;
		int c;

		NSLog(@"%d", a);	//print first 
		NSLog(@"%d", b);	//print second
		c = a + b;
		NSLog(@"%d", c);	//print third
	
		int i;
		for (i=0; i<=9; i++) //print #4-#13 of the sequence
		{
			a = b;
			b = c;
			c = a + b;
			NSLog(@"%d", c);

		}
	}
	
	else // print one additional number in the sequence per button press
	{
		a = b;
		b = c;
		c = a + b;
		NSLog(@"%d", c);
	}
	
}

@end
edit - I found that if I initialize the variables in the @interface section it will compile but I get the warning "local declaration hides instance variable" and when you run the program the first button press gives you the first 13 numbers but every press after that gives a zero.
QUOTE Thanks
JoshMcg

 
Member Since: Jun 06, 2008
Posts: 27
JoshMcg is on a distinguished road
Mac Specs: Blackbook - 2.4 GHZ Core 2 Duo - 2 GB RAM - 250 GB HDD

JoshMcg is offline
I got it working using setters and getters, but the compiler still gives me a bunch of warnings. I know this isn't the best code, but am I at least on the right track? The textbox outlet is there because I would like to eventually have it display the results in the app window rather than the console but for now I am just trying one thing at a time. Here is the working code, sorry for the sloppiness. Originally I setup a new class to handle the setting and getting of the variables, but for some reason it didn't work. Is that the correct way to do it?

Code:
#import <Cocoa/Cocoa.h>

@interface control : NSObject {
    IBOutlet id textBox;
	int a;
	int b;
	int c;
	int buttonPress;
}

- (IBAction)generate:(id)sender;
- (void) seta: (int) newNumber;
- (void) setb: (int) newNumber;
- (int) a;
- (int) b;

@end

#import "control.h"

@implementation control
- (IBAction)generate:(id)sender 
{
	
	if (buttonPress != 1)
	{
		buttonPress = 1;
		int a = 0;
		int b = 1;
		int c;

		NSLog(@"%d", a);	//print first 
		NSLog(@"%d", b);	//print second
		c = a + b;
		NSLog(@"%d", c);	//print third
	
		int i;
		for (i=0; i<=9; i++) //print #4-#13 of the sequence
		{
			a = b;
			b = c;
			c = a + b;
			NSLog(@"%d", c);

		}
		[self seta: a];
		[self setb: b];
		[self setc: c];
	}
	
	else // print one additional number in the sequence per button press
	{
		a = [self a];
		b = [self b];
		c = [self c];
		a = b;
		b = c;
		c = a + b;
		NSLog(@"%d", c);
	}
	
}

- (int) a
{
	return a;
}

- (int) b
{
	return b;
}

- (int) c
{
	return c;
}

- (void) setc: (int) newNumber
{
	c = newNumber;
}


- (void) seta: (int) newNumber
{
	a = newNumber;
}

- (void) setb: (int) newNumber
{
	b = newNumber;
}

@end
QUOTE Thanks
mystic_fm

 
Member Since: Mar 15, 2007
Posts: 161
mystic_fm will become famous soon enough
Mac Specs: 17" MacBook Pro, 2.33GHz C2D, 2GB RAM

mystic_fm is offline
You've got a lot of issues in this code that I don't have time to dig through, but I will at least tell you that the undefined variable errors in the earlier version of the code were because your declarations of variables a, b and c were scoped to the first part of the "if" statement. (No, the "else" doesn't make it part of a different function.) Since you also wanted to use the same variables in the "else" part, the most likely approach would have been for you to move the declarations to before the "if" statement (so that you would be using the same variables in both places).

In the 2nd version of the code, you've got namespace confusion from using the same variable names (a, b, c) as locals within your "generate" function and also as instance variables of the class object (leading to the "local definition hides instance variable" error you mentioned). This is never a good idea, as can be seen in the "else" portion of your code shown here, where you may think you are assigning values to the locals from the instance variable accessor methods, but in fact you are using the accessor methods to get values for the instance variables and are immediately storing the values right back into the same instance variables they came from (and without using the mutator methods for the latter task).

Beyond these fundamental issues, you're also not really on the right track for making a program that responds to a button press to perform additional work. You may want to wait until you have that book in hand before going any further, so that you don't keep going further down the wrong road and accumulating more stuff that you'll only need to unlearn eventually. Or if you don't want to wait, then find some more online Obj-C tutorials and start going through those.
QUOTE Thanks
JoshMcg

 
Member Since: Jun 06, 2008
Posts: 27
JoshMcg is on a distinguished road
Mac Specs: Blackbook - 2.4 GHZ Core 2 Duo - 2 GB RAM - 250 GB HDD

JoshMcg is offline
Thank you for you help. Could you quickly tell me how it should be done? I am not asking for code, but just in english. It seems to me that if I just move the variable declarations outside the if statement the first code is very close to working, but then the buttonPress check doesn't work for some reason.
QUOTE Thanks
mystic_fm

 
Member Since: Mar 15, 2007
Posts: 161
mystic_fm will become famous soon enough
Mac Specs: 17" MacBook Pro, 2.33GHz C2D, 2GB RAM

mystic_fm is offline
Given how you have structured your code, you do need persistent instance values rather than local variables in order to keep around the current sequence data values for calculating subsequent values on subsequent button pushes. Since they are only used internally, you don't really need accessor and mutator methods. I'd define a, b, and c as instance variables (although I'd probably choose more descriptive names) and then use them directly in the Fibonacci calculations, with no automatic (local) variables at all. The value of buttonPress also needs to be persistent, either as an instance variable (as in your 2nd example) or as a static local variable in the generate method.

I would suggest restructuring things to at least move the Fibonacci calculations out of generate and into a separate method (perhaps named something like getNextFibonacciValue) that simply calculates the next value in the sequence. Your generate method would then call getNextFibonacciValue, in order to keep the Fibonacci calculation in exactly one unique place. Duplication of algorithmic code in multiple locations invites problems in any non-trivial program, so it's wise to get used to designing your code that way from the outset. In fact I'd go further and say that the code and persistent values for the Fibonacci algorithm belong in a separate class object that is composited into the controller class, which hides its internal data (a, b, and c) and just provides the next Fibonacci number as a return value from getNextFibonacciValue, since the generate method doesn't really need to know anything more than that.

EDIT: This is short enough that I'll whip up some code to make it clearer, so stop reading now if you want to try it yourself first. Notice that the restructured code is quite concise. I didn't create a separate Fibonacci class for this example, but it would be similar in most respects.

Code:
@interface appController : NSWindowController {
	int prev1;
	int prev2;
	int current;
	int seqVal;	
}
- (IBAction)generate:(id)sender;
- (int)getNextFibonacciValue;
@end

@implementation appController
- (IBAction)generate:(id)sender
{
	static int initialSeqShown = 0;
	if (!initialSeqShown)
	{
		for (int i = 0; i < 13; ++i)
			NSLog(@"%d", [self getNextFibonacciValue]);
		initialSeqShown = 1;
	}
	else
		NSLog(@"%d", [self getNextFibonacciValue]);
}

- (int)getNextFibonacciValue
{
	if (seqVal <= 1)
		current = seqVal++;
	else
	{
		prev2 = prev1;
		prev1 = current;
		current = prev1 + prev2;		
	}
	return current;
}
@end
QUOTE Thanks
JoshMcg

 
Member Since: Jun 06, 2008
Posts: 27
JoshMcg is on a distinguished road
Mac Specs: Blackbook - 2.4 GHZ Core 2 Duo - 2 GB RAM - 250 GB HDD

JoshMcg is offline
Thanks a lot for your help. This is what I came up with. I changed it a little so that it generates one number in the sequence per button press rather than generating the first 13 with one press.

Code:
#import <Cocoa/Cocoa.h>


@interface control : NSObject {
    IBOutlet id textBox;
	int a;
	int b;
	int c; 
	int press;
}

- (IBAction)generate:(id)sender;
- (int)nextNumber;

@end

#import "control.h"


@implementation control
- (IBAction)generate:(id)sender 
{
	NSLog(@"%d",[self nextNumber]); // print next number in fibonacci sequence
}

- (int)nextNumber
{
	if (!press) // for the first press return 0 because it is the first number in the sequence
	{
		press = 1;
		return 0;
	}
	else if (press == 1) // for the second press return 1 because that is the second number in the sequence
	{
		press = 2;
		return 1;
	}
	else if (press == 2) // for the third press set a and b equal to the first and second number in the sequence
	{
		press = 3;
		a = 0;
		b = 1;
	}
	else // set a and b as the most recently calculated numbers in the sequence
	{
		a = b;
		b = c;
	}
	c = a + b; // determine next value in the sequence by adding the most recent two values
	return c; 
}

@end
I do have a few more questions.

Is it okay to cut the nextNumber method short by returning values in the if statements?

If I was going to create a seperate fibonacci class would I have to initialize and alloc an instance of that class before I use it? Then all the work would be done by a single instance of the class. Is that right?

Rather than using NSLog to display the numbers I would like to output them using the textBox outlet. It is linked to a large text area in my GUI. I know that if I just use setStringValue it sets it to the new value and deletes the old value. Would I use a mutable string to add the new number values to the end of the string as they are created and output that?

Sorry about all the questions. I just finished coding and havn't done any research yet. I will edit my post if I find the answers I am looking for.

I am going to take your advice about doing tutorials for now to get a better understanding rather then trying my own projects.

Thanks again,

Josh
QUOTE Thanks
mystic_fm

 
Member Since: Mar 15, 2007
Posts: 161
mystic_fm will become famous soon enough
Mac Specs: 17" MacBook Pro, 2.33GHz C2D, 2GB RAM

mystic_fm is offline
Quote:
Originally Posted by JoshMcg View Post
I do have a few more questions.

Is it okay to cut the nextNumber method short by returning values in the if statements?
Yes, it's okay, although I generally try to avoid it. I was taught that it is better programming form to have exactly one exit point in any function, and I try to do that whenever possible (you may have noticed I arranged things that way in my implementation of the Fibonacci function). However, it is not at all uncommon to see multiple return statements embedded in nested code within a function in order to gain a slight performance improvement, or to simplify the code that follows.

Quote:
If I was going to create a seperate fibonacci class would I have to initialize and alloc an instance of that class before I use it? Then all the work would be done by a single instance of the class. Is that right?
It sounds like you are on the right track. Don't forget you'd need a pointer to the class as an instance variable in your controller class, e.g.:

Code:
#import "fibonacciGenerator.h"

@interface appController : NSWindowController {
	fibonacciGenerator *fibGen;
}
...
@implementation appController
- (id)init
{
	[super init];
	fibGen = [[fibonacciGenerator alloc] init];
	return self;
}
@end
Quote:
Rather than using NSLog to display the numbers I would like to output them using the textBox outlet. It is linked to a large text area in my GUI. I know that if I just use setStringValue it sets it to the new value and deletes the old value. Would I use a mutable string to add the new number values to the end of the string as they are created and output that
If you mean that you'd create an NSMutableString as an instance member of your controller class, and then append the next sequence value to its contents before making each call to setStringValue for the text area, then yes, that would be a reasonable approach.
QUOTE Thanks
JoshMcg

 
Member Since: Jun 06, 2008
Posts: 27
JoshMcg is on a distinguished road
Mac Specs: Blackbook - 2.4 GHZ Core 2 Duo - 2 GB RAM - 250 GB HDD

JoshMcg is offline
Is there any way to make something like this work?

Code:
[list appendString:(@", %d",[self nextNumber])];
I looked through the documentation and tried a few different things, but I can't get it.

list is defined like this in the @interface section

Code:
NSMutableString *list;
QUOTE Thanks
mystic_fm

 
Member Since: Mar 15, 2007
Posts: 161
mystic_fm will become famous soon enough
Mac Specs: 17" MacBook Pro, 2.33GHz C2D, 2GB RAM

mystic_fm is offline
Quote:
Originally Posted by JoshMcg View Post
Is there any way to make something like this work?

Code:
[list appendString:(@", %d",[self nextNumber])];
Replace "appendString" with "appendFormat" as I've shown below. Note that you also had some extraneous parentheses which I've removed:

Code:
[list appendFormat:@", %d", [self nextNumber]];
QUOTE Thanks
JoshMcg

 
Member Since: Jun 06, 2008
Posts: 27
JoshMcg is on a distinguished road
Mac Specs: Blackbook - 2.4 GHZ Core 2 Duo - 2 GB RAM - 250 GB HDD

JoshMcg is offline
I think I may have tried that last night, but when I do the program locks up on the second button click. Here is the code:

Code:
#import <Cocoa/Cocoa.h>


@interface control : NSObject {
    IBOutlet id textBox;
	int a;
	int b;
	int c; 
	int press;
	int firstPress;
	NSMutableString *list;
}

- (IBAction)generate:(id)sender;
- (int)nextNumber;

@end


#import "control.h"


@implementation control
- (IBAction)generate:(id)sender 
{
	if (!firstPress)   // print first number in sequence without comma
	{
		firstPress = 1;
		list = [NSMutableString stringWithFormat:@"%d", [self nextNumber]];
		[textBox setString:list];
	}
	else   // print next number in fibonacci sequence with comma before each number
	{
		[list appendFormat:@", %d",[self nextNumber]];
		[textBox setString:list];
	}
	
}

- (int)nextNumber
{
	if (!press) // for the first press return 0 because it is the first number in the sequence
	{
		press = 1;
		return 0;
	}
	else if (press == 1) // for the second press return 1 because that is the second number in the sequence
	{
		press = 2;
		return 1;
	}
	else if (press == 2) // for the third press set a and b equal to the first and second number in the sequence
	{
		press = 3;
		a = 0;
		b = 1;
	}
	else // set a and b as the most recently calculated numbers in the sequence
	{
		a = b;
		b = c;
	}
	c = a + b; // determine next value in the sequence by adding the most recent two values
	return c; 
}

@end
The debugger loads all this into the window on the second click. I have never seen it before.

Code:
[Session started at 2008-12-18 11:24:27 -0500.]

[Session started at 2008-12-18 11:24:34 -0500.]
Loading program into debugger…
GNU gdb 6.3.50-20050815 (Apple version gdb-768) (Tue Oct  2 04:07:49 UTC 2007)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i386-apple-darwin".Program loaded.
sharedlibrary apply-load-rules all
Attaching to program: `/Users/Josh/My Documents/Apps/Fibonacci/build/Debug/Fibonacci.app/Contents/MacOS/Fibonacci', process 1343.
(gdb)
QUOTE Thanks
mystic_fm

 
Member Since: Mar 15, 2007
Posts: 161
mystic_fm will become famous soon enough
Mac Specs: 17" MacBook Pro, 2.33GHz C2D, 2GB RAM

mystic_fm is offline
Quote:
Originally Posted by JoshMcg View Post
I think I may have tried that last night, but when I do the program locks up on the second button click.
First, I'd suggest replacing your declaration of textBox with this:

Code:
    IBOutlet NSTextField *textBox;
Also, you're not calling the correct selector on textBox; try setStringValue instead. (The NSTextField declaration above would have allowed the compiler to warn you about using the wrong selector, BTW.)

Code:
    [textBox setStringValue:list];
Third, I expect the error you encountered was because you never retained the NSMutableString object returned by stringWithFormat, as the latter returns an autoreleased object in the classic memory management mode (I'm assuming you haven't enabled the garbage collector on this test program). After your first iteration of "generate" completed and program control returned to the runtime loop, the autoreleased string object was automatically deleted. To fix this, you need to at least add the 2nd line below:

Code:
list = [NSMutableString stringWithFormat:@"%d", [self nextNumber]];
[list retain];
It would be safer to instantiate your NSMutableString in the init method (via alloc and init), rather than in one control path of your generate function. Even though that path ought to be the first one that's executed as the code is currently written, it's unwise to rely upon behavioral side effects like that. Using the init method would not only be safer, but would give you a retained string object that wouldn't give you the error you experienced.

Note that I'm not even touching upon the need to clean up this allocated string object when your program exits. You are getting into a number of areas here, such as Cocoa memory management, for which you need book(s) and a structured approach to learn your way around them; a few posts in a forum aren't going to suffice.
QUOTE Thanks
JoshMcg

 
Member Since: Jun 06, 2008
Posts: 27
JoshMcg is on a distinguished road
Mac Specs: Blackbook - 2.4 GHZ Core 2 Duo - 2 GB RAM - 250 GB HDD

JoshMcg is offline
Thanks again for your help. You were right on with all of your assumptions and the code works perfectly now.

I am going to the book store right now to read some of Stephen Kochan's first edition objective-c book while I wait for my pre-ordered second edition to come in.

Just one really quick question though, if I retain list manually like that and never release it is the memory released when the program is closed?
QUOTE Thanks
mystic_fm

 
Member Since: Mar 15, 2007
Posts: 161
mystic_fm will become famous soon enough
Mac Specs: 17" MacBook Pro, 2.33GHz C2D, 2GB RAM

mystic_fm is offline
Quote:
Originally Posted by JoshMcg View Post
Just one really quick question though, if I retain list manually like that and never release it is the memory released when the program is closed?
When a program terminates, my understanding is that any allocated memory is normally reclaimed by Mac OS X, whether the memory had been released by the program or not. Memory leaks are primarily an issue while a program is still running. However, it's much smarter to take care of releasing memory and other resources in the program in all cases; failing to do so would be a bit like a Navy fighter pilot who doesn't attempt to catch a wire during a carrier landing, instead trusting to some sort of last ditch*, emergency barricade system to stop his plane from going into the water.

Caveat: I'm not an expert in Mac OS X's internal behavior in this regard. All I've ever needed to know for my own purposes as an application developer is that it is always best to make certain you're releasing anything you've allocated once you don't need it anymore.

* is this a pun? I'm not quite sure.
QUOTE Thanks

Post Reply New Thread Subscribe


« Applescript Mouse Click and Other ... | xcode web browser help »
Thread Tools

Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off
Forum Jump

Similar Threads
Thread
Thread Starter
Forum
Replies
Last Post
Graphics program help lbrewer42 Images, Graphic Design, and Digital Photography 0 01-02-2008 12:05 AM
PSPSync Impressions mcsenerd OS X - Apps and Games 9 03-29-2005 09:27 PM
Apple to test retail program at Best Buy schweb Apple Rumors and Reports 6 04-12-2004 01:43 PM
Open Source is in Danger! dmonk Schweb's Lounge 3 08-28-2003 08:05 PM
Apple starts Rendezvous Logo Program schweb Apple Rumors and Reports 0 03-25-2003 08:06 AM

All times are GMT -4. The time now is 09:45 AM.

Powered by vBulletin
Copyright ©2000 - 2014, Jelsoft Enterprises Ltd.
X

Welcome to Mac-Forums.com

Create your username to jump into the discussion!

New members like you have made this community the ultimate source for your Mac since 2003!


(4 digit year)

Already a member?