gcc compile errors in an basic example objc program - objective-c

Hey all, I'm new to programming and going through an objective-c book to learn the language and programing fundamentals. I've looked through the code repeatedly, went back to the book's example, and attempted to understand the gcc comple errors. Here's my code:
#import <stdio.h>
#import <objc/Object.h>
#interface Point: Object
{
int xaxis;
int yaxis;
}
-(void) print;
-(void) setx: (int)x;
-(void) sety: (int)y;
#end
#implementation Point;
-(void) print
{
printf("(%i,%i)", xaxis, yaxis);
}
-(void) setx: (int) x
{
xaxis = x;
}
-(void) sety: (int) y
{
yaxis = y;
}
#end
int main (int argc, char *argv[])
{
Point *myPoint;
myPoint = [Point alloc];
myPoint = [myPoint init];
[myPoint setx: 4];
[myPoint sety: 5];
printf("The coordinates are: ");
[myPoint print];
printf("\n");
[myPoint free];
return 0;
}
Then the compile errors from gcc look like this:
urban:Desktop alex$ gcc point.m -o point -l objc
point.m: In function ‘main’:
point.m:38: warning: ‘Point’ may not respond to ‘+alloc’
point.m:38: warning: (Messages without a matching method signature
point.m:38: warning: will be assumed to return ‘id’ and accept
point.m:38: warning: ‘...’ as arguments.)
point.m:40: error: ‘mypoint’ undeclared (first use in this function)
point.m:40: error: (Each undeclared identifier is reported only once
point.m:40: error: for each function it appears in.)
point.m:49: warning: ‘Point’ may not respond to ‘-free’
Where am I going wrong?
btw I'm going through "Programming in Objective-C" by Stephen Kochan if you wanted to know.

First the base class should be NSObject, not Object
the normal way to do the initialization is to write the alloc and init in the same statement. You would typically have an -(id)init; method in your class:
-(id)init
{
if ( ( self = [super init] ) )
{
; // additional initialization goes here
}
return self;
}
and
int main (int argc, char *argv[])
{
Point *myPoint = [[Point alloc] init];
Properties are better used, then you get the setter and getter automatically generated for you
instead of
#interface Point: Object
{
int xaxis;
int yaxis;
}
write
#interface Point : NSObject
{
}
#property int xaxis;
#property int yaxis;
then when you assign you can either write
[myPoint setXaxis:4]
or
myPoint.xaxis = 4;
when you release the object write release, not free
[myPoint release];
hth

You have warnings and an error. The warnings seem to suggest that Object, which you are subclassing, doesn't implement alloc, init or free. Normally, on an Apple platform, you'd subclass NSObject, which does implement these, but without knowing which platform you're on, it's not possible to advise the correct option.
Secondly, you had a typo, but that now seems to be corrected. This
point.m:40: error: ‘mypoint’ undeclared (first use in this function)
suggests that you had mypoint in your code, rather than myPoint.

You forgot to include the header Foundation.h:
#import <Foundation/Foundation.h>

Related

Assigning instance variance in method leads to segfault

Below is rather basic objective-c code. It contains one instance variable i. The problem is whenever I attempt to assign to it, it leads to segfault almost immediately following that assignment operation. Note: It does not segfault at the point of assignment. Usually it segfaults after the assignment and I try to invoke a method. ALSO, notice that this is not your standard mac/apple objective-c code. I'm using cygwin (Linux) plain vanilla version of objective-c. So I have to generate my own alloc and dealloc methods.
#import <objc/runtime.h>
#import <objc/Object.h>
#interface Test
{
int i;
}
+(id)alloc;
- (id) init;
- (int) load;
#end
#implementation Test
+(id)alloc
{
self = class_createInstance(self,0);
return self;
}
-(id)init
{
i = 0; // <------ if I comment out this line, there is no segfault
return self;
}
-(int) load
{
return i;
}
#end
int main(int argc, const char * argv[])
{
Test * test = [[Test alloc] init];
int v = [test load]; //segfaults here (NOTE: if I comment out this line, it does not segfault)
return 0;
}
What is causing the segfault?
I expect that, for a root class like yours, you need to explicitly declare the isa instance variable. Without it, your i is being interpreted as though it were the isa, which is why you get a crash.
So:
#interface Test
{
Class isa;
int i;
}
If you didn't intend to create a root class, you should probably inherit from Object or the like.

Invoking function getting stuck in a recursive loop and never comes

I am learning Objective-C inheritance and my program is getting lost in a recursive loop and won't come out. It gets hung up when calling a getter function.
I am using XCode version: Version 6.2 (6C101)
My program is given below
Vehicle.h
#ifndef exercise_2_Vehicle_h
#define exercise_2_Vehicle_h
#import <Foundation/Foundation.h>
#interface Vehicle : NSObject
#property float speed;
-(void) start;
-(void) stop;
-(void) park;
#end
#endif
Vehicle.m
#import "Vehicle.h"
#implementation Vehicle
-(void) setSpeed:(float)speed {
self.speed = speed;
}
-(float) speed {
return self.speed;
}
-(void) start {
NSLog(#"Starting the vehicle");
}
-(void) stop {
NSLog(#"Stopping the vehicle");
}
-(void) park {
NSLog(#"Parking the vehicle");
}
#end
Car.h
#ifndef exercise_2_Car_h
#define exercise_2_Car_h
#import "Vehicle.h"
#interface Car : Vehicle
#property (nonatomic) NSString* make;
-(Car*) initMake: (NSString*) make;
-(NSString*) make;
#end
#endif
Car.m
#import "Car.h"
#implementation Car
-(Car*) initMake:(NSString *)make {
self = [super init];
if (self) {
self.make = make;
}
return self;
}
-(NSString*) make {
return self.make;
}
#end
main.m
#import <Foundation/Foundation.h>
#import "Car.h"
#import "Vehicle.h"
int main(int argc, const char * argv[]) {
#autoreleasepool {
// insert code here...
Car* car = [[[Car alloc] init] initMake: #"Camry"];
//[car setSpeed:45];
NSLog(#"The model initialized is ");
[car make];
// [car speed];
}
return 0;
}
The issue you have is caused by creating the property for speed:
#property float speed;
and overriding setSpeed: method.
When you create #property compiler adds two methods for you, in your example setSpeed and speed.
This command:
self.speed = speed;
is equal to:
[self setSpeed: speed];
and inside setSpeed you have this command again which cause the loop. In your example you can remove both methods (setSpeed and speed) because compiler will add it for you. If you need it because you want to do some customisation you should use _speed instead self.speed.
_speed is backed variable added by compiler when using #property.
Change your method to:
-(void) setSpeed:(float)speed {
_speed = speed;
}
to remove the infinite loop.
In the
- (NSString*)make;
use
return _make
instead. The same with the speed.
If you return "self.x" in a getter method, then it's going to try and call the method again because you're requesting it on self. XCode will automatically convert the properties into variables that can be accessed with an '_' character, so you don't need to do any extra work.
You could also ignore our advice and remove both the "speed" and "make" getter methods you have made, because XCode automagically creates them for you.

Beginners confusion about objective c, assignment, properties etc

Sorry I couldn't be more descriptive in the title. I know C++ and C#, and a bit of Java, and I am doing some Objective C tutorials and can't explain what is going on here.
I will show you an example:
Here is the header/interface of the rectangle class:
#import <Foundation/Foundation.h>
#class XYPoint;
#interface Rectangle : NSObject
#property int width, height;
-(int) area;
-(int) perimeter;
-(void) setW:(int)w andH:(int)h;
-(XYPoint *) origin;
-(void) setOrigin:(XYPoint*)pt;
#end
Here is the implementation:
#import "Rectangle.h"
#implementation Rectangle{
XYPoint *origin;
}
#synthesize width, height;
-(void) setW:(int)w andH:(int)h
{
width = w;
height = h;
}
-(int) area{
return width*height;
}
-(int) perimeter{
return (width+height)*2;
}
-(XYPoint *) origin{
return origin;
}
-(void) setOrigin:(XYPoint*)pt{
origin = pt;
}
#end
And here is my main program:
#import <Foundation/Foundation.h>
#import "Rectangle.h"
#import "XYPoint.h"
int main(int argc, const char * argv[])
{
#autoreleasepool {
Rectangle *r = [[Rectangle alloc]init];
XYPoint *p = [[XYPoint alloc]init];
[p setX:100 andY:300];
[r setW:6 andH:8];
r.origin = p;
NSLog(#"Width and height is %i %i", r.width, r.height);
NSLog(#"Origin is at %i,%i", r.origin.x, r.origin.y);
NSLog(#"Arear and perimeter are %i and %i", [r area], [r perimeter]);
}
return 0;
}
The line r.origin = p; confuses me. Exactly which origin is being referred to here? The getter method as defined in the interface, or the actual member variable which is declared in the implementation?
Note origin is not a property.
To be honest I expected an error. The main program should only see the getter method, but it doesn't seem like a getter method that returns something could be on the left hand side of an assignment operator. Or is the system somehow mapping that syntax to a call to setOrigin?
I had expected the only possible way to set the origin would be something like [r setOrigin: p]
I can see how something like r.width = 5 would work, as width as declared in the header as being a property, but I cannot see how r.origin = p works.
Can someone explain what is going on here?
Thanks.
Your guess is right - that syntax, called dot notation, is translated into a call to [r setOrigin:p] by the compiler. The general idea is that just like most other languages, you have getters and setters for object properties; in Objective-C, these are usually written as:
- (type)variableName;
- (void)setVariableName:(type)aVariable;
So long as your own code conforms to these conventions, you can use dot notation to both get and set variables on your classes, and trust that your methods are called.
There's obviously a lot more going on behind the scenes, so I hope this brief explanation is enough for you for now. If you're interested, though, you can look further into:
Synthesizing properties and what actually happens - methods of the form shown above are generated by the compiler, along with instance variables for actual data storage
Key-value coding, which takes advantage of these principles and conventions
Special cases for some types (for example, BOOL variables' getters are usually written as -isVariableName rather than -variableName), and how you can manage them with #property attributes
Yes, property accessors invoked by the dot notation are automagically traansformed to method calls by the compiler; thus
variable = object.property;
is equivalent to
variable = [object property];
and
object.property = variable;
is equivalent to
[object setProperty:variable];

Extend iTunesApplication class with Categories

I am just learning how to use ScriptingBridges. I made a method that slowly fades the volume on iTunes, and would like to make it a category so I can do the following:
iTunesApplication* iTunes = [SBApplication applicationWithBundleIdentifier:#"com.apple.iTunes"];
[iTunes lowerVolume:50 speed:1];
I made another category for NSSpeechSynthesizer that works, but I can't get this one to. I keep getting the following build error:
"_OBJC_CLASS_$_iTunesApplication", referenced from:
l_OBJC_$_CATEGORY_iTunesApplication_$_iTunesApplicationAdditions in iTunesApplication.o
objc-class-ref-to-iTunesApplication in iTunesApplication.o
ld: symbol(s) not found
collect2: ld returned 1 exit status
Is there something special I can do to make it work since I can't include the symbols?
Thanks,
Ryan Pendleton
UPDATE:
I only found one solution, which is below. It involves MethodSwizzling, so I'm open to better answers, but for now it's all I have.
The solution I found was to use the Objective-C runtime API. I'm sure there's a better way to organize this, but here's how I did it:
Here are my .h and .m files for creating the category. Notice how lowerVolume is not an actual method, but a C function with the arguments id self, and SEL _CMD. You'll also notice a setupCategories function. We'll call that later.
// iTunes+Volume.h
#import <objc/runtime.h>
#import "iTunes.h"
void lowerVolume(id self, SEL _cmd, int dest, float speed);
void setupCategories();
#interface iTunesApplication (Volume)
- (void)lowerVolume:(int)dest speed:(float)speed;
#end
// iTunes+Volume.m
#import "iTunes+Volume.h"
void lowerVolume(id self, SEL _cmd, int dest, float speed)
{
NSLog(#"Lower Volume: %i, %f", dest, speed);
}
void setupCategories()
{
id object = [[SBApplication alloc] initWithBundleIdentifier:#"com.apple.iTunes"];
Class class = [object class];
[object release];
class_addMethod(class, #selector(lowerVolume:speed:), (IMP)lowerVolume, "#:if");
}
Now that I've made the functions, I need to actually add them to the scripting bridge class using the Objective-C runtime API. I'll do this in main.m to make sure that the methods are ready to be used when the run loop starts.
// main.m
#import <Cocoa/Cocoa.h>
#import "iTunes+Volume.h"
int main(int argc, char *argv[])
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
setupCategories();
return NSApplicationMain(argc, (const char **) argv);
[pool drain];
}
Now, I can use my method wherever I want as long as I include the header files:
- (void)mute
{
iTunesApplication* iTunes = [[SBApplication alloc] initWithBundleIdentifier:#"com.apple.iTunes"];
[iTunes lowerVolume:0 speed:1];
[iTunes release];
}
If any of this doesn't make sense, just tell me and I'll try to explain it better.
I think you need to include -framework ScriptingBridge to your gcc arguments. That got it to compile for me!
As noted above, you can't easily do a category on iTunesApplication because it doesn't exist at compile time, and also because the runtime class name is ITunesApplication (capital "I").
The best solution I've found is to do your category on the class that DOES exist, SBApplication. Here's the code I tested that works and does what the original example was trying to do:
// SBApplication+Extensions.h
#import ScriptingBridge;
#interface SBApplication (Extensions)
- (void)lowerVolume:(int)dest speed:(float)speed;
#end
// SBApplication+Extensions.m
#import "iTunes.h"
#import "SBApplication+Extensions.h"
#implementation SBApplication (Extensions)
- (void)lowerVolume:(int)dest speed:(float)speed
{
NSLog(#"Lower Volume: %i, %f", dest, speed);
}
#end
// Caller, say in AppDelegate
#import "SBApplication+Extensions.h"
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
iTunesApplication *iTunesApp =
[SBApplication applicationWithBundleIdentifier:#"com.apple.iTunes"];
[iTunesApp lowerVolume:4 speed:3.3f];
}

Class in ObjectiveC doesn't seem to recognize inherited messages

I'm learning ObjectiveC with "Programming in Objective C" by Stephen G Kochan and I'm having some difficulties with an example. It creates a simple Fraction class that inherits from Object. That's where I get into trouble, when I try to send messages that are understood by Object instead of Fraction, such as init, alloc or free (see code below):
// Fraction
#import <stdio.h>
#import <objc/Object.h> // base object
// #interface section
#interface Fraction: Object
{
int numerator;
int denominator;
}
- (void) print;
- (void) setNumerator: (int) n;
- (void) setDenominator: (int) d;
#end
// #implementation section
#implementation Fraction;
-(void) print
{
printf(" %i/%i ", numerator, denominator);
}
-(void) setNumerator: (int) n
{
numerator = n;
}
-(void) setDenominator: (int) d
{
denominator = d;
}
#end
// Program section
int main( int argc, char *argv[])
{
Fraction *myFraction;
// Create Instance of fraction
myFraction = [Fraction alloc];
myFraction = [Fraction init];
// Set fraction to 1/3
[myFraction setNumerator: 1];
[myFraction setDenominator: 3];
// Display the fraction
printf("The value of my fraction is: ");
[myFraction print];
printf("\n");
// Destroy the instance
[myFraction free];
return 0;
}
When I compile it:
gcc fraction.m -o fraction -l objc
I get the following warnings:
fraction.m: In function ‘main’:
fraction.m:47: warning: ‘Fraction’ may not respond to ‘+alloc’
fraction.m:47: warning: (Messages without a matching method signature
fraction.m:47: warning: will be assumed to return ‘id’ and accept
fraction.m:47: warning: ‘...’ as arguments.)
fraction.m:48: warning: ‘Fraction’ may not respond to ‘+init’
fraction.m:62: warning: ‘Fraction’ may not respond to ‘-free’
fernando#McFofo ~/code/learning objective c:: ./fraction
objc[1678]: Fraction: Does not recognize selector forward::
and the program, when run, complains about an illegal instruction…
Anybody knows what's going on?
Classes in Cocoa (the most popular Objective-C library, they are almost synonymous) tend to inherit from NSObject, the Cocoa root class. It is documented here.
There is also the NSObject protocol, implemented by NSProxy. It forms the basis of Cocoa's support for Distributed Objects. That said, we may be getting ahead of ourselves with that!
I also notice that you are trying to do the following:
Fraction *myFraction;
myFraction = [Fraction alloc];
myFraction = [Fraction init];
You are allocating memory for your object and then losing it by overwriting the pointer with another one. The standard practice is to do it on one line as follows:
Fraction *myFraction = [[Fraction alloc] init];
If you must do it one multiple lines, you must do the following:
Fraction *myFraction;
myFraction = [Fraction alloc];
myFraction = [myFraction init];
// myFraction is now ready to go!
I stumbled across a site that refers to what appears to be the book you're reading. The examples highlighted on the website inherit from NSObject and import <Foundation/NSObject.h>. Is there any particular reason you eschewed this and decided upon the Object class provided by the runtime?