在Swift中通过下标访问Singleton属性

时间:2015-12-04 16:01:17

标签: swift singleton subscript kvc

我有一个Singleton类:

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

在网络类中,我有多个异步调用,我使用map函数为每个网址启动:

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来放弃下标但是这也没有奏效&此外,我失去了所有类型的安全。

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

2 个答案:

答案 0 :(得分:1)

你可以让你的Singleton成为一个包类。您有一个包含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
            }
        }
    }   
}

答案 1 :(得分:1)

您可以使用反射。如果你有任何进一步的问题,我通常不会经常使用它,只需谷歌快速反思'。但要注意:反射可能看起来很好但速度很慢,只适用于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
            }
        }
    }
}