1

I am using below code in a function to handle all UIButtons in my View and it works fine when all the objects in the View are UIButton.

for v in self.mainView.subviews as [UIButton]
 {
   println (v.tag)
 }

But in case there is any other objects like Label or ImageView in the same View, I get error 'EXC_BAD_INSTRUCTION(code=EXC_I386_INVOP,subdued=0x0)'.

How should I change the code so that it works only for (all) UIButton.

Adaoli
  • 27
  • 1
  • 5

3 Answers3

1

This worked for me:

 for v in self.view.subviews as [AnyObject]
        {
            println (v.tag)
        }
Steve Rosenberg
  • 19,348
  • 7
  • 46
  • 53
1

The subview property of UIView is an array of AnyObject. The runtime happens because you are performing a forced downcast from [AnyObject] to [UIButton].

From a compiler perspective, the down cast is legit:

let x: [UIButton] = [AnyObject]() as [UIButton]

because AnyObject can be any class, and UIButton is a class.

In your case you are making the assumption that all objects contained in subviews are instances of UIButton, which can be possible (if you explicitly add UIButtons only to the view), but if the view has other UI elements (labels, other views, etc.) then the downcast will fail at runtime.

If for example the view contains another view, the above downcast is equivalent to doing this:

var view = UIView()
var button = view as UIButton

which fails because a UIView is not a UIButton (although thanks to polymorphism the opposite is true, being UIButton inherited from UIView).

If you want your code to print the tag for all UIButtons, ignoring all other UI elements, then @rahul_send89's answer is the correct one: it loops through all elements of the subview property, and it prints the tag only if the current element is a UIButton.

@SteveRosenberg's answer instead print the tag for all elements, regardless of their actual type.

Depending on what you want to do with your buttons (I presume the code posted in your question is just placeholder to explain the problem), there's an alternate way: filtering all buttons from the subviews property and storing into an array:

var buttons = mainView.subviews.filter { $0 is UIButton } as [UIButton]

and do whatever you need with this array of UIButton, such as printing their tag.

for button in buttons {
    println(button.tag)
}
Antonio
  • 71,651
  • 11
  • 148
  • 165
  • Hi Antonio, thank you for this great reply. You are correct the println is just a placeholder. Your suggestion is exactly what I want. It even gives me more space to improve my code in the whole project. Thanks a lot. – Adaoli Oct 08 '14 at 10:21
0
for v in self.mainView.subviews as [AnyObject]
 {
   if v is UIButton{
    println (v.tag)
   }
 }
rahul_send89
  • 943
  • 8
  • 19
  • Thank you. I refered to your answered and changed a bit. It works perfect for me. :) ** for v in self.mainView.subviews as [AnyObject]{ if v is UIButton {} else {break} } ** – Adaoli Oct 08 '14 at 05:44