0

I essentially want an enum of UIColors broken by which team would use them. The hope is that it could be accessed easily. Something like:

UIColor.Residential.white or UIColor.Commercial.white

The difficulty has been finding something that works in both Swift and Objective-C. Trying all manner of @objc and @objMembers in front of the extension and class declarations has stumped me. Is there a pattern for this kind of thing?

Something like the below would be ideal.

extension UIColor {

    @objc class Residential {
        static let navbarBlue = UIColor.color(hexString: "003865")
    }

    @objc class Commercial {
        static let navbarBlue = UIColor.color(hexString: "010101")
    }

}

Right now, I'm using the below, and it's working fine, but I dislike the naming duplication.

extension UIColor {

    @objc static let residentialDarkBlueNavBar = UIColor.color(hexString: "003865")
    @objc static let commercialLightBlueNavBar = UIColor.color(hexString: "0B60BB")
    @objc static let residentialBackgroundNavBar = UIColor.color(hexString: "0E49AD")
    @objc static let commercialBackgroundGray = UIColor.color(hexString: "F2F2F6")

}

Edit

The other question I've been referenced to recommends calling class methods to calculate the colors from a hex. But these are static variables that do not need to be calculated when called. Yes, the performance hit is negligible, but I'd like to access organized static variables in both Swift and ObjC without calling a method each time. If that's not possible, I'll do what the other question says. I just want to know if it is.

Thanks!

h.and.h
  • 690
  • 1
  • 8
  • 26
  • Does this answer your question? [Can objective-c code call swift extension on Class?](https://stackoverflow.com/questions/27097688/can-objective-c-code-call-swift-extension-on-class) – timbre timbre Jan 10 '20 at 17:44
  • After following the answer, check your `-Swift.h` file: if definitions are there, maybe the issue is elsewhere (e.g. maybe you didn't import `-Swift.h`) – timbre timbre Jan 10 '20 at 17:46
  • @KirilS. It's close, but I don't want to write functions for static variables, which is what the answers in the other question recommend. If that's a well-respected pattern, I'll do it, but I'd like to access static vars across Swift and ObjC, and that doesn't seem possible. – h.and.h Jan 10 '20 at 18:05

2 Answers2

1

You can't use Swift enums in Objective-C unless they declare an integer raw type so to adhere to your specifications and be available between both languages it becomes convoluted to achieve what you're asking. You will have to create an enum for each set of colors containing the RGB Int value which is then used in a class function for each color type that only accepts colors within it's associated enum. Those functions then call a function to unpack the RGB value from the int which is then used to create and return the UIColor.

The requirement to keep the colors as a hex string and use enums between both languages isn't currently possible due interoperability restrictions of enums between Swift and Obj-C.

@objc public enum Residential: NSInteger {
    case darkBlue = 14437
}

@objc public enum Commercial: NSInteger {
    case lightBlue = 745659
}

extension UIColor {

    @objc static func commercial(_ rgb: Commercial) -> UIColor {
        return UIColor.rgb(rgb.rawValue)
    }

    @objc static func residential(_ rgb: Residential) -> UIColor {
        return UIColor.rgb(rgb.rawValue)
    }

    @objc class func rgb(_ rgb: Int) -> UIColor {
        let iBlue = rgb & 0xFF
        let iGreen =  (rgb >> 8) & 0xFF
        let iRed =  (rgb >> 16) & 0xFF
        let iAlpha =  (rgb >> 24) & 0xFF
        return UIColor.init(red: CGFloat(iRed)/255, green: CGFloat(iGreen)/255,
                  blue: CGFloat(iBlue)/255, alpha: CGFloat(iAlpha)/255)

    }
}

Useage:

let residentialBlue = UIColor.residential(.darkBlue) // Swift useage

UIColor *residentialBlue = [UIColor residential:ResidentialBlue]; // Obj-C useage

Edit:

The Int to RGB code used to create the UIColor was found and modified from this SO answer.

clawesome
  • 1,223
  • 1
  • 5
  • 10
  • Close, but, like the question says, I need: `[UIColor residential.white]` and `[UIColor commercial.white]`. It's the nesting that's creating problems – h.and.h Jan 10 '20 at 18:14
  • 1
    I updated my answer with what I think will be the closest you're going to get with enums between Swift and Objective-C – clawesome Jan 10 '20 at 18:51
  • That's an impressive workaround, but it feels a bit like overkill for just storing some static UIColors :/ – h.and.h Jan 10 '20 at 18:55
  • Agreed, but it could be much more simple and straightforward if other enum types become available between the two languages. It was fun to have to try to figure out the workaround within your constraints though and there could still be a less convoluted way to do it. If you find one, please keep me updated if you don't mind. – clawesome Jan 10 '20 at 18:58
  • Will do. Nice job :) – h.and.h Jan 10 '20 at 19:11
1

So the following works:

extension UIColor {

     @objc(UIColorResidential) public class Residential: NSObject {
         @objc static let navbarBlue = UIColor.color(hexString: "003865")
     }

     @objc(UIColorCommercial) public class Commercial: NSObject {
         @objc static let navbarBlue = UIColor.color(hexString: "010101")
     }
}

Don't forget to properly import them: @class UIColorResidential, UIColorCommercial; in .h and #import "YourModule-Swift.h" in .m

timbre timbre
  • 12,648
  • 10
  • 46
  • 77