通过 Swift 中的下标访问单例 属性

Accessing a Singleton property by subscript in Swift

我有一个单身人士class:

class Session {
  static let sharedInstance = Session()
  private init() {}
  // app properties
  var token: String!
  var promotions: JSON!
}

在网络中 class 我有多个异步调用,我使用 map 函数触发每个 url:

let urls = [ "promotions": "http:..." ]

let results = urls.map { (k, url) in
  self.getFromApi(url, params: ["token" : token]) { response in
    guard response as? JSON != nil else { return }

    Session.sharedInstance[k] = response
    // the above should compile to Session.sharedInstance["promotions"] = response.
  }

问题在于尝试通过下标设置sharedInstance 上的响应。我试图在 Singleton 上实现下标但无济于事:

subscript(property: Any) -> Any {
  get {
    return Session.sharedInstance[property]
  }
  set(newValue) {
    Session.sharedInstance[property] = newValue
  }
}

我也曾尝试通过遵守 NSObject 和使用 KVC 来放弃下标,但这也没有用,而且我失去了所有类型安全性。

非常感谢任何帮助或建议。 提前致谢。

你可以让你的单身人士成为一个包class。您有一本字典,其中包含您的 JSON 或属性。其他一切都只是计算值。

class Session {
    static let sharedInstance = Session()
    private init() {}
    // app properties
    var token: String!

    private var fetchedJSON : [String:Any] = [:]

    var keys : [String] {
        return Array(fetchedJSON.keys)
    }

    // handy to do downcasts in here
    var promotions : JSON? {
        get {
            if let promotions = fetchedJSON["promotions"] as? JSON {
                return promotions
            } else {
                return nil
            }
        }
        set(value) {
            fetchedJSON["prmotions"] = value
        }
    }

    subscript(property: String) -> Any? {
        get {
            return fetchedJSON[property]

        }
        set(newValue) {
            fetchedJSON[property] = newValue
        }
    }
}

或者创建一个有限的 KVC(这也可以通过 Oliver Borchert 的另一个答案中所述的反射来完成):

class Singleton {

    var alpha : Any?
    var beta : Any?
    var delta : Any?

    subscript(property: String) -> Any? {
        get {
            switch property {
            case "alpha" : return self.alpha
            case "beta" : return self.beta
            case "delta" : return self.delta
            default : return nil
            }
        }
        set(newValue) {
            switch property {
            case "alpha" : self.alpha = newValue
            case "beta" : self.beta = newValue
            case "delta" : self.delta = newValue
            default : return
            }
        }
    }   
}

你可以利用反射。我不经常使用它,所以如果您有任何其他问题,只需 google 'Swift reflection'。但要注意:反射可能看起来不错,但速度很慢,并且只适用于 NSObject 子类(我认为,但请随意尝试)。它的工作原理如下:

subscript(property: String) -> Any {
    get {
        for i in 0..<reflect(self).count { // loop through all properties
            if reflect(self)[i].0 == property { // find property with specified name
                return reflect(self)[i].1.summary // return property's value
            }
        }
        fatalError("no such property found")
    } set(newValue) {
        for i in 0..<reflect(self).count { // loop through all properties
            if reflect(self)[i].0 == property { // find property with specified name
                self.setValue(newValue, forKey: property) // not possible to do otherwise in Swift
                return
            }
        }
    }
}