通过 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
}
}
}
}
我有一个单身人士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
}
}
}
}