In the implementation section for Rectangle when I left out #import "XYpoint" it still worked the same for me. Is putting #import "XYpoint" good practice or does it affect the program?
#import <Foundation/Foundation.h>
#interface XYPoint : NSObject
#property int x, y;
-(void) setX: (int) xVar andY: (int) yVar;
#end
#import "XYpoint.h"
#implementation XYPoint
#synthesize x, y;
-(void) setX:(int)xVar andY:(int)yVar {
x = xVar;
y = yVar;
}
#end
#import <Foundation/Foundation.h>
#class XYPoint;
#interface Rectangle: NSObject
-(XYPoint *) origin;
-(void) setOrigin: (XYPoint *) pt;
#end
#import "Rectangle.h"
#import "XYpoint.h"
#implementation Rectangle {
XYPoint *origin;
}
-(void) setOrigin:(XYPoint *)pt {
origin = pt;
}
-(XYPoint *) origin {
return origin;
}
#end
#import "XYpoint.h"
#import "Rectangle.h"
int main (int argc, char * argv[]) {
#autoreleasepool {
Rectangle *rect = [[Rectangle alloc] init];
XYPoint *pointy = [[XYPoint alloc] init];
[pointy setX:5 andY:2];
rect.origin = pointy;
NSLog(#"Origin %i %i", rect.origin.x, rect.origin.y);
}
return 0;
}
Your implementation of Rectangle doesn't use any of the specifics of the XYPoint class. It just treats it as a generic pointer and never messages it or dereferences it. Therefore, the forward declaration (the #class statement in the Rectangle interface file) is sufficient. Importing the header doesn't make any difference to the compiled program.
It is quite likely that your Rectangle class will eventually evolve to care about the interface of the XYPoint class. When it does, it will need to import that interface declaration. The compiler will warn you if you neglect to import it.
That said, there's little reason not to import it.
Related
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.
#interface rectangle: NSObject
#property int width, height;
{
-(int) area;
-(int) perimeter;
-(void) setWidth: (int) w andHeight: (int) h;
}
#end
#implementation rectangle
#synthesize width, height;
...
...
#end
I made a square subclass of rectangle
#interface square: rectangle
-(void) setSide: (int) s;
-(int) side;
#end
#implementation square
-(void) setSide: (int) s
{
[self setWidth: s andHeight: s];
}
-(int) side
{
return self.width;
}
#end
My main question is this: Why can't I just do this
return width;
when I want to get the side of my square object.
I thought
#property int width, height;
is just a simplified from
#interface rectangle: NSObject
{
int width;
int height;
}
//getter/setter methods
...
#end
and in the book, if an instance variable is declared in #interface, it is inherited by its subclass. But, apparently,
return width;
doesn't seem to work. Why is this happening?
The problem is that synthesize of properties is part of the implementation, not the interface. The subclass can only rely on the interface.
For example, the #synthesize could have specified a different instance variable name (e.g. #synthesize width = _my_funky_width;) and the subclass would have no way of knowing what the actual instance variable was.
I have an xcode project which has 2 classes - Stem & Player, I'm trying to ensure my code is solid from an object-orientated perspective, I believe it's acceptable programming practice for my Player Class to access information in my Stem Class.
I want to access indices from an array in stem - I can do this from my view controller using
stem.index[i]
when I try to do this from player I'm not allowed as stem is undeclared. I've tried importing Stem.h into my Player.m file & declaring stem in player (similar to how one does this in the view controller), only to get errors (expected specifier-qualifier-list before 'Stem').
What's the correct way to do this? Please excuse any loose use of terminology as I'm relatively new to this. Thanks in advance :)
Edit
Here is some code that might shed some light on things, In the viewController I declare stem & player
#import <UIKit/UIKit.h>
#import <AVFoundation/AVAudioPlayer.h>
#import "Stem.h"
#import "Player.h"
#interface TestApp_v1ViewController : UIViewController {
Stem *stem;
Player *player;
I alloc & init my two objects stem & player in viewController.m
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"Init Successful");
[self loadMOV];
[self setupInterface];
stem = [[Stem alloc] init];
player = [[Player alloc] init];
}
I then move to Stem.h where I declare stem again (so that stem is accessible to player when stem.h is imported to player.h - as per glogic's comment)
#import <Foundation/Foundation.h>
#interface Stem : NSObject {
int *index;
int numberOfStems;
Stem *stem;
}
#property(nonatomic,readwrite) int *index;
#property(nonatomic, retain) Stem *stem;
Player.h looks like this:
// Player.h
#import <Foundation/Foundation.h>
#import "Stem.h"
#interface Player : NSObject {
NSMutableArray *player1;
}
#property(nonatomic,retain) NSMutableArray *player1;
-(void) playAudio;
#end
Finally in Player.m I try to access the index array
#import "Player.h"
#implementation Player
#synthesize player1;
-(void)playAudio {
NSLog(#"play audio called");
NSLog(#"index[0] is: %i", stem.index[0]);
}
#end
I'm still being told that stem is undeclared, any ideas?
Edit #2 - adding bare-bones program
I hope this is considered ok but I've decided to post my program (pared down to the bare essentials). I think it may be the only way that the issue might be figured out - since a lot is going on across classes. I've been trying to get this to work for hours now arrrgh...
I alloc'd & initialised my stem & player objects in the viewController - i thought this was the best way to go about this, but maybe there is a better method.
//Part (i)
// TestApp_v1ViewController.h
#import <UIKit/UIKit.h>
#import <AVFoundation/AVAudioPlayer.h>
#import "Stem.h"
#import "Player.h"
#interface TestApp_v1ViewController : UIViewController {
Stem *stem;
Player *player;
}
#property(nonatomic, retain) Stem *stem;
#property(nonatomic, retain) Player *player;
#end
//Part (ii)
// TestApp_v1ViewController.m
#import "TestApp_v1ViewController.h"
#import <MediaPlayer/MediaPlayer.h>
#implementation TestApp_v1ViewController
#synthesize stem;
#synthesize player;
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"Init Successful");
stem = [[Stem alloc] init];
[stem loadURLs];
player = [[Player alloc] init];
[player playAudio];
int index = stem.value;
NSLog(#"r is: %i", index); //checking to see if I can get a value from the index array - this works fine, so 'value' can be accessed from the viewController
}
Here I declare an int array & the int "value" which I want to access later from my player (this is what turns out to be the problem)
//Part (iii)
// Stem.h
#import <Foundation/Foundation.h>
#interface Stem : NSObject {
NSMutableArray *urlArray;
int *index;
int value;
int numberOfStems;
Stem *stem;
}
- (void)loadURLs;
- (void)randomiseAudioForInitialPlay;
#property(nonatomic,retain) NSMutableArray *urlArray;
#property(nonatomic,readwrite) int *index;
#property(nonatomic,readwrite) int numberOfStems;
#property(nonatomic,readwrite) int value;
#property(nonatomic, retain) Stem *stem;
#end
//Part (iv)
// Stem.m
#include <stdio.h>
#import "Stem.h"
#implementation Stem
#synthesize numberOfStems;
#synthesize urlArray;
#synthesize index;
#synthesize stem;
#synthesize value;
- (void)loadURLs
{
NSLog(#"Loading URLs");
numberOfStems = 20;
urlArray = [[NSMutableArray alloc] init];
for ( int i = 1; i <= numberOfStems; i++ ) {
NSString *soundName = [NSString stringWithFormat:#"stem-%i", i];
NSString *soundPath = [[NSBundle mainBundle] pathForResource:soundName ofType:#"mp3"];
NSURL *soundFile = [[NSURL alloc] initFileURLWithPath:soundPath];
[urlArray addObject:soundFile];
[soundFile release];
}
[self randomiseAudioForInitialPlay];
}
- (void)randomiseAudioForInitialPlay
{
index = malloc(numberOfStems*sizeof(int));
for (int i = 0; i < numberOfStems; i++)
{
index[i] = i;
}
for (int i = (numberOfStems - 1); i > 0; i--)
{
int randomIndex = arc4random() % i;
int tmp = index[i];
index[i] = index[randomIndex];
index[randomIndex] = tmp;
}
value = self.index[10]; //this is what needs to be accessed later, from player
NSLog(#"value at index 10 is:%i", value);
}
#end
Here I include 'Stem.h' since player will require stem in order to return stem.value
//Part (v)
// Player.h
#import <Foundation/Foundation.h>
#import "Stem.h"
#interface Player : NSObject {
Player *player;
}
#property(nonatomic, retain) Stem *stem;
#property(nonatomic, retain) Player *player;
-(void) playAudio;
#end
This is where things go wrong, my NSLog statement tells me that value is 0, even though I can see that it's (e.g.) 14 in stem. The compiler gives no errors either.
//Part (vi)
// Player.m
#import "Player.h"
#implementation Player
#synthesize player;
#synthesize stem;
-(void)playAudio {
int value = stem.value;
NSLog(#"value is:%i", value );
}
#end
This is my first proper go at an object-orientated project so I'm learning on the job, any suggestions as to why I can't access stem.value in my Player class?
My ideas on how the various objects in such a program interact with one another (& the correct syntax) are still hazy so please forgive me for crazy n00b errors in my code :)
where are you declaring stem within player? if you are declaring it within the player.h then you will need the import of stem.h within the player.h and not player.m.
edit: yeah its still undeclared because you have stem declared in the view controller not the player. hmm seems to be afew things out of whack here. it really depends on how your code will actually work
#import Stem.h
#interface Player : NSObject {
NSMutableArray *player1;
}
#property(nonatomic,retain) NSMutableArray *player1;
#property(nonatomic,retain) Stem *stem;
-(void) playAudio;
#end
#
import "Player.h"
#implementation Player
#synthesize player1, stem = _stem;
-(void)playAudio {
NSLog(#"play audio called");
NSLog(#"index[0] is: %i", _stem.index[0]);//stem.index[0] will be a problem here as its not a c array
}
#end
and then in ur controller
player.stem = stem;
and im not sure why ur creating a stem pointer within the stem class.
#interface Stem : NSObject {
int *index;
int numberOfStems;
}
#property(nonatomic,readwrite) int *index;
and if its an array of stems you want then create that in the controller
edit : after you have the lines
player = [[Player alloc] init];
[player playAudio];
add
player.stem = stem;
you have to assign the pointer within player to the stem that you created in the view controller
The best way is to create a method in the Stem class like:
value = [stem valueAtIndex:i];
That way there is less coupling and the way the values are held in the Stem class is not exposed and can be changed later if necessary without preaching the access calls.
I am following along with a series of web tutorials relating to Objective-C and am now getting a "Accessing unknown origin getter method" error when i try to build my program (origin being a member of a Rectangle class that I created).
Here is my class titled PointXY:
#import <Foundation/Foundation.h>
#interface PointXY : NSObject
{
int x;
int y;
}
//Setters and Getters
#property int x;
#property int y;
//Methods
- (void) setXY : (int) xCO : (int) yCO;
#end
I then define a rectangle class, that has a member that is of type PointXY:
#import <Foundation/Foundation.h>
#class PointXY;
#interface rectangle : NSObject
{
float width;
float height;
PointXY * origin;
}
//Setters and Getters
#property float width, height;
//Instance Methods
- (float) getArea;
- (float) getPerimeter;
//We already have setters and getters defined for width
//and height. The below method is for illustration purposes
- (void) setHW: (float) h : (float) w;
//Methods to set and get origin values
- (PointXY *) getOrigin; //Returns a PointXY object
- (void) setOrigin : (PointXY *) point;
#end
I get the error in main, if i try to access the x or y property of my origin member via my NSLog statement:
#import <Foundation/Foundation.h>
#import "rectangle.h"
#import "PointXY.h"
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
//Create an object
rectangle * myRectangle = [[rectangle alloc]init];
PointXY * rOrigin = [[PointXY alloc]init];
[rOrigin setXY:100 :100];
myRectangle.origin = rOrigin;
NSLog(#"The origin for the rectangle is %i, %i", myRectangle.origin.x, myRectangle.origin.y);
[pool drain];
return 0;
}
I understand that one cannot access the members without either explicitly defining a synthesized accessor or by creating a method to do just that and was surprised to see the author of the tutorial do the above with no issue.
Is the above even possible? Can I access myRectangle.origin.x without origin being synthesized in myRectangle or do I have something set up incorrectly.
Thanks for your time.
Origin is an instance variable you need to create an #property for it and synthesize it as you already know.
//Setters and Getters
#property float width, height;
#property PointXY *origin;
But without the property you could access the origin by doing this rectangle->origin but that defeats the purpose of encapsulation.
Edit- origin will need to be defined as #public or #package
I'm trying to work my way through an Objective-C tutorial. In the book there is this example:
#interface
{
int width;
int height;
XYPoint *origin;
}
#property int width, height;
I thought, "hey there's no getter/setter for the XYPoint object. The code does work though." Now i'm going maybe to answer my own question :).
I thinks its because "origin" is a pointer already, and whats happening under the hood with "width" and "height", is that there is going te be created a pointer to them..
Am i right, or am i talking BS :) ??
I just dont get it. here's main:
#import "Rectangle.h"
#import "XYPoint.h"
int main (int argc, char *argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
Rectangle *myRect = [[Rectangle alloc] init];
XYPoint *myPoint = [[XYPoint alloc] init];
[myPoint setX: 100 andY: 200];
[myRect setWidth: 5 andHeight: 8];
myRect.origin = myPoint;
NSLog (#"Rectangle w = %i, h = %i",
myRect.width, myRect.height);
NSLog (#"Origin at (%i, %i)",
myRect.origin.x, myRect.origin.y);
NSLog (#"Area = %i, Perimeter = %i",
[myRect area], [myRect perimeter]);
[myRect release];
[myPoint release];
[pool drain];
return 0;
}
And here's the Rectangle object:
#import "Rectangle.h"
#import "XYPoint.h"
#implementation Rectangle
#synthesize width, height;
-(void) setWidth: (int) w andHeight: (int) h
{
width = w;
height = h;
}
- (void) setOrigin: (XYPoint *) pt
{
origin = pt;
}
-(int) area
{
return width * height;
}
-(int) perimeter
{
return (width + height) * 2;
}
-(XYPoint *) origin
{
return origin;
}
#end
What i dont understand is this line in main: myRect.origin = myPoint; I did not make a setter for it..
BTW thanks for your fast reply's
What i dont understand is this line in main: myRect.origin = myPoint; I did not make a setter for it..
There is both a getter and a setter (collectively referred to as accessors) created for origin in the Rectangle class. If you have a look in the implementation for Rectangle, this is the getter:
-(XYPoint *) origin
{
return origin;
}
and this is the setter:
- (void) setOrigin: (XYPoint *) pt
{
origin = pt;
}
And as of Objective-C 2.0 calling:
myRect.origin = myPoint;
is equivalent to:
[myRect setOrigin:myPoint];
Declaring getters and setters using #property (and then implementing them using #synthesize) is only one way of declaring and creating accessors, and is there for a convenience if you have lots of properties to declare in the class interface. As Schildmeijer said, #property int width is equivalent to declaring two methods:
- (int)width;
- (void)setWidth:(int)newWidth;
Due to the dynamically-bound nature of Objective-C method calls, you don't even have to declare the getter and setter methods in the interface, although it is generally best practice to do so if you are advertising them as publicly available to other classes.
You can think of a property declaration as being equivalent to declaring two accessor methods. Thus
#property int width;
is equivalent to:
- (int)width;
- (void)setWidth:(int)newWidth;
//Rectangle.h
#import <Foundation/Foundation.h>
#interface Rectangle : NSObject
#property int Width;
#property int Height;
-(int)Area;
#end
//Rectangle.m
#import "Rectangle.h"
#implementation Rectangle
#synthesize Width;/*Will create value Width , Setter called"setWidth" and Getter called "Width"*/
#synthesize Height;/*Will create value Height , Setter called"setHeight" and Getter called "Height"*/
-(int)Area
{
return Width*Height;
}
#end
// main.m
#import <Cocoa/Cocoa.h>
#import "Rectangle.h"
int main(int argc, const char * argv[])
{
Rectangle *myRectangle = [Rectangle new];
myRectangle.Width=3;
myRectangle.Height=5;
printf("Area = %d\n",[myRectangle Area]);
//Or
[myRectangle setWidth:5];
[myRectangle setHeight:6];
printf("Area = %d\n",[myRectangle Area]);
}
If you want to make Getter only or rename getter and setter
• readonly
• getter = newGetterName
• setter = new SetterName
example
//Rectangle.h
#import <Foundation/Foundation.h>
#interface Rectangle : NSObject
#property (getter = getWidth) int Width;
#property (readonly) int Height;
#end
You don't say what code is working, or what your expectations are for "working".
The above interface will create simple accessor methods for width and height that can be called from other objects as [object setWidth:1]; or object.width = 1; - these two are analogous.
Origin is some other object type and is a pointer, yes. But you would still want to declare a property for it to generate accessor methods.
Getters and setters are mostly useful if you need to access an instance variable from another class or you're using bindings to get/set them. So my guess would be that you need this functionality for the width and height but not for the origin. Note that the getters/setters do not make pointers out of the integers as you stated might be the reason. Ints are ints and getters/setters do not change that.