Pitch: Expose enum properties backed by bridgeable types to Objective-C


(Charles Srstka) #1

MOTIVATION:

Many Cocoa classes which allow the user to choose from a list of items, such as NSPopUpButton, NSSegmentedControl, and NSTabView, offer the ability to bind the view to an integer or string in the model via KVO, through bindings such as “Selected Tag”, “Selected Index”, “Selected Identifier”, and the like. Since it can be tough to remember all the tags and whatnot that are associated with each view, it’s usually been helpful to create an enum to keep track of them… until now, since Objective-C cannot see Swift enums, and therefore they cannot be marked ‘dynamic’ for KVO.

One can work around that by declaring two properties, one of which wraps the other, like this:

enum SortMethod: Int {
  case byName = 0
  case bySize = 1
  case byModificationDate = 2
}

var sortMethod: SortMethod {
  willSet { self.willChangeValue(forKey: “sortMethod”) }
  didSet { self.didChangeValue(forKey: “sortMethod”) }
}

@objc(sortMethod) private dynamic var objcSortMethod: Int {
  get { return self.sortMethod.rawValue }
  set(newValue) { self.sortMethod = SortMethod(rawValue: newValue)! }
}

However, this is cumbersome.

PROPOSED SOLUTION:

I propose that if an property is typed to an enum, and that enum is backed by an Objective-C-bridgeable type, the property should be visible to Objective-C as its underlying type. So, for example, if you simply declared “var sortMethod: SortMethod” with the @objc attribute or the ‘dynamic’ keyword, it would generate the longer code shown above. This would allow easy binding of UI elements in .xib files to enums in your model.

ALTERNATIVES CONSIDERED:

We could introduce some sort of annotation allowing the user to specify a default case in the event that Objective-C tried to set the property to a value not covered in the enum, instead of just crashing. However, doing such a thing is almost always the result of a programmer error, so I do not consider this of high importance.

Charles


(Derrick Ho) #2

You can currently access swift enums from objective c provided that it is
marked @objc and inherits from Int.

Objectivec can not however access a swift enum that inherits from a string.
I've asked the community about how they feel about enabling this but there
was little to no response.

···

On Thu, Dec 15, 2016 at 1:06 AM Charles Srstka via swift-evolution < swift-evolution@swift.org> wrote:

MOTIVATION:

Many Cocoa classes which allow the user to choose from a list of items,
such as NSPopUpButton, NSSegmentedControl, and NSTabView, offer the ability
to bind the view to an integer or string in the model via KVO, through
bindings such as “Selected Tag”, “Selected Index”, “Selected Identifier”,
and the like. Since it can be tough to remember all the tags and whatnot
that are associated with each view, it’s usually been helpful to create an
enum to keep track of them… until now, since Objective-C cannot see Swift
enums, and therefore they cannot be marked ‘dynamic’ for KVO.

One can work around that by declaring two properties, one of which wraps
the other, like this:

enum SortMethod: Int {
        case byName = 0
        case bySize = 1
        case byModificationDate = 2
}

var sortMethod: SortMethod {
        willSet { self.willChangeValue(forKey: “sortMethod”) }
        didSet { self.didChangeValue(forKey: “sortMethod”) }
}

@objc(sortMethod) private dynamic var objcSortMethod: Int {
        get { return self.sortMethod.rawValue }
        set(newValue) { self.sortMethod = SortMethod(rawValue: newValue)! }
}

However, this is cumbersome.

PROPOSED SOLUTION:

I propose that if an property is typed to an enum, and that enum is backed
by an Objective-C-bridgeable type, the property should be visible to
Objective-C as its underlying type. So, for example, if you simply declared
“var sortMethod: SortMethod” with the @objc attribute or the ‘dynamic’
keyword, it would generate the longer code shown above. This would allow
easy binding of UI elements in .xib files to enums in your model.

ALTERNATIVES CONSIDERED:

We could introduce some sort of annotation allowing the user to specify a
default case in the event that Objective-C tried to set the property to a
value not covered in the enum, instead of just crashing. However, doing
such a thing is almost always the result of a programmer error, so I do not
consider this of high importance.

Charles

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Charles Srstka) #3

Not when I try it:

enum MyEnum: Int {
    case foo = 0
    case bar = 1
}
    
@objc var myEnum: MyEnum = .foo // Property cannot be marked @objc because its type cannot be represented in Objective-C

Charles

···

On Dec 15, 2016, at 12:16 AM, Derrick Ho <wh1pch81n@gmail.com> wrote:

You can currently access swift enums from objective c provided that it is marked @objc and inherits from Int.


(Charlie Monroe) #4

You can currently access swift enums from objective c provided that it is marked @objc and inherits from Int.

Not when I try it:

enum MyEnum: Int {

The @objc annotation needs to be here.

@objc enum MyEnum: Int { ... }

You can then freely do even this:

@NSManaged var enumValue: MyEnum

and it works just fine with CoreData...

···

On Dec 15, 2016, at 7:28 AM, Charles Srstka via swift-evolution <swift-evolution@swift.org> wrote:

On Dec 15, 2016, at 12:16 AM, Derrick Ho <wh1pch81n@gmail.com <mailto:wh1pch81n@gmail.com>> wrote:

    case foo = 0
    case bar = 1
}
    
@objc var myEnum: MyEnum = .foo // Property cannot be marked @objc because its type cannot be represented in Objective-C

Charles
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution