Avoid method not found for protocol methods - cocoa

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;

Related

delegate works in xcode 5 but not in xcode 6

#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).

self.delegate respondsToSelector: ... does not compile

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:.

In cocoa2.0 does #property obviate variable declaration in the interface

Just experimenting with #property and #synthesize:
#interface Greeter : NSObject
//{
// NSString * name;
//}
#property (assign) NSString * name;
- (NSString *) greeting;
#end
It seems to be the case that if you declare a variable using #property that you don't have to declare it between the braces (and you don't even need the braces if all of your interface variables are all declared using #property). Is this always correct? And is it good style to leave out the top part of the interface (braces included)? I have been using both and been irritated by the redundancy.
There is no “Cocoa 2.0”.
In Objective-C 2.0, on the modern runtime, yes, you can leave out the instance variables, and the property will generate them for you. The legacy runtime on Mac OS X still requires explicit instance variables.
You cannot leave out the ivar section entirely yet, but you can leave it empty.
Here is the webpage where I first found out you can automatically have you properties synthesized and also declare new properties in class extensions. It gives a bit of interesting back story as well.
http://www.mcubedsw.com/blog/index.php/site/comments/new_objective-c_features/
As for style and correctness, I've been using primarily properties for the last couple of weeks and it has made my code look quite clean! I can now declare private properties in my implementation and not have them exposed in the header making any interface to use my classes very simple and non-confusing to use.
I've ran into a problem when using interface builder where having an iVar to any subviews of a view controller still has to be declared in the header for interface builder to see it as an IBOutlet and assign to it. You can still declare those #private though and then have the private properties declared in a class extension in your implementation if you really want it as a property for you to use.
// In your header
#interface MenuViewController : UIViewController {
#private
IBOutlet UIButton *buttonPeopleShouldNotKnowAbout;
}
#end
// And in your implementation
#implementation MenuViewController ()
#property (nonatomic, readwrite, assign) IBOutlet UIButton *buttonPeopleShouldNotKnowAbout;
#end

What's wrong with this Cocoa code?

I'm trying to make a simple Cocoa application using XCode 3.2.3. In interface builder I added NSTextField and NSButton. When I press the button, I want it to clear whatever is in the text field.
I made a new class called AppController.h. This is the contents:
#import <Foundation/Foundation.h>
#interface AppController : NSObject {
IBOutlet id textView;
}
- (IBAction) clearText: sender;
#end
AppController.m looks like this:
#import "AppController.h"
#implementation AppController
- (IBAction) clearText: sender
{
[textView setString: #" "];
}
#end
I connected the button to clearText and the textbox to textView.
The program compiles without error and runs. But when I press the button, nothing happens. Why is that?
Using id for an IBOutlet is a bad practice. Use
IBOutlet NSTextView* textView;
instead.
Please check using the debugger, or putting NSLog(#"foo!"); before [textView setString:#""] to see if the action method is really called.
Another pitfall is that there are NSTextView and NSTextField. These two are different!
The former supports both setString: and setStringValue:, while the latter only supports setStringValue:.
Which object did you use in the interface builder?

Which delegate method should I use to respond to clicks on an NSTextField?

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.

Resources