views:

81

answers:

3

Hey guys, I have a protocol which defines a number of ObjC-2.0 properties, like so:

@protocol Repeatable <NSCoding>
@required
@property (nonatomic, retain) Date *startDate;
@property (nonatomic, retain) Date *endDate;
@end

I have another class that implements the protocol:

@interface AbstractRepeatable : NSObject <Repeatable>

And finally, in AbstractRepeatable, I am implementing a method defined by the protocol:

- (BOOL)isEqualToRepeatable:(Repeatable *)r {
    if (r.startDate != startDate) // Compiler error here
        return NO;
    return YES;
}

Bits and pieces have been excluded for example-sake, but when compiling, I receive the familiar "request for member 'startDate' in something not a structure or union" on the line noted above. The AbstractRepeatable obviously includes the Repeatable header, otherwise the protocol would not be visible, so I don't know which part I'm missing.

A: 

@property ... startDate only declares two methods -startDate and -setStartDate:.

You have to actually implement them. In a protocol, this cannot be done with instance variables.

mouviciel
Defining the properties in the protocol just ensures that the subclasses (or implementers, more specifically) synthesize the properties, and that you can pass in any Repeatable to a method, and have code that acts on those properties, assuming they exist in the actual object, which is an implementation of that protocol.
craig
I should clarify - Defining the properties in the protocol does not synthesize the variables. Any implementation of the protocol *must* synthesize (or provide dynamic accessor methods) to ensure that the property is "maintained."
craig
This is a good point. Have you tried to replace (r.startDate != startDate) by (r.startDate != [self startDate]) ?
mouviciel
The compiler error was on the r.startDate 'getter', not the startDate instance var. Answer chosen above. :)
craig
A: 

That should work and do what you expect. But it doesn't because the compiler is broken.

Sorry about that.

As a workaround, you'll need to declare the methods in your protocol:

@protocol Repeatable <NSCoding>
@required
@property (nonatomic, retain) Date *startDate;
- (Date *) startDate;
- (void) setStartDate: (Date *) aDate;

@property (nonatomic, retain) Date *endDate;
- (Date *) endDate;
- (void) setEndDate: (Date *) aDate;
@end

Skipping the @property, if you want. Once the compiler is fixed, the above still won't generate any warnings.

(Yes, you still can @synthesize the methods. I believe that @synthesize will work in this case. If it doesn't -- which it might not -- then you'll need to redeclare the properties in the class -- potentially in a class extension -- until the compiler is fixed. If this second issue proves to be the case, please file a bug via http://bugreport.apple.com/)

bbum
I believe the compiler is synthesizing the getters/setters. See the chosen answer for a good explanation.
craig
The compiler is synthesizing the getter/setters. That isn't the problem. The problem is that the compiler does not see @property() in class declarations as indicating that methods are required correctly. In some cases, it'll lead to incorrect code gen.
bbum
+6  A: 

In your isEqualToRepeatable: method you are treating Repeatable as a class, not a protocol. Try using the following. Everything should work fine after that. I tested it. (Fingers crossed that I won't look stupid.)

- (BOOL)isEqualToRepeatable:(id<Repeatable>)r {
    if (r.startDate != startDate) // Compiler error here
        return NO;
    return YES;
}
Cory Kilger
Man, good call! I'm embarrassed I didn't catch that. :D
craig
I'd be surprised that entirely fixes the issue. There is a serious bug in the existing compilers with @property() in protocols.
bbum