Cannot use respondsToSelector using ARC on Mac - objective-c

When I call respondsToSelector in an ARC environment, I get the following error message Automatic Reference Counting Issue No known instance method for selector respondsToSelector:
This is the header
#import <AppKit/AppKit.h>
#class MTScrollView;
#protocol MTScrollViewDelegate
-(void)scrollViewDidScroll:(MTScrollView *)scrollView;
#end
#interface MTScrollView : NSScrollView
{
}
#property(nonatomic, weak) id<MTScrollViewDelegate>delegate;
#end
This is the implementation file
#import "MTScrollView.h"
#implementation MTScrollView
#synthesize delegate;
- (void)reflectScrolledClipView:(NSClipView *)aClipView
{
[super reflectScrolledClipView:aClipView];
if([delegate respondsToSelector:#selector(scrollViewDidScroll:)])
{
[delegate scrollViewDidScroll:self];
}
}
#end
Any suggestions on why I am getting this error?

Make the protocol conform to NSObject
#protocol MTScrollViewDelegate <NSObject>
Otherwise the compiler doesn't think that the object will respond to NSObject messages like respondsToSelector, and will generate a warning. It will succeed at runtime without issues either way.

For Swift this becomes:
#objc protocol MTScrollViewDelegate: NSObjectProtocol
The NSObject protocol groups methods that are fundamental to all Objective-C objects.
For more information on what NSObjectProtocol is: https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Protocols/NSObject_Protocol/index.html

Related

Unable to access protocol methods via delegate

While accessing protocol methods via delegate I'm getting following error:
"No known instance method for selector 'lostConnection'"
Swift Protocol:
#objc protocol GameDelegate {
func lostConnection()
}
Objective C game file
//game.h
#protocol GameDelegate;
#interface SSStreamManager : NSObject
#property (assign) id<GameDelegate> delegate
#end
Getting error while calling protocol methods
[self.delegate lostConnection]; // No known instance method for selector 'lostConnection'
You haven't shown any real code, but here's an example that will get you started. These are the three files in an iOS app project:
ViewController.swift
import UIKit
#objc protocol GameDelegate {
func lostConnection()
}
class ViewController: UIViewController {
}
Thing.h
#import <Foundation/Foundation.h>
#protocol GameDelegate;
#interface Thing : NSObject
#property (assign) id<GameDelegate> delegate;
#end
Thing.m
#import "Thing.h"
#import "MyApp-Swift.h"
#implementation Thing
- (void) test {
[self.delegate lostConnection];
}
#end
That compiles. You should be able to follow this model in your own code.

"Expected a Type" error for protocol which should be known to the compiler

Minimum Example "Test.h":
#import <Foundation/Foundation.h>
#protocol CallBack <NSObject>
-(void)method;
#end
#interface Test : NSObject
-(void)callback:(CallBack*)theCallback;
#end
And the corresponding "Test.m":
#import "Test.h"
#implementation Test
-(void)callback:(CallBack*)theCallback
{
[theCallback method];
}
#end
This will give me a "Expected a Type" error for the CallBack parameter both in the .m and the .h file. As the CallBack protocol is defined before everything else, i can't see why the compiler can't find it. If i add a Forward-Definition #class CallBack; at the beginning of the header file it will give me a "Receiver type 'CallBack' for instance message is a forward declaration" error for the line [theCallback method].
why can't the compiler find the protocol?
The correct syntax to refer to an object that conforms to the CallBack protocol is id<CallBack>.
Thus, you might want:
#protocol CallBack <NSObject>
-(void)method;
#end
#interface Test : NSObject
-(void)callback:(id <CallBack>)theCallback;
#end
and
#implementation Test
-(void)callback:(id <CallBack>)theCallback
{
[theCallback method];
}
#end
For more information, see Working with Protocols in the Programming with Objective-C guide.

do you need to import .h files when using delegates?

-(IBAction)ok
{
//send message to the delegate with the new settings
[self.delegate setHeight:_height Width:_width Mines:_mines];
[self.delegate dismissViewControllerAnimated:YES completion:nil];
}
the first message to the delegate wouldn't work until i imported ViewController.h, but the second one worked without the import.
if i add -(void)setHeight:(int)h Width:(int)w Mines:(int)m; as required in the optionsViewController protocol will that mean that i no longer have to import the root .h file.
i intend to use delegation to send messages in other parts of the program so i want to make sure i am using it correctly and not importing things when i don't need to.
Thank you.
if i add -(void)setHeight:(int)h Width:(int)w Mines:(int)m; as required in the optionsViewController protocol will that mean that i no longer have to import the root .h file.
Yes! You could also add it as #optional and it would work (remember to check if the delegate -respondsToSelector: in that case). The whole idea is that your object regularly knows nothing about the delegate object - except that it conforms to the protocol (ie implements the #required and possibly the #optional methods).
Added for clarification (on my phone, which is a pain in the butt):
//OptionsViewController.h
//this object does NOT have to import
//the calling viewControllers .h file
//which is what I think the OP does
#protocol optionsViewControllerProtocol;
#interface OptionsViewController : UIViewController
#property (nonatomic, assign) id<optionsViewControllerProtocol> delegate; //should be id, could be UIViewController too, if absolutely necessary (better design to make it id)
#end
#protocol optionsViewControllerProtocol <NSObject>
#required
-(void) setHeight: (NSInteger) height;
#end
//viewController.h
#import "optionsViewController.h" //necessary to get the protocols definitions
#interface OptionsViewController: UIViewController <optionsViewControllerProtocol>
//.....
If you define your delegate property to be of class UIViewController*, then the compiler will recognize the dismissViewControllerAnimated:completion: method without you needing to import anything, since that's a standard method for that class.
For a custom method, i.e. setHeight:Width:Mines:, you absolutely need to import the header file, or have it imported somewhere up the import chain.
Example: You have MyProtocol.h, and you want SomeClass to have a delegate property that conforms to that protocol. If you #import "MyProtocol.h" in SomeClass.h, you don't need to re-import it in SomeClass.m.
// SomeClass.h
#import "MyProtocol.h"
#interface SomeClass : NSObject
#property (weak, nonatomic) id<MyProtocol> delegate;
#end
//SomeClass.m
#import "SomeClass.h"
#implementation SomeClass
- (void)someMethod
{
[self.delegate myProtocolMethod];
}
#end

Custom delegate

I want to know how can I use a custom delegate?
Maybe an example will help you:
#import <UIKit/UIKit.h>
#protocol VSKeypadViewDelegate
#required
-(int)numberOfRows;
-(int)numberOfColumns;
-(NSString*)titleForButtonOnRow:(int)row andColumn:(int)column;
-(id)valueForButtonOnRow:(int)row andColumn:(int)column;
-(CGSize)sizeForButtonOnRow:(int)row andColumn:(int)column;
-(void)receivedValue:(id)value;
-(CGPoint)keypadOrigin;
#optional
-(NSArray *)additionalButtonsForKeypad;
//-(UIColor *)keypadBackgroundColor;
//-(UIColor *)keyBackgroundColorForRow:(int)row andColumn:(int)Column;
-(UIImage *)backgroundImageForState:(UIControlState)state forKeyAtRow:(int)row andColumn:(int)column;
-(BOOL)isButtonEnabledAtRow:(int)row andColumn:(int)column;
#end
#interface VSKeypadView : UIView {
id<VSKeypadViewDelegate> delegate;
NSArray *keypadButtons;
}
+ (VSKeypadView *)keypadViewWithFrame:(CGRect)r;
- (id)initWithFrame:(CGRect)r ;
-(void)fireKeypadButton:(id)sender;
#property(nonatomic, assign) id<VSKeypadViewDelegate> delegate;
#end
This is a keypad I wrote.
The VSKeyPadView derives from UIView and has a delegate ivar of type id<VSKeypadViewDelegate>, that means, that the object set to delegate is expected to conform to the protocol VSKeypadViewDelegate. That protocol has some required and some optional method. That means, that it is your responsibility to write those method — what ever makes sense for you.
You will find this code running in an example application at github.

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?