I want to create a custom delegate for NSWindow.
CustomWindow is subclassed to get notified about NSWindowDelegate events.
Now I want to create delegate for this CustomWindow.
I tried following code:
CustomWindow.h
#class CustomWindow;
#protocol CustomWindowDelegate
- (void)method1:(CustomWindow *)sender userInfo:(NSMutableDictionary*) userInfo;
- (void)method2:(CustomWindow *)sender event:(NSEvent *)theEvent;
- (void)method3:(CustomWindow *)sender;
#end
#interface CustomWindow : NSWindow <NSWindowDelegate>
#property (nonatomic) id <CustomWindowDelegate> delegate;
#end
mainDocument.h
#import "CustomWindow.h"
#interface mainDocument : NSDocument
#property (assign) IBOutlet CustomWindow *mainWindow;
#end
mainDocument.m
#import "mainDocument.h"
#implementation mainDocument
- (void)method1:(CustomWindow *)sender userInfo:(NSMutableDictionary*) userInfo
{
...
...
}
- (void)method2:(CustomWindow *)sender event:(NSEvent *)theEvent
{
...
...
}
- (void)method3:(CustomWindow *)sender
{
...
...
}
#end
Its working as per expectations however its giving following warnings:
'retain (or strong)' attribute on property 'delegate' does not match the property inherited from 'NSWindow'
'atomic' attribute on property 'delegate' does not match the property inherited from 'NSWindow'
Property type 'id' is incompatible with type 'id _Nullable' inherited from 'NSWindow'
Auto property synthesis will not synthesize property 'delegate'; it will be implemented by its superclass, use #dynamic to acknowledge intention
How can I get rid of these warnings ?
Any helps are greatly appreciated.
NSWindow already has a delegate property and it uses its delegate for different purposes than you're using yours for. The errors are conflicts between your declaration of your delegate property with the declaration of the inherited property.
The simplest solution is for you to rename your property to customDelegate or something like that. Also, the general convention is for delegate properties to be weak, so you should probably declare yours as weak, too.
In general, one could combine a new delegate protocol with NSWindowDelegate and re-use the existing delegate property. In your case, though, since you've declared CustomWindow to conform to NSWindowDelegate, it seems like you're planning on making the window object its own delegate. So, that would conflict with this approach. But, for completeness, if you were going to do that you'd declare your protocol as an extension of NSWindowDelegate:
#protocol CustomWindowDelegate <NSWindowDelegate>
Your property declaration would have to have the same attributes as NSWindow's declaration of its delegate property. So:
#property (nullable, assign) id<CustomWindowDelegate> delegate;
Finally, since you're relying on NSWindow to actually provide the storage and accessor methods of the property, you'd fix the last warning by putting this in the #implementation of CustomWindow:
#dynamic delegate;
Related
I created a NSManagedObject called MapState. I then created a category for it to call some methods and store some extra variables.
.h
#import "MapStateDB.h"
#protocol MapStateDelegate;
#interface MapStateDB (MapState)
#property (weak, nonatomic) id <MapStateDelegate> delegate;
-(void)selectedSceneObject:(SceneObject *)sceneObject;
-(void)removeDisplayedScene;
#end
#protocol MapStateDelegate <NSObject>
-(void)displayScene:(SceneDB *)scene inState:(NSString *)state;
-(void)removeScene:(SceneDB *)scene;
#end
In the .m:
#dynamic delegate;
-(void)setDelegate:(id<MapStateDelegate>)delegate {
}
How do I do the setter? Normally it would just be:
-(void)setDelegate:(id<MapStateDelegate>)delegate {
_delegate = delegate;
}
But since the variable is #dynamic instead of #synthesize, no _delegate is created. And #synthesize creates an error.
How should I be handling this?
Using #dynamic implies that the appropriate accessors will be created at run time. NSManagedObject does that for attributes of entities in the data model, but not for properties you declare. You could do this with some ObjC runtime wizardry (the APIs all exist, and are supported, so it's not what might be called a hack) but it's not trivial. (Using #dynamic would be fine if delegate were a transient property on the entity, but that would mean that the delegate would have to be one of the types supported by Core Data instead of any class implementing the protocol).
But there's hope! If you're using Xcode 7+ to generate NSManagedObject subclasses, it's safe to add your own properties in the subclass without fear of them being overwritten. You'd make the delegate property work by adding a #synthesize for it and then not adding your own setter. You don't have to provide one unless you need to do more than just set the property value.
If you do need a custom setter, modify the #synthesize to be something like
#synthesize delegate = _delegate;
(you don't have to use _delegate here, any valid name is fine)
Then add a setter like the one in your question that assigns to the synthesized name.
I got that error:
/business/Dropbox/badgers/BadgerNew/BGProfileView.m:56:17: Auto property synthesis will not synthesize property declared in a protocol
I am aware that auto property synthesis will not synthesize property declared in a protocol
So I synthesize that my self.
This is the protocol:
#protocol BGIhaveNavigationController <NSObject>
#property (readonly)UINavigationController * navigationController;//This is the problematic property
#end
#protocol BGCommonProtocol <NSObject>
#end
As for the implementation
#interface BGProfileView : UIViewController
#end
is a UIViewController and as we know UIViewController has a navigationController property. So what's wrong?
Things get problematic when I use this:
#interface BGProfileView () <BGReviewsTableDelegateProtocol>
BGReviewsTableDelegateProtocol protocol inherits BGIhaveNavigationController protocol
I can remove the warning by adding:
-(UINavigationController *) navigationController
{
return self.navigationController;
}
But that's absurd. In a sense
-(UINavigationController *) navigationController
{
return self.navigationController;
}
-(UINavigationController *) navigationController already exist through UINavigationController
Use
#dynamic navigationController;
This tells the compiler that the property implementation is 'somewhere else' and that it should trust that the requirement will be fulfilled at runtime. In practice, that means its in the superclass.
If you try to implement it yourself you'll end up with duplicate storage (so things probably won't work how you expect) or recursion.
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
I'm a little bit confused about the custom UiViewController inheritance.
For example if I have:
#interface MyViewController : UIViewController <UITableViewDelegate, UITableViewDataSource> {
IBOutlet UITableView *tableView;
id <MyDelegate> aDelegate;
AnObject *myObject;
}
#property (nonatomic, assign) id <MyDelegate> aDelegate;
#property (nonatomic, retain) AnObject *myObject;
#end
A subclass of MyViewController "inherits" the protocol declaration? that is, can or not it override the methods in them, setting the delegate and datasource properly without redeclaring in its interface?
And what about property and their possible deallocation?
I would some examples, links...
Firstly, a protocol is simply a promise that a class implements required and (optionally) optional methods. That's all it is. You can override these in subclasses and such however you want.
The data source and delegate of the table view are set to self, and self implements the UITableViewDataSource and UITableViewDelegate protocols.
In your sub-class, self is the sub-class. Overriding the protocol methods in the sub-class will work perfectly fine. The table view is the one defined in the parent class.
In short, the answer is yes. If you want more information I suggest you read up on how #protocol works.
I've got a protocol:
#protocol Gadget <NSObject>
#property (readonly) UIView *view;
- (void) attachViewToParent:(UIView *)parentView;
#end
And an "abstract" base class, with an implementation (as a getter, not shown) of -(UIView *)view:
// Base functionality
#interface AbstractGadget : NSObject {
UIView *view;
}
#property (readonly) UIView *view;
#end
But when I implement the Gadget protocol in a subclass of AbstractGadget, like so:
// Concrete
#interface BlueGadget : AbstractGadget <Gadget> {
}
- (void) attachViewToParent:(UIView *)parentView;
#end
#implementation BlueGadget
- (void) attachViewToParent:(UIView *)parentView {
//...
}
#end
I get a compiler error telling me "warning: property 'view' requires method '-view' to be defined." I can make this go away using #dynamic, or adding a stub method:
- (UIView *) view {
return [super view];
}
But I just want to know if I'm doing something that's not supported, something I shouldn't be doing, or if it's just a limitation / bug in the compiler?
By declaring the property as #dynamic you are telling the compiler that the property getter (and setter if required) are implemented elsewhere (potentially at runtime). This sounds like a perfectly reasonable use case to me.
See The Docs for more information.
I also came across this exact issue. This is one of situations that #dynamic is there for.
Here is the rule for variable, property and synthesize in objective-C:
If you have a property, you must have a #synthesize or you declare #dynamic and write the getter and setter method yourself.
So, because you have a property called view, you have to declare #synthesize. That should be it. Nothing to do with #protocol, inheritance