Wondering if there's a good way to do this or not:
I have a #propertyWrapper named "Enhanced" that I use. I use the wrappedValue.set to do some actions, and I would also like to do some further actions if the property is Equatable.
Currently, the code looks like this:
#propertyWrapper
class Enhanced<T: Equatable>: Codable
{
private var value: T
var projectedValue: Enhanced<T> { self }
var wrappedValue: T
{
get { value }
set { set(newValue, notify: nil) }
}
func set(_ proposedValue: T, notify: Bool?)
{
let oldValue = value
let newValue = proposedValue
let changed = newValue != oldValue
if changed { /* more magic here */ }
value = newValue
}
}
Now I would like to remove the Equatable conformance over the generic T, but still be able to compare the old and new values IF the generic T conforms to Equatable.
I've tried a handful of techniques, all of which dead end somewhere. My latest was this:
let changed: Bool
switch T.self
{
case let equatableType as any Equatable.Type:
if
let oldEquatableValue = oldValue as? any Equatable,
let newEquatableValue = newValue as? any Equatable
{
changed = newEquatableValue != oldEquatableValue
}
default:
changed = true
}
...but the error is an understandable Binary operator '!=' cannot be applied to two 'any Equatable' operands.
I tried different patterns to cast the generic type T into an Equatable and silently fail if the generic does not conform, but even if they do, the resulting "cast" types I get back aren't equatable themselves.
Any revelations to the proper pattern would be great!
After some deep web-sleuthing, I came across a snippet of code that does the magic I need:
private extension Equatable
{
func isEqualTo(_ rhs: Any) -> Bool
{
if let castRHS = rhs as? Self
{
return self == castRHS
}
else
{
return false
}
}
}
(HT to neonichu/equalizer.swift on GitHub)
With this bit of pseudo type-erasure, I can make this work:
let changed: Bool
if let oldEquatableValue = oldValue as? any Equatable,
let newEquatableValue = newValue as? any Equatable
{
changed = oldEquatableValue.isEqualTo(newEquatableValue) == false
}
else
{
changed = true
}
By using an extension on Equatable that does further casting of the values, this allows for these two values to be compared (and fail if they are not the same).
Hope this helps someone else!
Context
I have multiple Enums conforming to a specific Protocol. I now would like to define a Custom Case for each of these Enums and use this Requirement for checking for Equality.
However, I get the following Compiler Error:
'var' binding pattern cannot appear in an expression
Code
protocol Component {
// I read that you can use this Syntax for requiring Enum Cases -> It is working!
static var default: Self { get }
static func custom(value: Int) -> Self
var customValue: Int? { get }
}
extension Component {
var customValue: Int? {
guard case .custom(let value) = self else { return nil } // Compiler Error in this Line.
return value
}
}
Question
How can I achieve my goal of not only requiring Cases but also working with them and checking for Equality?
You can't require protocol conformances to be enum's
protocol Component {
static var `default`: Self { get }
static func custom(value: Int) -> Self
var customValue: Int? { get }
}
struct C: Component {
static var `default`: C {
return C()
}
static func custom(value: Int) -> Self {
return C()
}
var customValue: Int? { 42 }
}
let c = C()
c is Component // true
And because you can't require conforming types to be enums you can't switch/case on self in a protocol extension
Let's say I have some variable with type
let someVariable: SomeType<AnotherType?>
and I am sure that this concrete instance not contain any nil of AnotherType?. Is there is general way to convert it to SomeType<AnotherType>? For example, I need this convert for use someVariable in some function.
It could go along these lines:
protocol _Optional {
associatedtype _Wrapped
func unveil() -> _Wrapped?
}
extension Optional: _Optional {
typealias _Wrapped = Wrapped
func unveil() -> _Wrapped? { return self }
}
extension SomeType where T: _Optional {
func rewrap() -> SomeType<T._Wrapped>? {
guard let _value = value.unveil() else { return nil }
return SomeType<T._Wrapped>(value: _value)
}
}
struct SomeType<T> {
let value: T
}
let someValue = SomeType<Int?>(value: 42) // SomeType<Int?>
let rewrappedValue = someValue.rewrap() // SomeType<Int>?
let forceUnwrappedValue = someValue.rewrap()! // SomeType<Int>
Specifics depend on details of the particular implementation for SomeType (I use a simplest assumption in my example).
I would like to use enum with associated values for type-safe NSNotifications:
enum Notification {
case Foo(Int)
case Bar
var rawValue: String {
switch self {
case .Foo:
return "Foo"
case .Bar:
return "Bar"
}
}
var asNSNotification: NSNotification {
let userInfo = [String: AnyObject]()
switch self {
case let .Foo(intVal):
userInfo["intVal": intVal]
default:
break
}
return NSNotification(name: rawValue, object: nil, userInfo: userInfo)
}
init?(fromNSNotification n: NSNotification) {
switch n.name {
case .Bar:
self = .Bar
case .Foo(42): // some bogus value
let realValue = n.userInfo?["intVal"] ?? 0
self = .Foo(realValue)
default:
return nil
}
}
}
This should work, but it sure is an ugly piece of code. Anyone has ideas how to make it more elegant?
EDIT: the reason why I want to use enum is to make parameters of each notification type-safe.
By "more elegant" I mean:
Simplify rawValue property (avoid having to switch)
Avoid "bogus values" when referencing enum cases with associated values in
initializer.
Anything that would reduce verbosity and improve
readability.
Okay, here's how rawValue property can be simplified:
var rawValue: String {
return Mirror(reflecting: self).children.first.flatMap({ $0.label }) ?? "\(self)"
}
It seems to me that your enum is working too hard. This should be sufficient:
enum Notification {
case Foo(Int)
case Bar
func notification() -> NSNotification {
switch self {
case Foo(let intVal):
return NSNotification(name: "Foo", object: nil, userInfo: ["IntVal":intVal])
case Bar:
return NSNotification(name: "Bar", object: nil)
}
}
}
Adding the ability to supply a non-nil object is left as an exercise for the reader.
I think I have figured out how to make the handling of NSNotifications more elegant:
enum NotificationType: String {
case Foo
case Bar
}
enum Notification {
case Foo(Int)
case Bar
// the fragile part
var type: NotificationType {
let name = Mirror(reflecting: self).children.first.flatMap({ $0.label }) ?? "\(self)"
return NotificationType(rawValue: name)!
}
var asNSNotification: NSNotification {
let name = type.rawValue
let userInfo = [String: AnyObject]()
switch self {
case let .Foo(intVal):
userInfo["intVal": intVal]
default:
break
}
return NSNotification(name: name, object: nil, userInfo: userInfo)
}
init?(fromNSNotification n: NSNotification) {
let type = NotificationType(rawValue: n.name)!
switch type {
case .Bar:
self = .Bar
case .Foo:
let value = n.userInfo?["intVal"] ?? 0
self = .Foo(value)
default:
return nil
}
}
}
This solution relies on the convention that case names in Notification and NotificationType are the same. One might say that such design is fragile, but I think this is little tradeoff compared to what we achieve.
Below is a little helper class to handle subscription/unsubscription:
protocol NotificationReceiving: class {
func didReceiveNotification(notification: Notification)
}
class NotificationReceiver {
private weak var delegate: NotificationReceiving?
private(set) var subscriptions = Set<NotificationType>()
init(delegate: NotificationReceiving?) {
self.delegate = delegate
}
func subscribe(notificationTypes: NotificationType...) {
let nc = NSNotificationCenter.defaultCenter()
let doSubscribe: NotificationType -> Void = {
nc.addObserver(self, selector: "handleNotification:", name: $0.name, object: nil)
self.subscriptions.insert($0)
}
notificationTypes.forEach(doSubscribe)
}
func unsubscribe(notificationTypes: NotificationType...) {
let nc = NSNotificationCenter.defaultCenter()
if notificationTypes.isEmpty {
nc.removeObserver(self)
} else {
let doUnsubscribe: NotificationType -> Void = {
nc.removeObserver(self, name: $0.name, object: nil)
self.subscriptions.remove($0)
}
notificationTypes.forEach(doUnsubscribe)
}
}
#objc private func handleNotification(notification: NSNotification) {
if let n = Notification(fromNSNotification: notification) {
delegate?.didReceiveNotification(n)
}
}
}
This is how a client might look:
class Client: NotificationReceiving {
private var receiver: NotificationReceiver!
init() {
receiver = NotificationReceiver(delegate: self)
receiver.subscribe(.Foo, .Bar)
}
deinit {
receiver.unsubscribe()
}
func didReceiveNotification(notification: Notification) {
switch notification {
case let .Foo(val):
print("foo with val: \(val)")
// this notification is one-shot:
receiver.unsubscribe(.Foo)
case .Bar:
print("bar!")
}
}
}
Not sure handling all notifications in one method is good design (I guess it might get messy when there are many notifications), but the point is that we can now use the power of type safety and pattern matching, which is awesome.
Swift documentation says that classes, structs, and enums can all conform to protocols, and I can get to a point where they all conform. But I can't get the enum to behave quite like the class and struct examples:
protocol ExampleProtocol {
var simpleDescription: String { get set }
mutating func adjust()
}
class SimpleClass: ExampleProtocol {
var simpleDescription: String = "A very simple class."
var anotherProperty: Int = 69105
func adjust() {
simpleDescription += " Now 100% adjusted."
}
}
var a = SimpleClass()
a.adjust()
let aDescription = a.simpleDescription
struct SimpleStructure: ExampleProtocol {
var simpleDescription: String = "A simple structure"
mutating func adjust() {
simpleDescription += " (adjusted)"
}
}
var b = SimpleStructure()
b.adjust()
let bDescription = b.simpleDescription
enum SimpleEnum: ExampleProtocol {
case Base
var simpleDescription: String {
get {
return "A Simple Enum"
}
set {
newValue
}
}
mutating func adjust() {
self.simpleDescription += ", adjusted"
}
}
var c = SimpleEnum.Base
c.adjust()
let cDescription = c.simpleDescription
I haven't figured out how to get the simpleDescription to change as a result of calling adjust(). My example obviously won't do that because the getter has a value hard-coded, but how can I set a value for the simpleDescription while still conforming to the ExampleProtocol?
This is my attempt:
protocol ExampleProtocol {
var simpleDescription: String { get }
mutating func adjust()
}
enum ExampleEnum : ExampleProtocol {
case Base, Adjusted
var simpleDescription: String {
return self.getDescription()
}
func getDescription() -> String {
switch self {
case .Base:
return "A simple description of enum"
case .Adjusted:
return "Adjusted description of enum"
}
}
mutating func adjust() {
self = ExampleEnum.Adjusted
}
}
var c = ExampleEnum.Base
c.adjust()
let cDescription = c.simpleDescription
Here is my take at it.
As this is an enum and not a class, you have to think different(TM): it is your description that has to change when the "state" of your enum changes (as pointed out by #hu-qiang).
enum SimpleEnumeration: ExampleProtocol {
case Basic, Adjusted
var description: String {
switch self {
case .Basic:
return "A simple Enumeration"
case .Adjusted:
return "A simple Enumeration [adjusted]"
}
}
mutating func adjust() {
self = .Adjusted
}
}
var c = SimpleEnumeration.Basic
c.description
c.adjust()
c.description
Hope that helps.
Here's another approach, using only the knowledge gained from the tour until that point*
enum SimpleEnumeration: String, ExampleProtocol {
case Basic = "A simple enumeration", Adjusted = "A simple enumeration (adjusted)"
var simpleDescription: String {
get {
return self.toRaw()
}
}
mutating func adjust() {
self = .Adjusted
}
}
var c = SimpleEnumeration.Basic
c.adjust()
let cDescription = c.simpleDescription
If you want to have adjust() act as a toggle (although there's nothing to suggest this is the case), use:
mutating func adjust() {
switch self {
case .Basic:
self = .Adjusted
default:
self = .Basic
}
}
*(Although it doesn't explicitly mention how to specify a return type and a protocol)
Here's a solution that doesn't change the current enum value, but their instance values instead (just in case it is useful to anyone).
enum ProtoEnumeration : ExampleProtocol {
case One(String)
case Two(String)
var simpleDescription: String {
get {
switch self {
case let .One(desc):
return desc
case let .Two(desc):
return desc
}
}
}
mutating func adjust() {
switch self {
case let .One(desc):
self = .One(desc + ", adjusted 1")
case let .Two(desc):
self = .Two(desc + ", adjusted 2")
}
}
}
var p = ProtoEnumeration.One("test")
p.simpleDescription
p.adjust()
p.simpleDescription
It is not possible to define variables without getter and setter in enums and therefore it is impossible to have a variable that you can modify.
You can conform to the protocol but you cannot have same behavior with mutating as in classes.
It is a link about enum in swift.
Structures and enumerations are value types. By default, the properties of a value type cannot be modified from within its instance methods. link
Then, you have to use mutating function.
enum ProtocolEnum: ExampleProtocol {
case on, off
var simpleDescription: String {
switch self {
case .on:
return "Switch is ON"
case .off:
return "Switch is OFF"
}
}
mutating func adjust() {
switch self {
case .on:
self = off
case .off:
self = on
}
}
}
var c = ProtocolEnum.on
c.simpleDescription
c.adjust()
let cDescription = c.simpleDescription
Another option is for adjust() to flip between cases as follows:
enum SimpleEnum: ExampleProtocol {
case Foo, Bar
var simpleDescription: String {
get {
let value = self == .Foo
? "Foo"
: "Bar"
return "A simple \(value) enum."
}
}
mutating func adjust() {
self = self == .Foo
? .Bar
: .Foo
}
}
Here's building on Jack's answer:
protocol ICanWalk {
var description: String { get }
mutating func stepIt()
}
enum TwoStepsForwardThreeStepsBack: Int, ICanWalk {
case Base = 0, Step1, Step2
var description: String {
return "Step \(self.rawValue)"
}
mutating func stepIt() {
if let nextStep = TwoStepsForwardThreeStepsBack( rawValue: self.rawValue + 1 ) {
// going forward.
self = nextStep
} else {
// back to the base.
self = TwoStepsForwardThreeStepsBack.Base
}
}
}
I came up with this
protocol ExampleProtocol {
var simpleDescription: String { get }
mutating func adjust()
}
enum Seat: ExampleProtocol {
case WindowSeat, MiddleSeat, AisleSeat
var simpleDescription : String {
switch self {
case .WindowSeat:
return "Window Seat"
case .MiddleSeat:
return "Middle Seat"
case .AisleSeat:
return "Aisle Seat"
}
}
mutating func adjust() {
switch self {
case .WindowSeat:
self = .MiddleSeat
case .MiddleSeat:
self = . AisleSeat
case .AisleSeat:
self = .WindowSeat
}
}
}
var seat = Seat.MiddleSeat
print(seat.simpleDescription) // Middle Seat
seat.adjust()
print(seat.simpleDescription) // Aisle Seat
Another variation: Using associated values to hold and display previous option
(of the form "Selected 1, adjusted from 2, adjusted from 1, adjusted from 2, adjusted from 1")
protocol ExampleProtocol {
var simpleDescription: String { get }
mutating func adjust()
}
indirect enum EnumWithDescription: ExampleProtocol {
case option1(EnumWithDescription?)
case option2(EnumWithDescription?)
var simpleDescription: String {
return "Selected " + getDescription()
}
internal func getDescription() -> String {
var currentValue: String
let previousValue : EnumWithDescription?
switch self {
case .option1(let previous):
currentValue = "1"
previousValue = previous
case .option2(let previous):
currentValue = "2"
previousValue = previous
}
if let adjustedFrom = previousValue?.getDescription() {
return "\(currentValue) adjusted from \(adjustedFrom)"
}
else {
return "\(currentValue)"
}
}
mutating func adjust() {
switch self {
case .option1:
self = .option2(self)
case .option2:
self = .option1(self)
}
}
}
var d = EnumWithDescription.option1(nil)
d.simpleDescription
d.adjust()
d.adjust()
d.simpleDescription
// Output: "Selected 1, adjusted from 2, adjusted from 1, adjusted from 2, adjusted from 1"
here's my code
enum SimpleEnum: ExampleProtocol {
case Base, Adjusted
var simpleDescription: String {
get {
var description = "A simple enum."
switch self {
case .Base:
return description
case .Adjusted:
return description + " - [adjusted]"
}
}
}
mutating func adjust() {
self = SimpleEnum.Adjusted
}
}
var simpleEnum = SimpleEnum.Base
simpleEnum.adjust()
simpleEnum.simpleDescription
My first contribution here:
enum SimpleEnum: ExampleProtocol {
case Basic(String), Adjusted(String)
init() {
self = SimpleEnum.Basic("A simple Enum")
}
var simpleDescription: String {
get {
switch self {
case let .Basic(string):
return string
case let .Adjusted(string):
return string
}
}
}
mutating func adjust() {
self = SimpleEnum.Adjusted("full adjusted")
}
}
var c = SimpleEnum()
c.adjust()
let cDescription = c.simpleDescription
Thanks for others!
This experiment threw me off too, due to the previous SimpleClass and SimpleStructure examples showing the property simpleDescription being modified internally, which caused me to think that I needed to do the same thing. After looking over the other answers posted here and reading the official Apple Swift 2.1 documentation, I came up with this:
protocol ExampleProtocol {
var simpleDescription: String { get }
mutating func adjust()
}
enum SimpleEnum: ExampleProtocol {
case Simple
case Adjusted
var simpleDescription: String {
switch self {
case .Simple:
return "A simple enumeration"
case .Adjusted:
return "A simple enumeration somewhat changed."
}
}
mutating func adjust() {
self = .Adjusted
}
mutating func restore() {
self = .Simple
}
}
var d: SimpleEnum = .Simple
d.simpleDescription
d.adjust()
d.simpleDescription
d.restore()
d.simpleDescription
Also notice that in the examples given by Apple for SimpleClass and SimpleStructure prior to this experiment, the simple description is lost internally - you cannot get the original value back (unless of course you save it outside of the class/structure); this is what prompted me to create a restore() method for the SimpleEnum example, which allows you to toggle it back and forth between values. Hope this is useful to someone!
I was thinking that the goal is simply to retain state and use a description to make the current state easier to read:
enum SimpleEnum: ExampleProtocol {
case Default, Adjusted
init() {
self = .Default
}
var simpleDescription: String { get { return "\(self) Value" }}
mutating func adjust() {
self = .Adjusted
}
}
var simpleEnum = SimpleEnum()
simpleEnum.adjust()
let adjustedSimple = simpleEnum.simpleDescript
how about this
enum SimpleEnum : ExampleProtocol {
case Desc(String)
init() {
self = Desc("a simple enum")
}
var simpleDescription:String {
get {
return (Mirror(reflecting: self).children.first!.value as? String)!
}
}
mutating func adjust() {
self = SimpleEnum.Desc(self.desc + " adjusted")
}
}
var e = SimpleEnum()
e.simpleDescription # => "a simple enum"
e.adjust()
e.simpleDescription # => "a simple enum adjusted"