How to define and implement properties in protocol - objective-c

I want to define one protocol with few properties and need to use those properties in another NSObject subclass. Please give me link or example code. I need that to work with 10.5.
Thanks
PLEASE CHECK THE FOLLOWING SAMPLE CODE
#protocol MyProtocol
#property (nonatomic, readonly) id someObject;
#property (nonatomic, getter=isAlive) BOOL alive;
#end
#import "MyProtocol.h"
#interface MyCustomClass : NSObject <MyProtocol>{
}
#end
#import "MyCustomClass.h"
#implementation MyCustomClass
#synthesize someObject,alive;
/*
- (id)someObject {
return nil;
}
- (BOOL)isAlive {
return YES;
}
- (void)setAlive:(BOOL)aBOOL {
}
*/
#end
**Added:
Compling code with x86_64 architecture works fine. But error if i'll change the architecture to i386, then i am getting following warnings:
MyCustomClass.m:13: error: synthesized property 'someObject' must either be named the same as a compatible ivar or must explicitly name an ivar
error: synthesized property 'alive' must either be named the same as a compatible ivar or must explicitly name an ivar
I just want to know why it is working in x86_64 with #synthesize and not in i386.**

#property just says to the compiler that the class is expected to define the methods to match that property.
#protocol MyProtocol
#property (nonatomic, readonly) id someObject;
#property (nonatomic, getter=isAlive) BOOL alive;
#end
Anything implementing that protocol will now need to have
- (id)someObject;
- (BOOL)isAlive;
- (void)setAlive:(BOOL)aBOOL;

I think the things you're dealing with are primarily side effects of the introduction of Objective-C 2.0. It lets you do things like declare properties without also defining instance vars. But (as you have discovered), it is only x86_64 and post-10.5 compatible.

Related

"property has a previous declaration" error in class extension: bug or feature?

In Objective-C you can generally re-declare a readonly property as readwrite in a class extension like this:
#interface PubliclyImmutablePrivatelyMutableClass : NSObject
#property (readonly, nonatomic) SomeStateEnum someState;
#end
// In "PubliclyImmutablePrivatelyMutableClass+Private.h"
// or "PubliclyImmutablePrivatelyMutableClass.m"
#interface PubliclyImmutablePrivatelyMutableClass()
#property (readwrite, nonatomic) SomeStateEnum someState;
#end
// In "PubliclyImmutablePrivatelyMutableClass.m"
#implementation PubliclyImmutablePrivatelyMutableClass #end
If, however, I introduce a property in a class extension as readonly and try to re-declare it as readwrite in a second one, Xcode 10’s Clang gives me a compiler error:
#interface ClassWithPrivateImmutableInternallyMutableProperty : NSObject
// any public API
#end
// In "ClassWithPrivateImmutableInternallyMutableProperty+Private.h"
#interface ClassWithPrivateImmutableInternallyMutableProperty()
#property (readonly, nonatomic) SomePrivateStateEnum somePrivateState;
#end
// In "ClassWithPrivateImmutableInternallyMutableProperty.m"
#interface ClassWithPrivateImmutableInternallyMutableProperty()
#property (readwrite, nonatomic) SomePrivateStateEnum somePrivateState; // error: property has a previous declaration
#end
#implementation ClassWithPrivateImmutableInternallyMutableProperty
// other API
#end
Now I wonder:
Is the compiler error a bug/regression in Clang or a deliberate feature?
If it’s a bug, is there another workaround than manually implementing the setter?
I believe that this is correct behavior from the compiler.
In the second example you are using two class continuation categories with the same name () to declare the same property on two occasions. It is effectively the same as declaring the same property name twice in the same extension.
Note that this differs from the first example, in which the property is declared first in the header and then re-declared in a single class continuation category named ().
If I am right, then the answer is to mark the '+private' class extension with a name like (Private) instead of ():
#interface ClassWithPrivateImmutableInternallyMutableProperty(Private)
And also if you have any implementation for the private extension:
#implementation ClassWithPrivateImmutableInternallyMutableProperty(Private)
I hope that helps!

XCode: Unrecognized selector sent to instance

I am getting the following error:
"-[Order items]: unrecognized selector sent to instance 0x6b5f240"
I do have a class called Order, which looks like this:
Order.h
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#class OrderItem;
#interface Order : NSManagedObject {
#private
}
#property (nonatomic, retain) NSNumber * orderID;
#property (nonatomic, retain) NSDate * date;
#property (nonatomic, retain) NSNumber * orderCode;
#property (nonatomic, retain) NSSet* items;
#end
Order.m
#import "Order.h"
#import "OrderItem.h"
#implementation Order
#dynamic orderID;
#dynamic date;
#dynamic orderCode;
#dynamic items;
...
It doesn't extend any sort of class which has an "items" method, if I'm reading that correctly?
Is there any other reason I would be getting such an error. To add to the madness, this project is copied directly from a previous project, with some minor edits. I've done text comparisons on every single class in both projects and there are no differences other than the cosmetic changes I've made.
#dynamic items tells the compiler that you will be providing the methods for items.
Since this was working in a previous project, it must have had the following method somewhere in the .m file:
- (NSSet *)items {
// Appropriate code
}
If you do not want to provide your own custom getter like this, then change #dynamic items to #synthesize items and the compiler will generate one for you.
For more details, see the Declared Properties section of The Objective-C Programming Language provided by Apple here: https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocProperties.html
EDIT
While everything above still applies to a normal object (and may still apply here), I just noticed that this is a subclass of NSManagedObject.
In your old data model there was probably a relationship called items and therefore the appropriate methods were provided by NSManagedObject and #dynamic was appropriate to prevent compiler warnings.
If in your new data model there is no relationship named items, then the methods will not be generated and it will cause the problem that you are getting here.

Syntax for resolving incompatible property type on inherited delegate

Some code I inherited has an annoying warning. It declares a protocol and then uses that to specify the delegate
#protocol MyTextFieldDelegate;
#interface MyTextField: UITextField
#property (nonatomic, assign) id<MyTextFieldDelegate> delegate;
#end
#protocol MyTextFieldDelegate <UITextFieldDelegate>
#optional
- (void)myTextFieldSomethingHappened:(MyTextField *)textField;
#end
Classes which use myTextField implement the MyTextFieldDelegate and are called it with this code:
if ([delegate respondsToSelector:#selector(myTextFieldSomethingHappened:)])
{
[delegate myTextFieldSomethingHappened:self];
}
This works, but creates the (legitimate) warning: warning: property type 'id' is incompatible with type 'id' inherited from 'UITextField'
Here are the solutions I've come up with:
Remove the property. This works but I get the warning '-myTextFieldSomethingHappened:' not found in protocol(s)
Drop the protocol entirely. No warnings, but you also lose the semantic warnings if you forget to implement the protocol in the delegate.
Is there a way to define the delegate property such that the compiler is happy?
try:
#property (nonatomic, assign) id<UITextFieldDelegate,MyTextFieldDelegate> delegate;
UITextField has also got property named delegate, but it has another type. Just rename your delegate property to something else.
Found the answer in UITableView.h.
The UIScrollView has property name delegate, and the UITableView has the same name property.
#protocol UITableViewDelegate<NSObject, UIScrollViewDelegate>
// Your code
......
#end
The original problem is that there is no information about MyTextFieldDelegate's inheritance during declaration of delegate property. It's caused by forward declaration of protocol (#protocol MyTextFieldDelegate;).
I've faced the same problem but with protocol declaration in the other .h file. In my case solution was just to #import appropriate header.
In your case you just need to swap the order of declaration:
#class MyTextField;
#protocol MyTextFieldDelegate <UITextFieldDelegate>
#optional
- (void)myTextFieldSomethingHappened:(MyTextField *)textField;
#end
#interface MyTextField : UITextField
#property (nonatomic, assign) id <MyTextFieldDelegate> delegate;
#end

Can I remove the #private generated by Core Data?

What is the #private for in the file generated by Core Data below? I know what #private means in Objective-C, but there are not instance variables listed after it, so can't I just take it out?
//
// Event.h
//
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#interface Event : NSManagedObject {
#private
}
#property (nonatomic, retain) NSDate * timestamp;
#end
//
// Event.m
//
#import "Event.h"
#implementation Event
#dynamic id;
#end
You can safely take it out, it won't change the semantics of your class. If you're not statisfied with what XCode generates for you (though it's a reasonable default), I'd suggest you take a look at https://github.com/rentzsch/mogenerator.
You can, but it doesn't hurt. If you generate the model again it will just put it back.
Xcode now defaults to generating classes with #private for instance variables, which you are supposed to declare in case you need them. You can safely remove that #private since, as you’ve already noticed, there are no instance variables. In fact, that class declaration is equivalent to
#interface Event : NSManagedObject
#property (nonatomic, retain) NSDate * timestamp;
#end

Overriding properties which conform to protocols

I seem to be getting a new error when using LLVM Compiler 2.0, which I haven't had before.
I have a protocol called DTGridViewDelegate defined as:
#protocol DTGridViewDelegate <UIScrollViewDelegate>
I have a property called delegate on DTGridView (a subclass of UIScrollView, which itself has a delegate property). This is defined as:
#property (nonatomic, assign) IBOutlet id<DTGridViewDelegate> delegate;
Now the message I get is:
DTGridView.h:116:63: error: property type 'id<DTGridViewDelegate>' is incompatible with type 'id<UIScrollViewDelegate>' inherited from 'UIScrollView'
Because I had said that the DTGridViewDelegate conforms to UIScrollViewDelegate, I thought that this would be ok to override this property in this way, and indeed this is the first compiler to suggest there is a problem.
I have fixed the error by declaring the property as such:
#property (nonatomic, assign) IBOutlet id<DTGridViewDelegate, UIScrollViewDelegate> delegate;
I am wondering whether this is a compiler issue?
Your setup looks like the same one used in the case of UITableView inheriting from UIScrollView. The UITableViewDelegate protocol inherits from UIScrollViewDelegate protocol.
I set up the following which compiles fine:
// .h
#protocol ParentClassDelegate
-(NSString *) aDelegateMethod;
#end
#interface ParentClass : NSObject {
id delegate;
}
#property(nonatomic, assign) IBOutlet id <ParentClassDelegate> delegate;
#end
//.m
#implementation ParentClass
#synthesize delegate;
-(id) delegate{
return #"Parent delegate";
}//-------------------------------------(id) delegate------------------------------------
-(void) setDelegate:(id)someObj{
delegate=someObj;
}//-------------------------------------(id) setDelegate------------------------------------
#end
//.h
#protocol ChildClassDelegate <ParentClassDelegate>
-(NSArray *) anotherDelegateMethod;
#end
#interface ChildClass : ParentClass{
}
#property(nonatomic, retain) IBOutlet id <ChildClassDelegate> delegate;
#end
//.m
#implementation ChildClass
//#synthesize delegate;
-(id) delegate{
return #"childDelegate";
}//-------------------------------------(id) delegate------------------------------------
-(void) setDelegate:(id)someObj{
delegate=someObj;
}//-------------------------------------(id) setDelegate------------------------------------
#end
Not sure what is causing your problem. I would note that in the header the UITableViewDelegate protocol looks like:
#protocol UITableViewDelegate<NSObject, UIScrollViewDelegate>
... so maybe the compiler likes things more explicit sometimes.
I would suggest a clean and build. That solves a lot of problems.
Since there isn't a formal Objective-C language specification, it's impossible to say whether the compiler is behaving properly. All we can say is that Apple's gcc doesn't seem to have a problem with the above scenario, though it's conceptually unsound as it can break Liskov substitution, since delegate is covariant from UIScrollView to DTGridView (though covariance is just as much a problem). What would happen if you passed a DTGridView to code expecting a UIScrollView, which then proceeded to set delegate to an object that conformed to UIScrollViewDelegate but not DTGridViewDelegate?