program not displaying simple side values for my triangle object properly in nslog - objective-c

Project file here if you want to download: http://files.me.com/knyck2/918odc
So I am working on the book "programming in Objective c 2.0" and working on exercise 8.5, where you have to build a bunch of classes and subclass a homemade abstract class into a square class a triangle class and a circle class. you also have to calculate the area and perimiter/circumference through methods on each object and display it on nslog.
Everything is pretty much set, but some weird values are being returned when i display the size of each side from my triangle class and I'm not sure why. one of the sides display as 0.000000 and the other two display as these huge floats/doubles:
521556413499497987605515504756958465074645713473678706698073680750705671496313493175192637227720116636212033961634738517717834352497805734697302078530634879721347399811072.000000
and
661675923659048238438515844320261245751425513854584815925028483891542482488445146590620251584462848.000000
When i go to debug it appears as if all values assign correctly so i am at a loss as to why this is displaying so funkily.
Thanks for any help you can provide,
Nick
here's the main:
#import <Foundation/Foundation.h>
#import "Rectangle.h"
#import "Triangle.h"
#import "Circle.h"
int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
Rectangle *myRect = [[Rectangle alloc] init];
Circle *myCircle = [[Circle alloc] init];
Triangle *myTriangle = [[Triangle alloc] init];
myRect.fillColor = 12345;
myRect.filled = NO;
myRect.lineColor = 29999;
[myRect setWidth:15.3 andHeight:22.3];
NSLog(#"the rectangle has a filled color of %i,line color of %i",
myRect.fillColor, myRect.lineColor);
if (myRect.filled == YES)
NSLog(#"The rectangle is also filled");
else if (myRect.filled == NO)
NSLog(#"The rectangle is not filled");
NSLog(#" rectangle %f, %f, area %f, perimeter %f",
myRect.w , myRect.h, myRect.area, myRect.perimeter);
myCircle.fillColor = 15555;
myCircle.filled = NO;
myCircle.lineColor = 32349;
[myCircle setR:15.2];
NSLog(#"the circle has a radius of %f ,color of %i, line color of %i",
myCircle.r, myCircle.fillColor, myCircle.lineColor);
NSLog(#"Also the circles area is %f and the circumference is %f",
myCircle.area, myCircle.circumference );
myTriangle.fillColor = 71611;
myTriangle.filled = NO;
myTriangle.lineColor = 78998;
[myTriangle setSide1:13];
[myTriangle setSide2:19];
[myTriangle setSide3: 27.5];
NSLog(#"triangle sides %g, %g and %g."), // << error
myTriangle.side1 , myTriangle.side2 , myTriangle.side3 ;
NSLog(#"triangle area %f, perimeter %f.",
myTriangle.area, myTriangle.perimeter );
NSLog(#"triangle fill color %i, line color %i",
myTriangle.fillColor, myTriangle.lineColor);
[myCircle release];
[myRect release];
[myTriangle release];
[pool drain];
return 0;
}
and here's the interface and implementation:
#import <Foundation/Foundation.h>
#import "GraphicObject.h"
#interface Triangle : GraphicObject
{
double side1;
double side2;
double side3;
}
#property double side1, side2, side3;
-(void) setSides: (double)s1: (double)s2 : (double)s3;
-(double) area;
-(double) perimeter;
#end
Triangle.m
#import "Triangle.h"
#import <math.h>
#implementation Triangle
#synthesize side1, side2, side3;
-(void) setSides: (double) s1: (double) s2:(double) s3
{
side1 = s1;
side2 = s2;
side3 = s3;
}
-(double) area
{
return sqrt( (side1 + side2 + side3)
* (side1 + side2 - side3)
* (side2 + side3 - side1)
* (side3 + side1 - side2) / 16);
}
-(double) perimeter
{
return side1 + side2 + side3;
}
#end
also here is the super class, GraphicObject.h
#import <Foundation/Foundation.h>
#interface GraphicObject : NSObject
{
int fillColor;
BOOL filled;
int lineColor;
}
#property int fillColor, lineColor;
#property BOOL filled;
#end
GraphicObject.m
#import "GraphicObject.h"
#implementation GraphicObject
#synthesize fillColor, lineColor, filled;
#end

The problem is this line:
NSLog(#"the triangle has the sides of sizes %g, %g and %g."), myTriangle.side1 , myTriangle.side2 , myTriangle.side3 ;
Using ) before the , means that your call to NSLog provides no values to substitute for those %g when formatting for output. It appears unintentional, as my old friend used to say "All errors stem from copy and paste.... all of them".
The fix is to move the ) to just before the ; like so:
NSLog(#"the triangle has the sides of sizes %g, %g and %g.", myTriangle.side1 , myTriangle.side2 , myTriangle.side3);

Related

Trouble with Polymorphism example from Programming in Objective-C, Stephen Kochan, 6th Edition (Program 9.1)

** UPDATE **
I have changed the extraneous division by zero error in the reduce method. This was not causing the problem.
Original Question Text
I am in the process of reading Stephen Kochan's book, Programming in Objective-C, 6th Edition. There is a program in Capter 9 (9.1) that demonstrates Polymorphism by having complex numbers and fraction each have a print method and an add method.
resultComplex = [c1 add: c2]
and
resultFraction = [f1 add: f2]
and likewise with the print methods. It is completely understandable to me but there appears to be a bust somewhere in the code and I was hoping someone could help. The book is excellent and previous chapters build on themselves with existing code. The earlier versions of the code have all worked. I am suspecting that I have done something stupid like mis-typed something but I've been pouring over it for a few hours.
The output is as follows:
Chapter_9[5617:303] 18 + 2.5i
Chapter_9[5617:303] +
Chapter_9[5617:303] -5 + 3.2i
Chapter_9[5617:303] -----------
Chapter_9[5617:303] 13 + 5.7i
Chapter_9[5617:303]
Chapter_9[5617:303] 1/10
Chapter_9[5617:303] +
Chapter_9[5617:303] 2/15
Chapter_9[5617:303] ------
(lldb)
The program is able to add the Complex numbers but dies at the point it is required to add the Fractions. Xcode identifies add method in Fraction as the offender the following line as the offensive point:
Fraction *result = [[Fraction alloc] init]; // must be alloc/init here
I will include the class files (.h and .m) for the Fraction class. I am leaving out the Complex class because that part of the code runs fine, although there is an analogous line in that Class that seems to work fine. If it is necessary, I will update the post to add those. I just didn't want to drown everyone with that code if my error is obvious.
UPDATE
I am inserting a picture of the debug and output
Fraction Header File
//
// Fraction.h
// Chapter_9
#import <Foundation/Foundation.h>
#interface Fraction : NSObject
#property int numerator, denominator;
-(void) print;
-(void) setTo: (int) n over: (int)d;
-(double) convertToNum;
-(Fraction *) add: (Fraction *) f;
-(void) reduce;
#end
Fraction Implementation File
//
// Fraction.m
// Chapter_9
#import "Fraction.h"
#implementation Fraction
#synthesize numerator, denominator;
-(void) print
{
NSLog (#"%i/%i", numerator, denominator);
}
-(double) convertToNum
{
if (denominator != 0)
return (double) numerator / denominator;
else
return NAN;
}
-(void) setTo: (int) n over: (int) d
{
numerator = n;
denominator = d;
}
-(void) reduce
{
int u = numerator;
int v= denominator;
int temp;
while (v!= 0) {
temp = u % v;
u = v;
v = temp;
numerator /= u;
denominator /=u; //originally there was an unrelated error here
}
}
-(Fraction *) add: (Fraction *) f
{
// To add two fractions:
// a/b + c/d = ((a*d) + (b*c) / (b*d)
// Store the answer in a new Fraction object called (result)
// ************* Here is where Xcode identifies the error *******************
Fraction *result = [[Fraction alloc] init]; // must be alloc/init here
result.numerator = numerator * f.denominator + denominator * f.numerator;
result.denominator = denominator * f.denominator;
[result reduce];
return result;
}
#end
Program Main File:
//
// main.m
// Chapter_9
// Programming in Objective-C, Stephen Kochan, 6th Edition
//Problem 9.1: Shared Method Names: Polymorphism
#import "Fraction.h"
#import "Complex.h"
int main(int argc, const char * argv[])
{
#autoreleasepool {
Fraction *f1 = [[Fraction alloc] init];
Fraction *f2 = [[Fraction alloc] init];
Fraction *fracResult;
Complex *c1 = [[Complex alloc] init];
Complex *c2 = [[Complex alloc] init];
Complex *compResult;
[f1 setTo: 1 over: 10];
[f2 setTo: 2 over: 15];
[c1 setReal: 18 andImaginary:2.5];
[c2 setReal: -5 andImaginary: 3.2];
//add and print 2 complex numbers
[c1 print]; NSLog(#" +"); [c2 print];
NSLog(#"-----------");
compResult = [c1 add: c2]; //compResult is alloc/init in add method
[compResult print];
NSLog(#"\n");
// add and print 2 fractions
[f1 print]; NSLog(#" +"); [f2 print];
NSLog(#"------");
// ******************** Here is where the method call takes place that causes the error
fracResult = [f1 add: f2]; //fracResult is alloc/init in add method
[fracResult print];
}
return 0;
}
I am obviously new to Xcode and Objective-C and so am not able to debug on my own. Sorry for the long and drawn out explanation. I hope someone can help.
Xcode should be giving you a fairly clear division-by-zero error in your reduce method. You haven't copied it correctly from the book, I'm guessing, because your division-by-zero error is being caused by an error in your GCD algorithm.
This:
while (v!= 0) {
temp = u % v;
u = v;
v = temp;
numerator /= u;
denominator /=v;
}
should be this:
while (v!= 0) {
temp = u % v;
u = v;
v = temp;
}
numerator /= u;
denominator /=u;

Objective C inheritance and syntax

I am starting to learn basic of Objective-C, currently reading Kochan's (Progamming Objective C).
I am stucked at Inheritance topic.
I have 2 Class and 1 subClass, XYPoint and Rectangle, Square (Square is subclass of Rectangle).
I have method which can retain value X and Y coordinate for Rectangle Object.
here is my main.m files
#import <Foundation/Foundation.h>
#import "Rectangle.h"
#import "Square.h"
#import "XYPoint.h"
int main(int argc, const char * argv[])
{
#autoreleasepool {
Square *square1 = [[Square alloc]init];
XYPoint *myPoint = [[XYPoint alloc]init];
[myPoint setX:33 andY:33];
[square1 setOrigin:myPoint];
[myPoint setX:25 andY:25];
NSLog(#"square1 origin is %i and %i",[[square1 origin]x],[[square1 origin]y]);
[myPoint setX:125 andY:125];
NSLog(#"square1 origin is %i and %i",[[square1 origin]x],[[square1 origin]y]);
[myPoint setX:25 andY:25];
NSLog(#"square1 origin is %i and %i",[[square1 origin]x],[[square1 origin]y]);
}
return 0;
}
and my Rectangle.m
-(void) setOrigin:(XYPoint *)pt{
if (!origin)
origin = [[XYPoint alloc]init];
origin.x = pt.x;
origin.y = pt.y;
}
-(XYPoint *)origin {
return origin;
}
and XYPoint.m files
- (void) setX:(int)xVal andY: (int) yVal{
x = xVal;
y = yVal;
}
Output from this Program is :
2014-01-23 15:25:36.368 Rectangle1[4356:303] square1 origin is 33 and 33
2014-01-23 15:25:36.370 Rectangle1[4356:303] square1 origin is 33 and 33
2014-01-23 15:25:36.370 Rectangle1[4356:303] square1 origin is 33 and 33
NSLogged 3 times. this retain method -(void) setOrigin:(XYPoint *)pt;
helped to retain XY values on Rectangle Object even XY value reseted through setX andY method.
but when I changed retain method into this :
-(void) setOrigin:(XYPoint *)pt{
if (!origin)
origin = [[XYPoint alloc]init];
origin = pt;
}
NSLogged output changed into this :
2014-01-23 15:29:54.287 Rectangle1[4398:303] square1 origin is 25 and 25
2014-01-23 15:29:54.288 Rectangle1[4398:303] square1 origin is 125 and 125
2014-01-23 15:29:54.289 Rectangle1[4398:303] square1 origin is 25 and 25
what is the difference between those two ? aren't those two have the same characteristic pointing at the same coordinate both for x and y?
Because You're creating an origin with the name myPoint using the following :
[myPoint setX:33 andY:33];
And then you're making the myPoint as origin of square 1using :
[square1 setOrigin:myPoint];
And then you're changing the co-ordinates of square using the statements:
[myPoint setX:25 andY:25];
[myPoint setX:125 andY:125];
[myPoint setX:25 andY:25];
When you change the values and then try to print the origin using the
[[square1 origin]x];
[[square1 origin]y];
You'll get the modified values because when you say :
[origin x]; // it points to myPoint.x which u r changing all the time.
and
[origin Y]; // it points to myPoint.y which u r changing all the time.
Finally you are getting the right output . Please analyse the code properly.
EDIT: You have gone wrong in defining:
-(void) setOrigin:(XYPoint *)pt;
when you do this :
-(void) setOrigin:(XYPoint *)pt{
if (!origin){
origin = [[XYPoint alloc]init];
origin = pt;// makes origin.X to point to pt.x and origin.Y to point to pt.y
}
}
you're just making origin point to pt (which is myPoint), i.e, origin is nothing but a pointer to pt ,so when myPoint's X and Y value changes. Your origin.x and origin.y changes. This is a shallow copy.
But when we do this :
-(void) setOrigin:(XYPoint *)pt{
if (!origin){
origin = [[XYPoint alloc]init];
origin.x = pt.x;// copies value in pt.x to origin.x, so when pt.x changes origin.x doesn't change
origin.y = pt.y;// copies value in pt.y to origin.y, so when pt.y changes origin.y doesn't change
}
}
We're acheiving a Deep Copy, which means whenever mypoint.x and mypoint.y changes our origin.x and origin.y doesn't change.

Trouble with NSString: using a controller to set an NSTextField?

I am using Xcode 4 writing a simple program to generate text based on user input. Im reading from two text fields successfully, but I am unable to send the result to a separate NSTextField. I'm confident I've made all the right connections in IB, and I'm sending the NSTextField the setStringValue method. I have created a ScaleGenerator object that I believe may be improperly creating the string itself. My Controller header looks like this:
#import <Cocoa/Cocoa.h>
#interface Controller : NSObject
{
IBOutlet NSTextField * notesField;
IBOutlet NSTextField * midiField;
IBOutlet NSTextField * resultField;
IBOutlet id scalegenerator;
}
- (IBAction) generate: (id) sender;
#end // Controller
The Controller implementation looks like this:
#import "Controller.h"
#import "ScaleGenerator.h"
#import <Foundation/foundation.h>
#implementation Controller
- (IBAction) generate: (id) sender
{
int midinote;
int notes;
NSString * scale;
midinote = [midiField intValue];
if(midinote < 0 || midinote > 127) {
NSRunAlertPanel(#"Bad MIDI", #"That MIDI note is out of range! (0 - 127)", #"OK", nil, nil);
return;
}
notes = [notesField intValue];
if(notes < 2 || notes > 24) {
NSRunAlertPanel(#"Bad Scale Size", #"You must have at least two notes in your scale, and no more than 25 notes!", #"OK", nil, nil);
return;
}
scale = [scalegenerator generateScale: midinote and: notes];
[resultField setStringValue:scale];
}
#end
My ScaleGenerator code looks like this:
#import "ScaleGenerator.h"
#import <math.h>
#implementation ScaleGenerator
- (NSMutableString *) generateScale: (int) midinote and: (int) numberOfNotes
{
double frequency, ratio;
double c0, c5;
double intervals[24];
int i;
NSMutableString * result;
/* calculate standard semitone ratio in order to map the midinotes */
ratio = pow(2.0, 1/12.0); // Frequency Mulitplier for one half-step
c5 = 220.0 * pow(ratio, 3); // Middle C is three semitones above A220
c0 = c5 * pow(0.5, 5); // Lowest MIDI note is 5 octaves below middle C
frequency = c0 * pow(ratio, midinote); // the first frequency is based off of my midinote
/* calculate ratio from notes and fill the frequency array */
ratio = pow(2.0, 1/numberOfNotes);
for(i = 0; i < numberOfNotes; i++) {
intervals[i] = frequency;
frequency *= ratio;
}
for(i = 0; i < n; i++){
[result appendFormat: #"#%d: %f", numberOfNotes + 1, intervals[i]];
}
return (result);
}
#end // ScaleGenerator
My ScaleGenerator object has one function, which is where I believe I may be messing things up. What kind of string can I iteratively append formatted text to?? And what method do I call??
You have not allocated/initialized your NSMutableString. Therefore the message appendFormat: goes to nil. Replace the line
NSMutableString * result;
with
NSMutableString * result = [[NSMutableString alloc] init];

SegmentedControl Always Zero

I am trying to build an application that rolls dice. Nothing fancy at all. However, I'm using a segmented control to determine the number of dice and the sides of the dice.
Here is the RollPressed code.
#import "DiceBrain.h"
#import "ViewController.h"
#interface ViewController ()
#property (readonly) DiceBrain *brain;
#end
#implementation ViewController
- (DiceBrain *) brain {
if (!brain) brain = [[DiceBrain alloc] init];
return brain;
}
- (IBAction)RollPressed:(id)sender {
int num_dice = dice.selectedSegmentIndex;
int num_sides = sides.selectedSegmentIndex;
NSLog(#"Number of Dice is %u and Number of Sides is %u", num_dice, num_sides);
int result = [self.brain RollDice:num_dice Sides: num_sides];
display.text = [NSString stringWithFormat:#"%g", result];
}
#end
According to NSLog there, I'm always using a zero. Of course, actuating using this logic to roll the dice results in the display showing me something like 3.82652e-308.
The logic used to roll the dice is
- (int)RollDice:(int)dice Sides:(int)num_sides{
total = 0;
for (int i = 0; i < dice; i++) {
total += (arc4random() % num_sides) + 1;
}
return total;
}
What could cause the segmented control to give me such funky results?
Sounds like your IBOutlets for sides and dice are not connected.
Check their value; it's probably NULL.

I have a problem using NSSize

I'm doing the challenge exercises in Aaron Hillegass' book Cocoa Programming for Mac.
What I'm trying to do is have a window resize to twice the height of the width. Here is my code so far.
#import "AppController.h"
#implementation AppController
-(id) init
{
[super init];
NSLog(#"init");
[window setDelegate:self];
return self;
}
-(NSSize) windowWillResize:(NSWindow*) sender
toSize:(NSSize)frameSize
{
int x;
NSSize mySize;
mySize.width = x;
mySize.height = 2*x;
NSLog(#"mySize is %f wide and %f tall",mySize.width,mySize.height);
return mySize;
}
This does not work as intended I'm sure I'm not using the NSSize type correctly. I don't know a lot of C so using the struct is where I think I'm making my mistake.
ADDENDUM: I changed the above code to the following.I know that I'm being passed an NSSize so there is no reason to create another one (i.e. mySize).However, I don't understand why this works. Can someone explain.
#import "AppController.h"
#implementation AppController
-(id) init
{
[super init];
NSLog(#"init");
[window setDelegate:self];
return self;
}
-(NSSize) windowWillResize:(NSWindow*) sender
toSize:(NSSize)frameSize
{
//float x = 100;
//NSSize mySize;
//mySize.width = x;
//mySize.height = x * 2;
//NSLog(#"mySize is %f wide and %f tall",mySize.width,mySize.height);
NSLog(#"mySize is %f wide and %f tall",frameSize.width,frameSize.height);
return NSMakeSize(frameSize.width, frameSize.width * 2);
}
#end
Let's think about what you want mySize to be.
You want its width to be the same as frameSize.width
You want its height to be frameSize.width * 2.
Now let's look at what you do with x:
You set mySize.width to be equal to it
You set mySize.height to be x * 2
From this we can conclude:
You want to set x to frameSize.width.
Alternatively, the entire method could just be return NSMakeSize(frameSize.width, frameSize.width * 2).
You should assign an initial value to x:
int x = 100;
Otherwise, outcome is undefined.