Swift operator `subscript` []
Asked Answered
C

6

25

I am beginner with the Swift having no advance knowledge with operators.

I have the following class

class Container {
   var list: [Any] = [];
}

I want to implement the operator subscript [] in order to access the data from list.

I need something like this:

var data: Container = Container()
var value = data[5]
// also    
data[5] = 5

Also I want to be able to write something like this:

data[1][2]

Is it possible considering that element 1 from Container is an array?

Thanx for help.

Courtroom answered 11/8, 2015 at 19:16 Comment(0)
U
42

It looks like there are 2 questions here.

1. How can I enable subscripting on my own custom class?

To enable subscripting on your class Container you need to implement the subscript computed property like this.

class Container {
    private var list : [Any] = [] // I made this private

    subscript(index:Int) -> Any {
        get {
            return list[index]
        }
        set(newElm) {
            list.insert(newElm, atIndex: index)
        }
    }
}

Now you can use it this way.

var container = Container()
container[0] = "Star Trek"
container[1] = "Star Trek TNG"
container[2] = "Star Trek DS9"
container[3] = "Star Trek VOY"

container[1] // "Star Trek TNG"

2. Can I access one element of Container that supports subscripting writing something like data[1][2]?

If we use your example no, you cannot. Because data[1] returns something of type Any. And you cannot subscript Any.

But if you add a cast it becomes possible

var container = Container()
container[0] = ["Enterprise", "Defiant", "Voyager"]
(container[0] as! [String])[2] // > "Voyager"
Uitlander answered 11/8, 2015 at 19:44 Comment(0)
S
6

A workaround is to leverage multiple parameters in subscript

So instead of data[1][2], you can say data[1, 2]. This will be handy in some cases

struct Container {
  subscript(a: Int, b: Int) -> String {
    print(a)
    print(b)
    return "possible"
  }
}

let data = Container()
data[1, 2]
Sundew answered 22/6, 2016 at 12:24 Comment(0)
F
2

Swift 5.2: Subscripting in UserDefaults values - Useful Manager

Static function with generic type

class Defaults {

   static subscript<T>(key: DefaultsKey) -> T? {
      get {
        return UserDefaults.standard.value(forKey: key.rawValue) as? T
      }
      set {
        UserDefaults.standard.set(newValue, forKey: key.rawValue)
      }
    }
}

enum DefaultsKey: String {
    case firstKey = "JSGHDjasgchvsas"
}

Save value

Defaults[.firstKey] = 34

Get value

let value: Int = Defaults[.firstKey]

Happy coding!

Foxtrot answered 18/4, 2020 at 15:44 Comment(0)
B
1
class Container
{
    var list: [AnyObject] = ["hello" , "world"];
    subscript ( i : Int) -> AnyObject{
        get{
            return list[i]
        }
        set{
            list[i] = newValue
        }
    }
}

var c : Container = Container()
println(c[1])

c[1] = "lol"

println(c[1])

For more information about operator : http://nshipster.com/swift-operators/

Broker answered 11/8, 2015 at 19:43 Comment(0)
C
1

It sounds like you are looking for subscripts. You can make subscripts for your own type like the following example:

class Container {
    var list = [["Hello", "World"], ["Foo", "Bar"]]

    subscript(index: Int) -> [String] {
        get {
            return list[index]
        }
        set {
            list.insert(newValue, atIndex: index)
        }
    }
}

The above example works with the double [ ] only because I know that we are going to return an Array. Here the Array contain Strings as an example, but you could of course swap in your own type

var container = Container()

container[0][0] = "Stack"
container[0][1] = "Overflow"

print(container[0][0]) // "Stack"
print(container[1][1]) // "Bar"
Crosier answered 11/8, 2015 at 19:56 Comment(0)
N
1
class Container {
    private var list = [Any]()
    subscript(_ index: Int) -> Int? {
       get {
            guard index < list.count else { return nil }
            return list[index]
      }
       set(newValue){
          guard let unwrappedElement = newValue else { return }
          list.insert(unwrappedElement, at: index)
       }
    }
}

Here we are using subscripts with optional type to handle index out of range.

Norenenorfleet answered 29/11, 2020 at 18:15 Comment(3)
I know this is an old post (also neat solution), but shouldn't this technically cause a crash? returning nil can have unforeseen consequences and also isn't in line with the way subscripting works. at the very least it should raise an out of bounds exception or something?Fin
You quoted "but shouldn't this technically cause a crash? " Signature ``` subscript(_ index: Int) -> Int?``` says that, it will guarantee a return value, Return value can be desired request accessed or nil in case of absenceNorenenorfleet
Handling crash will definitely you want in your code.Norenenorfleet

© 2022 - 2024 — McMap. All rights reserved.