getting a warning setting up delegate for a custom

2019-05-09 22:42发布

问题:

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?

回答1:

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.



回答2:

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.



回答3:

Try explicitly typing (giving type to) the destinationVC, like this:

SomeSecondCustomViewController *vc = (SomeSecondCustomViewController  *)segue.destinationViewController;
vc.delegate = self;


回答4:

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