Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Swift中通过下标访问单例属性_Swift_Singleton_Subscript_Kvc - Fatal编程技术网

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

在Swift中通过下标访问单例属性,swift,singleton,subscript,kvc,Swift,Singleton,Subscript,Kvc,我有一个单身班: class Session { static let sharedInstance = Session() private init() {} // app properties var token: String! var promotions: JSON! } 在networking类中,我有多个异步调用,我使用map函数对每个url进行调用: let urls = [ "promotions": "http:..." ] let results =

我有一个单身班:

class Session {
  static let sharedInstance = Session()
  private init() {}
  // app properties
  var token: String!
  var promotions: JSON!
}
在networking类中,我有多个异步调用,我使用
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
放弃订阅,但是这也不起作用&而且我失去了所有类型安全性

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

你可以让你的单身汉成为一个包类。您有一个保存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在另一个答案中所述的反射来实现):


你可以利用反射。我不经常使用它,所以如果你有任何进一步的问题,只需谷歌“快速反应”。但要小心:反射可能看起来不错,但速度很慢,并且只适用于
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
            }
        }
    }
}
下标(属性:字符串)->任意{
得到{

对于0中的i..为什么需要下标?我猜是因为您有更多的属性,如
促销
?也不需要执行:
会话。sharedInstance[property]=newValue
只需使用:
self.[property]=newValue
然后,很明显您正在创建一个递归下标。这很好。谢谢@r-menke!@KyleGillen哪一个很棒?我选择了类似KVC的选项。考虑到我有很多属性,它看起来不那么麻烦。
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
            }
        }
    }
}