I've implemented a protocol with an optional method and in the calling method I want to send respondsToSelector: to self.delegate before I send the message, but that does not compile. The fail message is:
No Known instance method for selector 'respondsToSelector'.
As a work-around, I "sanitized" the delegate as shown below, which compiles...
//MyClass.h:
#class MyClass;
#Protocol MyClassDelegate
- (void)myClass:(MyClass *)sender willDoSomething:(BOOL)animated;
#end
#interface MyClass : UIViewController
#property (nonatomic, weak) id<MyClassDelegate> delegate;
#end
and
//MyClass.m:
...
#synthesize delegate = _delegate;
...
id sanitizedDelegate = self.delegate; //Hmmmm... why does this work?
if ([sanitizedDelegate respondsToSelector:#selector(myClass:willDoSomething:)]) {
[self.delegate myClass:self willDoSomething:animated];
}
.
I checked a number of posts including this one but it does not answer the compilation fail issue.
Also, alternative accessors do not work...
[self delegate]
//or
_delegate
Has anyone seen this or can advise a better way of handling?
IOS 5.0:(9A334), Xcode 4.2.1 (4D502)
-respondsToSelector: is a method on NSObject. Either assume that your id delegate is in fact an NSObject, and cast it:
[(NSObject*)self.delegate respondsToSelector:#selector(myClass:willDoSomething:)]
Or, better, make your delegate explicitly an NSObject:
#property (nonatomic, weak) NSObject<MyClassDelegate>* delegate;
Or make the protocol be a sub-protocol of NSObject:
#protocol MyClassDelegate <NSObject>
Basically you are saying that your delegate is constrained only by your <MyClassDelegate> protocol so the compiler assumes that those are the only methods available. What you need to do is have the protocol extend <NSObject> like so:
#Protocol MyClassDelegate <NSObject>
- (void)myClass:(MyClass *)sender willDoSomething:(BOOL)animated;
#end
That way the compiler knows that any object which conforms to your protocol also conforms to the <NSObject> protocol which defines respondsToSelector:.
Related
#property (unsafe_unretained,nonatomic) id<SceneDelegate> delegate;
it works fine on xcode 5, but it gives me this error on xcode 6.1
Error: Property type 'id<SceneDelegate>' is incompatible with type 'id<SKSceneDelegate>' inherited from 'SKScene'
what's that mean?
Addition:
beginning of scene.h
#protocol SceneDelegate <NSObject>
- (void) eventStart;
#end
#interface Scene : SKScene<SKPhysicsContactDelegate>
#property (unsafe_unretained,nonatomic) id<SceneDelegate> delegate;
viewController.h
#import "Scene.h"
#import <AVFoundation/AVFoundation.h>
#interface ViewController : UIViewController<SceneDelegate, AVAudioPlayerDelegate>
viewController.m
scene.delegate = self;
That's all the lines contain SceneDelegate.
It means SKScene already has a property of the same name: delegate
You are trying to redeclare that property but with a different protocol: SceneDelegate instead of SKSceneDelegate.
So either you wanted to use the delegate property, in that case you needn't declare that property, just assign your SKSceneDelegate object to the delegate property. For example:
self.delegate = mySceneDelegateObject;
Otherwise use a different name instead of delegate if SceneDelegate is an actual protocol you created (and consider renaming the protocol because it's easily confused with SKSceneDelegate).
Somehow I got this error in XCode 4.0.2, not sure what is wrong.
File: HomeViewController.h
#import <UIKit/UIKit.h>
#interface HomeViewController : UIViewController <UITabBarDelegate>
{
UIButton *Button1, *Button2, *Button3;
}
#property (nonatomic, retain) IBOutlet UIButton *Button1;
#property (nonatomic, retain) IBOutlet UIButton *Button2;
#property (nonatomic, retain) IBOutlet UIButton *Button3;
.... other member functions...
....
#end
File: HomeViewController.m
......
#import "RemoteServiceManager.h"
#interface HomeViewController()
{ //This is where the error happens: Expected Identifier or "(" before "{" token
RemoteServiceManager* serviceManager;
}
#end
#implementation HomeViewController
#synthesize Button1, Button2, Button3;
.... other member functions
....
#end
Looks like it does not recognize RemoteServiceManager. Wherever I used the serviceManager, it will say HomeViewController has no member named serviceManager.
Is it possible that is caused by XCode version? I am using XCode 4.0.2 on Mac OS X 10.6.7.
Thanks.
you cant add instance variables to private categories.
put properties in there instead, and synthesize them to obtain a variable as well as an internal getter/setter
#interface HomeViewController
#property (nonatomic, strong) NSString *privateProperty;
#end
#implementation HomeViewController
#synthesize privateProperty = _privateProperty;
#end
or you can add the instance variable to the class itself.
#implementation HomeViewController
NSString *privateVariable;
#end
Bear in mind also. that if you create a category in another file, any variables you declare in the body of that category will be static across all instances. definitely something to keep an eye out for.
To recap. you can create a variable in the interface of the main category. or in the implementation of the main category.
and the private category is for you to add prototypes to your class that will let the rest of the file know they "will be/are" available.
the old xcode cant do this, no. it does know class extensions yet because it ships with an older version of the LLVM compiler
You probably found your answer, but I post the answer here for somebody who encounters the same problem:
as Daij said, the problem is due to the version of compiler, so to fix this you need to change the compiler setting:
Build Setting > Build Options > Compiler for C/C++/ObjectiveC
Change value from "LLVM GCC 4.2" to "Apple LLVM compiler 4.2"
Hope it helps.
My Cocoa AppDelegate contains a reference of type ID to it's main view. The reference is polymorphic because it may point to a subclass of PDFView or a subclass of NSImageView, depending on the origin of the view's image. Both view subclasses implement the same protocol, so my AppDelegate does not have to know what type of view it's dealing with. However, every time I call one of the protocol methods I get a warning that says "Instance method '-methodName' not found (return type defaults to 'id')". I can either ignore the warning or force the issue by using "performSelector:(#selector(methodName:)" to call the protocol method.
Is there something I can do (or should have done) to eliminate the warning without resorting to performSelector?
//FLAppDelegate.h
#interface FLAppDelegate : NSObject <NSApplicationDelegate>
{
...
IBOutlet id _formImageView; //type is FLPDFView* or FLImageView*
…
}
//FLFormImageProtocol.h
#protocol FLFormImageProtocol <NSObject>
#required
- (void) methodName;
#end
//FLPDFView.h
#interface FLPDFView : PDFView <FLFormImageProtocol>
#end
//FLImageView.h
#interface FLImageView : NSImageView <FLFormImageProtocol>
#end
Type the instance variable with the protocol:
IBOutlet id<FLFormImageProtocol> _formImageView;
This seems like a simple thing, but my brain doesn't seem to be working today, and my searches haven't turned up a helpful answer.
I have lots of code that extends Cocoa classes via categories (it's open source, too). Some methods want to call the delegate; the old code used informal protocols to do this, but now when building targeting 10.6, I get the warning:
warning: '-outlineView:menuForTableColumn:byItem:' not found in protocol(s)
As an example, here's a category:
#interface NSOutlineView (DSOutlineViewCategories)
- (NSMenu *)menuForEvent:(NSEvent *)event;
#end
Which used an informal protocol to declare a delegate method:
#interface NSObject (DSTableViewDelegate)
- (NSMenu *)outlineView:(NSOutlineView *)olv menuForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item;
#end
And the implementation calls that on the delegate:
#implementation NSOutlineView (DSOutlineViewCategories)
- (NSMenu *)menuForEvent:(NSEvent *)event
{
NSPoint point = [self convertPoint:[event locationInWindow] fromView:nil];
NSInteger column = [self columnAtPoint:point];
NSInteger row = [self rowAtPoint:point];
id item = [self itemAtRow:row];
if (column >= 0 && item && [[self delegate] respondsToSelector:#selector(outlineView:menuForTableColumn:byItem:)])
return [[self delegate] outlineView:self menuForTableColumn:[[self tableColumns] objectAtIndex:column] byItem:item];
else
return [super menuForEvent:event];
}
#end
How can I update this code for 10.6 (and beyond), to avoid the "not found in protocol(s)" warning?
I think this is because the NSOutlineView delegate is now typed as id <NSOutlineViewDelegate> rather than a plain id as it was in the 10.5 SDK. The category is declared on NSObject, but the compiler doesn't see the delegate object as inheriting from NSObject, so it doesn't recognize that it would respond to the message. Before, since the delegate was a plain id, it wouldn't complain about any message sent to it, as long as it could find the declaration somewhere.
The quick and dirty fix would be to just add a cast, making the code [(id)[self delegate] outlineView:self menuForTableColumn:[[self tableColumns] objectAtIndex:column] byItem:item];
To be a little more formal, you could declare your own formal delegate protocol which inherits from NSOutlineViewDelegate, which would look like
#protocol DSOutlineViewDelegate <NSOutlineViewDelegate>
#optional
- (NSMenu *)outlineView:(NSOutlineView *)olv menuForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item;
#end
Then, in the code that calls it, you would want to be calling the method on an object with type id <DSOutlineViewDelegate>. You can do this by declaring a new method that does the casting for you, like:
- (id <DSOutlineViewDelegate>)ds_delegate
{
return (id <DSOutlineViewDelegate>)[self delegate];
}
Then, in the actual code, you'd call:
[[self ds_delegate] outlineView:self menuForTableColumn:[[self tableColumns] objectAtIndex:column] byItem:item];
and the compiler should be OK with that. Since the method is declared as optional in the protocol, you still want to check at runtime whether the delegate actually responds to the selector.
I am trying to respond to a click within a textfield. When the click occurs, I am going to open a panel. My initial thought was to use a delegate method to respond to the click event - but I found that:
This method doesn't work:
(void)textDidBeginEditing:(NSNotification *)aNotification
This method does work, but only when I actually edit the text within the text field, not when I first click it. And - if I edit the text a second time, this method stops working:
(void)controlTextDidBeginEditing:(NSNotification *)aNotification
I could use as much detail as possible - or a code example, ideally. I know that an nstextfield inherits from NSControl, which has a mouseDown event. Is there a similar way to respond to the event with a textfield, also?
Since NSTextField inherits from the NSControl class, it also inherits the -(void)mouseDown:(NSEvent*) theEvent method.
I needed to have an NSTextField call a delegate function upon clicking it today, and thought this basic code might be useful. Note that NSTextField already has a delegate and that in SDK v10.6, the delegate already has a protocol associated with it. Note that if you don't care about protocols, compiler warnings, etc., you don't need the protocol and property declarations or the getter and setter.
MouseDownTextField.h:
#import <Appkit/Appkit.h>
#class MouseDownTextField;
#protocol MouseDownTextFieldDelegate <NSTextFieldDelegate>
-(void) mouseDownTextFieldClicked:(MouseDownTextField *)textField;
#end
#interface MouseDownTextField: NSTextField {
}
#property(assign) id<MouseDownTextFieldDelegate> delegate;
#end
MouseDownTextField.m:
#import "MouseDownTextField.h"
#implementation MouseDownTextField
-(void)mouseDown:(NSEvent *)event {
[self.delegate mouseDownTextFieldClicked:self];
}
-(void)setDelegate:(id<MouseDownTextFieldDelegate>)delegate {
[super setDelegate:delegate];
}
-(id)delegate {
return [super delegate];
}
AppDelegate.h:
#interface AppDelegate <MouseDownTextFieldDelegate>
...
#property IBOutlet MouseDownTextField *textField;
...
AppDelegate.m:
...
self.textField.delegate = self;
...
-(void)mouseDownTextFieldClicked:(MouseDownTextField *)textField {
NSLog(#"Clicked");
...
}
...
If you're building with 10.5 SDK, don't have the protocol inherit from NSTextFieldDelegate.