15

The ARC migration tool is refusing to accept this code prior to starting with migration:

[self.delegate performSelector:@selector(overlayDismissed:) withObject:self afterDelay:0];

The delegate is forced to implement this method with a protocol, and it should work fine:

@protocol OverlayDelegate <NSObject>
- (void)overlayDismissed:(Overlay*)overlay;
@end

@interface Overlay : UIImageView {
    id<OverlayDelegate> delegate;
}

@property (nonatomic, assign) id<OverlayDelegate> delegate;

What's wrong with ARC? Why is it telling me that there is "no known instance method for selector 'performSelector:withObject:afterDelay:'?

openfrog
  • 40,201
  • 65
  • 225
  • 373

4 Answers4

16

ARC isn't causing this - it is is merely exposing it. That method is defined on NSObject - but id works for more than just NSObject (so you have to be more specific than just 'id'). Change your code to this:

@interface Overlay : UIImageView {
    NSObject<OverlayDelegate> *delegate;
}

@property (nonatomic, assign) NSObject<OverlayDelegate> *delegate;
Brad Larson
  • 170,088
  • 45
  • 397
  • 571
dtuckernet
  • 7,817
  • 5
  • 39
  • 54
  • So that means under ARC the days where we declare delegates as id are gone? Simply rely on NSObject instead? (for me that makes sense anyways) – openfrog Jan 13 '12 at 01:37
  • 1
    ARC enforces these things for memory management purposes. If you know that your delegate will be of type NSObject - then just state that and this problem goes away. – dtuckernet Jan 13 '12 at 01:38
  • Or still use `id` and just don't use methods from `NSObject`. Why are you using methods from `NSObject` anyway? Is there a requirement to here? – mattjgalloway Jan 13 '12 at 01:43
  • Yes, probably there is a requirement to use a delayed performSelector. See this question: http://stackoverflow.com/q/8844551/221023 – openfrog Jan 13 '12 at 01:47
  • 1
    You missed the pointers here: you want `NSObject *delegate`. – DarkDust Jan 13 '12 at 02:01
3

Simple, your object is of type id and conforms to the NSObject protocol. However, this protocol doesn't declare performSelector:withObject:afterDelay:, so ARC doesn't know what the method is doing and if it must retain anything. Either use an NSObject or cast it prior to making the method call.

JustSid
  • 25,168
  • 7
  • 79
  • 97
0

I met error:

No known class method for selector conformsToProtocol:

The reason is that : file name is not equal to the class name with @interface and @implementation.

ChenYilong
  • 8,543
  • 9
  • 56
  • 84
0

I've figured out that casting the delegate to NSObject* solves the problem:

[self.delegate performSelector:@selector(overlayDismissed:) withObject:self afterDelay:0];

For some weird reason autocompletion did not even come up with -performSelector:withObject:afterDelay: so I had to type it manually. Instead, it offered only -performSelector: and -performSelector:withObject:withObject:

My guess is that it's just stupid to use id as the type for delegates in Objective-C, and I never really knew why everyone including myself is doing that rather than just defining it as NSObject. However, my protocol even told that whoever conforms to that protocol also has to conform to the NSObject protocol by doing this: OverlayDelegate <NSObject> - and still, the compiler didn't get it.

So for now I'm satisfied it works with the cast, but it feels like eating old fish.

openfrog
  • 40,201
  • 65
  • 225
  • 373
  • Note: While typing my answer a message appeared that an answer has been posted by dtuckernet. So he was faster. – openfrog Jan 13 '12 at 01:38
  • 2
    It's because `performSelector:withObject:afterDelay:` is defined on `NSObject` the class rather than `NSObject` the protocol. That's why it errored (under ARC) and didn't come up in code completion. – mattjgalloway Jan 13 '12 at 01:41