ide
ide

Reputation: 20808

Swift subscript setter that accepts a different type than the getter's return value

I have a custom collection that can receive values of any type and converts them to strings. For example:

collection["key"] = 10
let value = collection["key"] // value is a String

Is there a way to do this? I tried implementing two subscript methods but Swift doesn't support write-only subscripts.

subscript(key: String) -> String {
  get { ... }
}

// Doesn't compile
subscript(key: String) -> AnyObject {
  set { ... }
}

Upvotes: 0

Views: 911

Answers (4)

Jão
Jão

Reputation: 469

I was facing a similar problem here and I solved it using a generic type for my variable and returning the type I want on its getter. You can try doing something like this:

class StorageClass {
  private var _value: String?
  public var value: Any? {
    set {
      if let num = newValue as? Int {
        self._value = String(format: "%d",num)
      }
    }
    get {
      return self._value
    }
  }
}

By doing this, it is possible to do something like:

var storage = StorageClass()
storage.value = 10 /* setting value as an Integer */
let aString = storage.value as! String /* receiving a String value back */

Upvotes: 0

matt
matt

Reputation: 535586

You can use two different subscript implementations and disable the getter for one of them:

subscript(key: String) -> String {
    get { return "howdy" } // put real implementation here
}
subscript(key: String) -> AnyObject {
    get { fatalError("Oooops") }
    set { }
}

However, this still leaves open the question of how to distinguish between these two subscript calls in context. It would be better to give them different signatures through their external parameter names:

subscript(key: String) -> String {
    get { return "howdy" } // put real implementation here
}
subscript(# any: String) -> AnyObject {
    get { fatalError("Oooops") }
    set { }
}

And here's how to use it:

let m = MyClass()
m[any:"thing"] = 1
println(m["thing"]) // "1", presumably

Upvotes: 2

Asyra
Asyra

Reputation: 91

You could also define your own type and make it conform to the IntegerLiteralConvertible and the StringLiteralConvertible protocols.

Technically you could also write an extension for String to make it conform to IntegerLiteralConvertible but that might get confusing, since it will be available in your entire project.

Upvotes: 0

GoZoner
GoZoner

Reputation: 70185

Define subscript to return AnyObject (or Any as needed) and at the point you use the getter cast the result to String. You may already need to deal with subscript returning an optional so the coercion is just all part of extracting your desired value.

if let value = collection["key"] as String { ... }
else {...}

Upvotes: 0

Related Questions