computed setter for a subscript of an array in Swi

2020-02-14 10:37发布

问题:

To keep it short, what I want to achieve is for example:

var actions: [String]{
    get{
        if (_actions==nil){
            _actions = []
        }
        return _actions!
    }
    set{
        _actions = newValue
    }
    subscript(index:Int) -> String{
      set {
         assert(index<_actions.count && index>=0, "Index out of range")
         _actions[index] = newValue
      }
    }
}

I know subscript isn't an accessor for array, but then what is the most convinient alternative to do just that?

I truly appreciate for succinct answers if possible! Thank you very much!

Edit:

To extend my explanation for @jrturton,

What I am trying to achieve is whenever actions[i] is set to a newValue, I would like to do some extra computations, such as repositioning actions[i]'s respective subview.

But if i say actions[3] = "randomMethod", the computed setter for the entire array will get called. Right? So I'd like to find a way so that when actions[3] is set to a newValue, a function repositionView(3) can get called, for example.

I know other ways to do it, but my question simply askes if there is a more convinient way, like the example above: a computed setter, to do what I want?

Edit 2:

To show @Vatsal Manot what I truly mean, I removed getter for subscript, and here is a complete example.swift(which wont run due to error):

import UIKit
import Foundation

class DWActionsSubmenu: UIView{
    var actions: [DWAction]{
        get{
            if (_actions==nil){
                _actions = []
            }
            return _actions!
        }
        set{
            _actions = newValue
        }
        subscript(index:Int) -> DWAction{
            set {
                assert(index<_actions.count && index>=0, "Index out of range")
                _actions[index] = newValue
                a()
            }
        }
    }

    var _actions: [DWAction]?

    init(actions:[DWAction]?){
        super.init()
        _actions = actions
    }

    required init(coder aDecoder: NSCoder) {
        super.init(coder:aDecoder)
    }

    func a(){

    }
}

回答1:

I'd wrap your actions list in a custom class that you can then access via subscripting. You can then add a block to be run whenever a subscripted member is set:

class ActionList {
    private var actions = [String]()

    var actionDidChange : ((Int) -> ())?

    subscript(actionIndex:Int) -> String {
        get {
            return actions[actionIndex]
        }
        set {
            actions[actionIndex] = newValue
            if let actionDidChange = actionDidChange {
                actionDidChange(actionIndex)
            }
        }
    }

    func addAction(action: String) {
        actions.append(action)
    }

    func addActions(newActions:[String]) {
        actions += newActions
    }
}

Usage (in a playground):

let actionList = ActionList()
actionList.actionDidChange = {
    actionIndex in
    println("Action \(actionIndex) did change")
}

actionList.addActions(["One", "Two", "Three"])
actionList[2] = "New"
// Prints "Action 2 did change"


回答2:

The following should work:

var actions: [String] = []

subscript(index:Int) -> String
{
    get
    {
        assert(index < actions.count && index >= 0, "Index out of range")
        return actions[index]
    }

    set(newValue)
    {
        assert(index < actions.count && index >= 0, "Index out of range")
        actions[index] = newValue
    }
}