Asyncdisplaykit: [ASControlNode] ASControlStateNormal disappears in Swift 3.0

Created on 23 Sep 2016  Â·  3Comments  Â·  Source: facebookarchive/AsyncDisplayKit

AsyncDisplayKit: master
Swift 3.0
Xcode: Version 8.0 (8A218a)

Using:
buttonNode.setBackgroundImage(image, for: .normal)
Error:
'normal' is unavailable: use [] to construct an empty option set

You can still get it to work without modifying ASDK by using:
buttonNode.setBackgroundImage(image, for: ASControlState())

While Xcode converts UIControlState's .normal to UIControlState() as well, .normal works just fine.

The reason I'm getting the error is that the generated swift code for ASControlState is:

public struct ASControlState : OptionSet {

    public init(rawValue: UInt)


    public static var highlighted: ASControlState { get } // used when ASControlNode isHighlighted is set

    public static var disabled: ASControlState { get }

    public static var selected: ASControlState { get } // used when ASControlNode isSelected is set

    public static var reserved: ASControlState { get } // flags reserved for internal framework use
}

There's no normal variable.
I believe it's because ASControlStateNormal has a value of 0, if you change the Objective-C code to:

typedef NS_OPTIONS(NSUInteger, ASControlState) {
    ASControlStateNormal       = 1 << 0,
    ASControlStateHighlighted  = 1 << 1,                  // used when ASControlNode isHighlighted is set
    ASControlStateDisabled     = 1 << 2,
    ASControlStateSelected     = 1 << 3,                  // used when ASControlNode isSelected is set
    ASControlStateReserved     = 0xFF000000               // flags reserved for internal framework use
};

Then you get the .normal option, but I'm not sure if that's a desired change.

Needs Review Swift

Most helpful comment

Thanks for raising this @george-gw. It's unfortunate – UIControlState declares UIControlStateNormal = 0 but in Swift it gets a public static var normal: UIControlState { get }. Having a "zero" option like this is not technically allowed but Apple must've made some special exception.

I think we have two choices here:

  • Do nothing. In Swift you'll have to use [] to represent an "empty" control state. Not really acceptable.
  • Investigate whether we can add an optional Swift file into ASDK that defines an extension on UIControlState that adds the static var. Ideal outcome, extremely costly and perhaps impossible.
  • Define ASControlStateNormal = 1 as you mentioned. Fixes the Swift import, but diverges from UIKit's values and creates a new "undefined" 0 state. Also it's conceptually incorrect – normal means 0 flags.
  • Replace ASControlState with UIControlState. Fixes everything, but we lose control of the enum. We could use #define ASControlState UIControlState to ease the transition.

We should do the last one. Apple has created a special exception for themselves and we should piggyback on it. The likelihood of us creating some new control state in the future is extremely low. This also eliminates code which is always nice. @appleguy @maicki could someone else weigh in?

All 3 comments

Thanks for raising this @george-gw. It's unfortunate – UIControlState declares UIControlStateNormal = 0 but in Swift it gets a public static var normal: UIControlState { get }. Having a "zero" option like this is not technically allowed but Apple must've made some special exception.

I think we have two choices here:

  • Do nothing. In Swift you'll have to use [] to represent an "empty" control state. Not really acceptable.
  • Investigate whether we can add an optional Swift file into ASDK that defines an extension on UIControlState that adds the static var. Ideal outcome, extremely costly and perhaps impossible.
  • Define ASControlStateNormal = 1 as you mentioned. Fixes the Swift import, but diverges from UIKit's values and creates a new "undefined" 0 state. Also it's conceptually incorrect – normal means 0 flags.
  • Replace ASControlState with UIControlState. Fixes everything, but we lose control of the enum. We could use #define ASControlState UIControlState to ease the transition.

We should do the last one. Apple has created a special exception for themselves and we should piggyback on it. The likelihood of us creating some new control state in the future is extremely low. This also eliminates code which is always nice. @appleguy @maicki could someone else weigh in?

Same happens with ASRelativeLayoutSpecPosition.

When using ASRelativeLayoutSpec it's not possible to define vertical or horizontal position toASRelativeLayoutSpecPosition.start. Using[] or ASRelativeLayoutSpecPosition()seems to work as .start.

The solution provided by @george-gw makes the .start appear

I know I am posting very late but here is another workaround

Add UILabel in ASButtonNode if you have same text for normal , highlight or for any state like
`ASButtonNode(viewBlock: { () -> UIView in
let lblTitle:UILabel = UILabel()
lblTitle.text="Submit"
lblTitle.textColor = Color.white
lblTitle.font = // define your font

// make label alignment center

        return lblTitle
    })

`

Was this page helpful?
0 / 5 - 0 ratings