2015-12-04 5 views
0

У меня есть класс Singleton:доступ к свойству Singleton по индексу в Swift

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

В классе сетей у меня есть несколько асинхронных вызовов, которые я выпалить используя 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 однако это также не работает & кроме того я потеряю все типы безопасность.

Любая помощь или совет очень ценится. Спасибо заранее.

+0

для чего нужен индекс? Я предполагаю, потому что у вас есть гораздо больше свойств, таких как «акции»? –

+0

также не нужно: 'Session.sharedInstance [property] = newValue' just use:' self. [Property] = newValue' Тогда также становится ясно, что вы создаете рекурсивный индекс. –

ответ

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 (это также может быть сделано путем отражения, как указано в другом ответе Оливера Борхерт):

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 
      } 
     } 
    } 
} 
+0

Это замечательно. Спасибо @ r-menke! –

+0

@ KyleGillen, который отлично? –

+0

Я пошел с вариантом KVC. Учитывая, что у меня есть немало свойств, это казалось менее громоздким. –

1

Вы можете использовать отражение. Я не использую это часто, поэтому, если у вас есть какие-то дополнительные вопросы, просто «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 
      } 
     } 
    } 
}