How to resolve "no known instance method for selector 'performSelector:withObject:afterDelay:'" when migrating to ARC?
Asked Answered
P

4

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:'?

Penetrating answered 13/1, 2012 at 1:32 Comment(0)
A
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;
Atronna answered 13/1, 2012 at 1:35 Comment(5)
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)Penetrating
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.Atronna
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?Coprology
Yes, probably there is a requirement to use a delayed performSelector. See this question: https://mcmap.net/q/824491/-how-to-correctly-notify-a-delegate-that-the-instance-is-no-longer-needed/221023Penetrating
You missed the pointers here: you want NSObject<OverlayDelegate> *delegate.Neukam
D
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.

Danadanae answered 13/1, 2012 at 1:36 Comment(0)
P
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.

Penetrating answered 13/1, 2012 at 1:36 Comment(2)
Note: While typing my answer a message appeared that an answer has been posted by dtuckernet. So he was faster.Penetrating
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.Coprology
I
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.

Impecunious answered 11/8, 2016 at 2:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.