Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How is it possible to pass NSNumber to a method expecting a bool?

[[self.view.window subviews] makeObjectsPerformSelector:@selector(setUserInteractionEnabled:) withObject:[NSNumber numberWithBool:NO]];

I saw this code in another question's answer ( How to disable touch input to all views except the top-most view?) and it surprised me when it worked, as setUserInteractionEnabled: expects a BOOL (which as it's not an objective-c object can't be passed in performSelector:withObject: type methods).

Where is the documentation that says that passing an NSNumber is ok? Does it work for all methods, or is a special implementation needed? And does it only work with BOOLs, or can it be done with types like int?

like image 316
Jonathan. Avatar asked Jan 01 '12 21:01

Jonathan.


2 Answers

If you just want your code to work, upvote and accept Paul.s's answer. If you want to read about nerds performing experiments, carry on. There was some interesting discussion in the comments to my original answer which I have summarised below.

This does not work. I have tried it in an iOS project, the userInteractionEnabled property is not affected by sending performSelector:withObject:. This matches up with the documentation for NSObject which states:

aSelector should identify a method that takes a single argument of type id. For methods with other argument types and return values, use NSInvocation.

The now legendary Peter Hosey built a sample foundation tool here which bizzarely enough works when you pass a double to it, also a float as I found out myself.

To add curiosity to curiosity, this does not work in an iOS project (double or float).

In summary, I think we can say the following:

  • If it ever works, it works by accident and should not be relied upon
  • An accepted or upvoted answer on stack overflow is not necessarily correct
like image 135
jrturton Avatar answered Sep 24 '22 08:09

jrturton


You cannot pass an NSNumber as the object and have it come out as a BOOL on the other end like that. However, there are some workarounds.

  1. Use an NSInvocation. You'd need to create an NSArray category that uses NSInvocation. This is a little messy.

  2. Create a UIView category with a setUserInteractionEnabled:-like function (with a similar name?) that operates with an NSNumber which then calls setUserInteractionEnabled: with the BOOL value of the NSNumber. Something like:

    @implementation UIView (Additions)
    - (BOOL)setUserInteractionEnabled2:(NSNumber *)aBool
    {
      self.userInteractionEnabled = [aBool boolValue];
    }
    @end
    
like image 39
senojsitruc Avatar answered Sep 21 '22 08:09

senojsitruc