24

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.

Luca Angeletti
  • 58,465
  • 13
  • 121
  • 148
Colateral
  • 1,736
  • 2
  • 18
  • 22

6 Answers6

41

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"
Luca Angeletti
  • 58,465
  • 13
  • 121
  • 148
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]
onmyway133
  • 45,645
  • 31
  • 257
  • 263
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!

Saranjith
  • 11,242
  • 5
  • 69
  • 122
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/

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"
MortenHC
  • 495
  • 8
  • 20
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.

Roshan Sah
  • 137
  • 10
  • 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? – Chucky May 23 '21 at 19:58
  • 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 absence – Roshan Sah May 24 '21 at 07:56
  • Handling crash will definitely you want in your code. – Roshan Sah May 24 '21 at 07:58