PDA

View Full Version : objc




jamesapp
Apr 4, 2008, 05:01 PM
james-collinss-macbook-pro:prog9 jamescollins$ gcc prog9.2.m -o prog9.2 -l objc
Undefined symbols:
".objc_class_name_Complex", referenced from:
literal-pointer@__OBJC@__cls_refs@Complex in cciaLwic.o
".objc_class_name_Fraction", referenced from:
literal-pointer@__OBJC@__cls_refs@Fraction in cciaLwic.o
ld: symbol(s) not found
collect2: ld returned 1 exit status

got this error message when i tried to run a program from a book.

here is my test file which i called prog9.2.m

[code]
//illustrate Dynamic Typing and Binding

#import "Fraction.h"
#import "Complex.h"

int main (int argc, char *argv[])
{
id dataValue;
Fraction *f1 = [[Fraction alloc] init];
Complex *c1 = [[Complex alloc] init];

[f1 setTo: 2 over: 5];
[c1 setReal: 10.0 andImaginary: 2.5];

// first dataValue gets a fraction

dataValue = f1;
[dataValue print];
printf ("\n");

//now dataValue gets a complex number

dataValue = c1;
[dataValue print];
printf ("\n");

[c1 free];
[f1 free];
[dataValue free];

return 0;
}
[code]

i think the problem is in Complex.h and Fraction.h so i will include those two files.

first Fraction.h

[code]
#import <objc/Object.h>
#import <stdio.h>

// define the fraction class

@interface Fraction : Object
{


int numerator;
int denominator;
}
-(void) print;
-(void) setNumerator: (int) n;
-(void) setDenominator: (int) d;
-(void) setTo: (int) n over: (int) d;
-(void) reduce;
-(int) numerator;
-(int) denominator;
-(double) convertToNum;

@end
[code]

and then Complex.h

[code]
//Interface file for Complex class

#import <objc/Object.h>

@interface Complex: Object
{
double real;
double imaginary;
double compResult;
}

-(void) print;
-(void) setReal: (double) a;
-(void) setImaginary: (double) b;
-(void) setReal: (double) a andImaginary: (double) b;
-(double) real;
-(double) imaginary;
-(double) compResult;
-(Complex *) add: (Complex *) f;
@end
[code]

any help would be appreciated.



gnasher729
Apr 4, 2008, 05:14 PM
Where are Fraction.m and Complex.m ?

jamesapp
Apr 4, 2008, 05:27 PM
here is complex.m

// Implementation file for Complex class

#import "Complex.h"
#import <stdio.h>

@implementation Complex;
-(void) print
{
printf (" %g + %gi ", real, imaginary);
}


-(void) setReal: (double) a
{
real = a;
}

-(void) setImaginary: (double) b
{
imaginary = b;
}

-(void) setReal: (double) a andImaginary: (double) b
{
real = a;
imaginary = b;
}

-(double) real
{
return real;
}

-(double) imaginary
{
return imaginary;
}

-(Complex *) add: (Complex *) f
{
Complex *result = [[Complex alloc] init];

[result setReal: real + [f real]
andImaginary: imaginary + [f imaginary]];

return result;
}
@end

and fraction.m

#import "Fraction.h"
#import <stdio.h>

@implementation Fraction;

-(Fraction *) initWith: (int) n: (int) d
{
self = [super init];

if (self)
[self setTo: n over: d];
return self;
}

// add a fraction to the receiver

-(Fraction *) add: (Fraction *) f
{
// to add two fractions
// a/b + c/d = ((a*d) + (b*c)) / (b * d)

// result will store the result of the addition
Fraction *result = [[Fraction alloc] init];
int resultNum, resultDenom;

resultNum = (numerator * [f denominator]) +
(denominator * [f numerator]);
resultDenom = denominator * [f denominator];

[result setTo: resultNum over: resultDenom];
[result reduce];

return result;
}

-(void) reduce
{
int u = numerator;
int v = denominator;
int temp;
while (v != 0) {
temp = u % v;
u = v;
v = temp;
}

numerator /= u;
denominator /= u;
}
-(void) print
{
printf (" %i/%i ", numerator, denominator);
}

-(void) setNumerator: (int) n
{
numerator = n;
}

-(void) setDenominator: (int) d
{
denominator = d;
}

-(int) numerator
{
return numerator;
}

-(int) denominator
{
return denominator;
}

-(double) convertToNum
{
if (denominator != 0)
return (double) numerator / denominator;
else
return 1.0;
}


-(void) setTo: (int) n over: (int) d
{
numerator = n;
denominator = d;
}
@end

Eraserhead
Apr 4, 2008, 05:39 PM
I'm not sure what your problem is, but I do have some general tips, see whether they help.

In complex.m
#Use NSLog not printf so you don't have to import stdio.h.

#In the add method as you are returning a reference you should create a new complex number to store the result, as you do in Fraction.m

In fraction.m you need to have a name for the second part of the init method.

You also need to have a general init method that for complex sets both values to 0 and for fraction sets the numerator (the top one) to 0 and the denominator to 1.

You also should use [c1 release] not [c1 free] to free the memory.

Sbrocket
Apr 4, 2008, 06:00 PM
Do you think you could wrap your code in tags so its a bit easier to read? Just edit the posts above.

Ok, your code has other problems that people above mentioned a few of...but you're not compiling correctly. You didn't compile your other files, so you're getting errors about missing symbols.

[code]
gcc -c Fraction.m Complex.m prog.m && gcc -o prog Fraction.o Complex.o prog.o -lobjc


In any case, running the compiled program results in a segfault so you have some memory management things to address.

@Eraserhead: He can't use -[NSObject release] since his classes are subclassed from Object rather than NSObject and he hasn't imported and linked in Foundation. I would do that, personally (subclass from NSObject not Object), import <Foundation/Foundation.h> and link in the framework like so:


gcc -c Fraction.m Complex.m prog.m && gcc -o prog -framework Foundation Fraction.o Complex.o prog.o -lobjc


You know...if you used Xcode you probably wouldn't have to deal with the nitty gritty compiling and such. :D

EDIT52: Oh, and you're getting a segmentation fault because of this: (Well, on yours its -[Object free] instead of -[NSObject release], but you should change that like I said)


dataValue = c1;
...
[c1 release];
[f1 release];
[dataValue release];


You're releasing the object that c1 (and dataValue) points to twice, so you get a segfault. Take out the [dataValue release].

EDIT53: Just to show you it does in fact work...


[~][19:29:14 bryan]$ gcc -c Fraction.m Complex.m prog.m && gcc -o prog -framework Foundation Fraction.o Complex.o prog.o -lobjc
Complex.m:45: warning: incomplete implementation of class ‘Complex’
Complex.m:45: warning: method definition for ‘-compResult’ not found
[~][19:39:09 bryan]$ ./prog
2/5
10 + 2.5i


Man, this turned into a long post.

Eraserhead
Apr 5, 2008, 04:21 AM
@Eraserhead: He can't use -[NSObject release] since his classes are subclassed from Object rather than NSObject and he hasn't imported and linked in Foundation. I would do that, personally (subclass from NSObject not Object), import <Foundation/Foundation.h> and link in the framework like so:

Ah, I've always used Xcode for Cocoa stuff so I've never had to worry about that stuff...

Sbrocket
Apr 5, 2008, 05:54 AM
Ah, I've always used Xcode for Cocoa stuff so I've never had to worry about that stuff...

Hehe, so do I. I just figured out this stuff as I was typing the post.

jamesapp
Apr 6, 2008, 02:56 PM
i believe one of my problems was when i compiled the program i used .h files instead of .m.
i still don't understand the segmentation fault error, didn't i free the variables?

Sbrocket
Apr 6, 2008, 09:09 PM
i believe one of my problems was when i compiled the program i used .h files instead of .m.
i still don't understand the segmentation fault error, didn't i free the variables?

You did...the problem is you over-freed the variables. That's what caused the segmentation fault. If you didn't release anything, it would just cause a leak (or in this case do nothing since the program just ends and the memory used by the program is freed anyway).

Say I do this:

Complex *aComplex = [[Complex alloc] init];
Complex *bComplex;

bComplex = aComplex;

[bComplex free]; // or [bComplex release];


That code is correct. However if I added one more line...
[aComplex free];
...then a segfault occurs since you're attempting to free/release the object that both aComplex and bComplex point to when its already been deallocated.

Have you got the compiling stuff down? You don't need the one with "-framework Foundation" if you're going to stay with subclasses of Object, I'm just used to using Foundation.

skochan
Apr 6, 2008, 09:16 PM
All you Xcode advocates will be happy to know that I'm going to get rid of all the Object.h, gcc, and printf stuff and work directly with NSObject, Xcode, and NSLog in the second edition of my book. The reason for the original approach was due to my hope that Objective-C would gain popularity on more than just the Mac OS X platform. Well, guess what? It hasn't happened! Therefore, I've decided that the second edition will avoid the switch from Object to NSObject and be more Mac-centric right from the start. Of course, I'm also revising it to address Objective C 2.0 (the biggest change will be the approach to memory management in light of the garbage collector). And for those of you who didn't like my description of the bitwise operators (admittedly there's a few of you out there), I promise to do a better job the second time around.

Suggestions for the 2nd edition are welcome.

Cheers,

Steve Kochan

Sbrocket
Apr 6, 2008, 09:33 PM
Not to get too far off-topic, but while you're here...

I would be careful about leaning too far into the garbage collection side of Objective-C 2.0. Proper memory management is still an important thing for budding programmers to learn properly unless they're only going to be developing for GC-enabled environments (of which the iPhone is not). Fundamentals can't hurt any, just expand the reader's breadth of knowledge.

Oh and implementing user interfaces in code (and not relying on Interface Builder too much, though it is an invaluable tool when it works for your project) is a good skill for new Cocoa developers, too. You could have this in there already, I dunno, I haven't picked up any books yet personally since I'm waiting for them to get updated (and hopefully find one with some Cocoa Touch stuff in it).

Krevnik
Apr 7, 2008, 02:25 AM
Oh and implementing user interfaces in code (and not relying on Interface Builder too much, though it is an invaluable tool when it works for your project) is a good skill for new Cocoa developers, too. You could have this in there already, I dunno, I haven't picked up any books yet personally since I'm waiting for them to get updated (and hopefully find one with some Cocoa Touch stuff in it).

While I agree it is fairly useful to understand how UI components fit together, it is also possible to take this too far. Merging your controllers and views are all to easy to do (I have issues with it myself on custom controls) and makes code harder to maintain. Interface Builder helps enforce this separation of view and application behavior.

But, it is still very important to understand how the UI bits connect to each other, as it will help when you get around to writing custom controls (which unless you are on the iPhone, will happen more often than you think).

jamesapp
Apr 7, 2008, 12:42 PM
took out [datavalue free]
program worked.

i have a question about posting code.
i have been placing [code] at the beginning and end of my program files.
what is the proper way to post code?

Sbrocket
Apr 7, 2008, 12:47 PM
took out [datavalue free]
program worked.

i have a question about posting code.
i have been placing [code] at the beginning and end of my program files.
what is the proper way to post code?

The opening tag is and the closing tag is [/ code] (without the space), so you need to replace your [code] closing tags with the [/ code] tag.

In other words...
[code]str = [[NSString alloc] init];[code]
...generates just that, whereas
[code]str = [[NSString alloc] init];[/ code]
...without the space generates...
[code]str = [[NSString alloc] init];