leftspin
leftspin

Reputation: 2488

UIApplication's sendAction() works even if target(forAction:…) is nil

This code is called when a subview (imageSlideshow) is tapped:

        imageSlideshow.didTap = { [weak self] in
        guard UIApplication.shared.sendAction(#selector(ImageCarouselViewResponder.didTapImageCarousel(sender:)), to: nil, from: self, for: nil) else {
            assertionFailure("No target for ImageCarouselViewResponder.didTapImageCarousel(sender:)")
            return
        }
        …

This works as expected, as you can see from this debugging output:

(lldb) po UIApplication.shared.sendAction(#selector(ImageCarouselViewResponder.didTapImageCarousel(sender:)), to: nil, from: self, for: nil) 
true

However, when I try to ask for the target with the same selector, it's nil:

(lldb) po UIApplication.shared.target(forAction: #selector(ImageCarouselViewResponder.didTapImageCarousel(sender:)), withSender: self)
nil

Furthermore, I've added an extension to walk the responder tree to find the first responder, and it returns nil in this situation.

How is sendAction(…) working if there is no first responder?

Upvotes: 1

Views: 1496

Answers (1)

David Rönnqvist
David Rönnqvist

Reputation: 56625

Calling target(forAction:) will only pass the request up the responder chain from that responder, but the only thing after the application in the responder chain is the application delegate. Unless this method is implemented in either of those two, calling target(forAction:) on the application instance would return nil.

Calling sendAction(_:to:from:for:) with a nil target works because it sends the message to the first responder which passes it up the responder chain until it is handled.

Upvotes: 2

Related Questions