2

I am trying to create an extension method on NSLayoutAnchor to accept a multiplier. I get a weird Swift compile error (Swift 3, XCode 8.2.1) not in the extension file but in the corresponding .h file (this file is automatically generated by the compiler) for the module:

@interface NSLayoutAnchor (SWIFT_EXTENSION(MYMODULENAME))
- (NSLayoutConstraint * _Nonnull)constraintTo:(NSLayoutAnchor</* AnchorType */> * _Nonnull)anchor multiplier:(CGFloat)m;
@end

The error points to /* AnchorType */ and says: "Expected a type". Well, that makes sense since /* AnchorType */ is not a type but a comment. However I am using the AnchorType type parameter in the method signature.

The extension source code is as follows:

extension NSLayoutAnchor {
  open func constraint(to anchor: NSLayoutAnchor<AnchorType>, multiplier m: CGFloat) -> NSLayoutConstraint {
  // ...
  }
}
andrewz
  • 4,729
  • 5
  • 49
  • 67
  • This extension is in a separate module from my main project. When I move the extension code inside my main project everything works fine. This must be some sort of mixup in building the module interface. – andrewz Feb 25 '17 at 14:48

2 Answers2

6

NOTE: Fixed as of Swift 4, see benrudhart's answer below.

This is currently an issue with swift and objc. Extending objc generics in swift then bridging back into objc is not allowed. Even adding a @nonobjc doesn't fix the issue. Take a look at the bug filed here: https://bugs.swift.org/browse/SR-2708 for more info.

A potential fix is to make an extension on each concrete type of NSLayoutAnchor. The concrete types are NSLayoutXAxisAnchor, NSLayoutYAxisAnchor and NSLayoutDimension.

extension NSLayoutDimension {
    open func constraint(to anchor: NSLayoutDimension, 
             multiplier m: CGFloat) -> NSLayoutConstraint
}

extension NSLayoutXAxisAnchor {
    open func constraint(to anchor: NSLayoutXAxisAnchor, 
             multiplier m: CGFloat) -> NSLayoutConstraint
}

extension NSLayoutYAxisAnchor {
    open func constraint(to anchor: NSLayoutYAxisAnchor, 
             multiplier m: CGFloat) -> NSLayoutConstraint
}
3

As of Swift 4 this is now possible by annotating the extension with @objc. The following code will compile:

@objc extension NSLayoutAnchor {
    func constraint(to anchor: NSLayoutAnchor<AnchorType>, multiplier: CGFloat) -> NSLayoutConstraint {
        // ...
    }
}
benrudhart
  • 1,406
  • 2
  • 13
  • 25