i added a custom protocol to one of my classes and i am getting a compiler warning when i attempt to set the delegate during a prepareForSegue: method. the warning i get is...
Sending 'MyCustomViewControllerClass *const __strong' to parameter of incompatible type 'id<NSFileManagerDelegate>'
the project builds and runs and everything works fine minus the warning. if i add <NSFileManagerDelegate>
to my custom class the warning goes away. am i missing something or is this a bug in Xcode (6 beta)? the code is standard code for setting up a protocol / delegate but i will post it anyways...
SomeSecondClass.h
#import <UIKit/UIKit>
@class SomeSecondCustomViewController;
@protocol SomeSecondCustomViewControllerDelegate <NSObject>
- (void)doThisForMe
@end
@interface SomeSecondCustomViewController : UIViewController
@property (weak, nonatomic) id <SomeSecondCustomViewControllerDelegate> delegate;
@end
SomeSecondClass.m
@interface SomeSecondViewController ()
…stuff
-(void)someMethod {
[self.delegate doThisForMe];
}
@end
CustomClass.h
#import <UIKit/UIKit.h>
#import “ SomeSecondViewController.h”
@interface MyCustomViewController : UIViewController <SomeSecondCustomViewControllerDelegate>
//adding on <NSFileManagerDelegate> removes the warning...
@end
CustomClass.h
...standard stuff...
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:@"MySegue"]) {
//this is where the warning happens on "self"
[segue.destinationViewController setDelegate:self];
}
}
- (void)doThisForMe {
//doing some stuff...
}
@end
i have opened previous projects where the warning did not exist and now the same warning appears. i am wondering if this is an Xcode problem?
You are running into an issue caused by an ambiguity in how Objective-C finds a matching selector and dealing with an id
reference.
UIStoryboardSegue destinationViewController
returns an id
. Your code then tries to call the setDelegate
method on this id
reference. Since there is no information about what this id
actually references, it doesn't know which setDelegate:
method you might mean (there are many). So the compiler scans through the list it knows of and picks one. In this case it chose the setDelegate:
method from the NSFileManager
class. Since self
doesn't conform to the NSFileManagerDelegate
protocol, you get the warning.
You could ignore the warning and your code will work fine in this case.
The better solution is to help the compiler by adding a cast:
[(SomeSecondCustomViewController *)segue.destinationViewController setDelegate:self];
This will let the compiler know which setDelegate:
method you really mean.
BTW - Adding NSFileManagerDelegate
to your class is not a valid solution even if it works at the moment. A simple reordering of some import
statements could lead the compiler to make a different choice and your warning would return but complain about not conforming to some other protocol.
as it turns out, this is a bug / change in Xcode 6 beta. running this exact same code on Xcode 5.1.1 produces no warnings or errors. the problem is cause because in Xcode 6 the compiler is asking for type
(id<NSFileManager>)
for the delegate. in Xcode 5.1 the compiler is simply expecting
(id)
for the delegate type.
as rmaddy stated, by casting the type in
[(SomeSecondCustomViewController *)segue.destinationViewController setDelegate:self];
it did remove the warning, but this should be an unnecessary step and will chalk it up to a problem with Xcode.
Try explicitly typing (giving type to) the destinationVC, like this:
SomeSecondCustomViewController *vc = (SomeSecondCustomViewController *)segue.destinationViewController;
vc.delegate = self;
@rmaddy provides the correct answer. This is a more detailed example for those of us who are lightly schooled in the ways of Objective-C.
I changed my code from:
[[segue destinationViewController] setDelegate:self];
UIPopoverController *popoverController = [(UIStoryboardPopoverSegue *)segue popoverController];
self.flipsidePopoverController = popoverController;
popoverController.delegate = self;
to:
[(UIPopoverController *)segue.destinationViewController setDelegate:self];
UIPopoverController *popoverController = [(UIStoryboardPopoverSegue *)segue popoverController];
self.flipsidePopoverController = popoverController;
popoverController.delegate = self;
and the warnings disappeared.