I'm new to Objective C. I am trying to define Constants which have behavior associated with them. So far I have done -
@interface Direction : NSObject {
NSString *displayName;
}
-(id)initWithDisplayName:(NSString *)aName;
-(id)left; // returns West when North
-(id)right; // return East when North
@end
@implementation Direction
-(id)initWithDisplayName:(NSString *)aName
{
if(self = [super init])
{
displayName = aName;
}
return self;
}
-(id)left {};
-(id)right {};
@end
Direction* North = [Direction initWithDisplayName:@"North"]; // err开发者_高级运维or - initializer element is not constant.
This approach results in the indicated error. Is there a better way of doing this in Objective C.
Short version
Store a geometric representation of your direction (using a vector or a simple angle) and compute the direction names dynamically. To get left and right directions, copy and rotate your vector by ±½π or ±90°, creating a new direction and returning that. If you only have 90° turns, you can use a point { 0, 1 }, and switch the directions, optionally negating them as you do so. ({ 0, 1 } is North; { 1, 0 } is East, { -1, -0 } is West, { -0, -1 } is South, so if you use this approach you'll have to have some extra code to determine when to negate, and when not to.)
Long version
The issue is that variables outside of functions are initialized at compile time. Naturally, this means that you cannot call functions to initialize them. To do something like this, you need to do the following (although you shouldn't, see below):
// Direction.h
extern Direction *north;
// Direction.m
Direction *north = nil;
+ (void)initialize {
north = [[Direction alloc] initWithDisplayName:@"North"];
}
This is, however, an almost entirely terrible way of going about things. What you want to do is as follows:
// Direction.h
@interface Direction (ConstantDirections)
+ (Direction *)north;
// etc...
@end
// Direction.m
+ (Direction *)north {
static Direction *northDirection = nil;
if (!northDirection) {
// assume that ConstantDirection is a subclass of
// Direction that prevents releases etc.
northDirection = [[ConstantDirection alloc] initWithDisplayName:@"North"];
}
return northDirection.
}
This will prevent other users of the direction from doing evil things (mostly).
PS: North is a really weird word, especially noticeable when you type it a lot. :P
Edit: Some clarification on the use of cardinal directions as separate objects.
In practice, your direction class will probably look something like this:
@interface Direction : NSObject <NSCopying,NSCoding> {
NSString *displayName;
NSPoint offset;
// XOR
NSInteger northOffset;
NSInteger eastOffset;
// XOR
CGFloat theta;
}
@property (copy) NSString *displayName;
@property (readonly) NSPoint offset;
+ (Direction *)north;
+ (Direction *)east;
+ (Direction *)west;
+ (Direction *)south;
- (id)initWithOffset:(NSPoint)offset;
@end
For the purpose of this discussion, we'll assume the first.
In this case, your Direction.m file would contain, among other things, the following.
@implementation Direction
+ (Direction *)north {
static Direction *northDirection = nil;
if (!northDirection) {
// assume that ConstantDirection is a subclass of
// Direction that prevents releases etc.
northDirection = [[ConstantDirection alloc] initWithOffset:NSMakePoint(0,DIRECTION_LARGE_OFFSET)];
northDirection.displayName = @"North";
}
return northDirection.
}
@end
精彩评论