Отредактированный вопрос: Как адаптировать значения словаря ДЛЯ ЧТЕНИЯ в swift?
Я хочу адаптировать значения словаря для чтения без изменения происхождения. Для этого я реализовал следующий класс.
class DictionaryView<Key, Value> where Key: Hashable {
let origin: Dictionary<Key, Value>
let map: (Value) -> Value
init(_ origin: Dictionary<Key, Value>,
map: @escaping (Value) -> Value) {
self.origin = origin
self.map = map
}
subscript(_ key: Key) -> Value?{
let value = origin[key]
return value == nil ? value : map(value!)
}
}
Но не работает, как я ожидал. Следующий код
var origin = ["A":2, "B":3]
var adapted = DictionaryView(origin, map: { $0 * 2 })
origin["C"] = 6
print(origin)
print(adapted["A"])
print(adapted["B"])
print(adapted["C"])
дает мне вывод:
["B": 3, "C": 6, "A": 2]
Дополнительно (4)
Дополнительно (6)
ноль
Мне нужна адаптация, которая будет печатать Optional (12) вместо нуля.
Как это сделать?
Оригинальный вопрос: Как адаптировать значения словаря в swift?
у меня есть словарь origin
var origin = ["A":2, "B":3]
И хотите создать новый словарь, который будет основан на origin
, но содержит двойные значения. Моим наивным решением было нанести на карту mapValues
var adapted = origin.mapValues { $0 * 2 }
Но это решение создает новый преобразованный словарь, основанный на моменте состояния origin
. Например следующий код
origin["C"] = 6
print(origin)
print(adapted)
* 1 035 * выходы
["A": 1, "B": 2, "C": 6]
["A": 2, "B": 4]
Но я хочу иметь настоящую адаптацию. Мне нужно решение, которое будет выводить результат, как показано ниже для кода, как указано выше.
["A": 1, "B": 2, "C": 6]
["A": 2, "B": 4, "C": 12]
Я новичок в Свифте и не обладаю глубокими знаниями стандартной библиотеки.
Перед тем, как начать проектирование велосипедов, я спрашиваю: каково будет общее решение этой проблемы в Swift?
Примечание 1
Я нашел проблему в реальной ситуации, но создал упрощенный пример, чтобы извлечь суть проблемы (избегать шума деталей) для текущего вопроса. Но, как я понимаю, реальная ситуация необходима, чтобы прояснить вопрос.
Мне нужно было реализовать наблюдаемый шаблон и разработать его 4 части в файле Observable.swift.
Подписка:
struct Subscription {
private let handler: () -> ()
init(cancel handler: @escaping () -> ()) {
self.handler = handler
}
func cancel() {
handler()
}
}
Наблюдатель:
struct Observer<Event> {
private let handler: (Event) -> ()
init(send handler: @escaping (Event) -> ()) {
self.handler = handler
}
func send(_ event: Event) {
handler(event)
}
}
Наблюдаемое:
class Observable<Event> {
fileprivate var observers: [UUID : Observer<Event>] = [:]
func subscribe(_ observer: Observer<Event>) -> Subscription {
let id = UUID()
observers[id] = observer
return Subscription(cancel: { self.observers[id] = nil })
}
}
Тема:
class Subject<Event> : Observable<Event> {
private(set) lazy var observer = Observer<Event>(
send: { event in
for o in self.observers.values {
o.send(event)
}})
}
Как правило, я предоставляю один экземпляр Subject as Observable вне клиентского класса и использую его как Observer внутри для хорошей инкапсуляции. Пример использования:
class Acc {
private let numberAdded: Observer<Int>
let numberDidAdd: Observable<Int>
init() {
let subject = Subject<Int>()
numberAdded = subject.observer
numberDidAdd = subject
}
func add(_ number: Int) {
numberAdded.send(number)
}
}
let acc = Acc()
acc.numberDidAdd.subscribe(Observer<Int>(send: { print($0) }))
acc.add(4)
acc.add(5)
Это решение полезно для меня в ситуации, когда мне нужно простое событие. Проблемы начались, когда мне нужно было реализовать более сложный интерфейс подписки на события. Мне нужно было предоставить словарь событий (Observables снаружи, Observers внутри). Следующий код является частью реального контекста. Нелегко описать этот контекст, но я думаю, что можно поймать его из кода.
class RealClass {
let buttonEvents = ButtonEvents()
override func viewDidLoad() {
super.viewDidLoad()
for (event, observer) in buttonEvents.observers {
someInternalSubscriptionFunc(event, observer)
}
buttonEvents.newEventTypeDidAdd.subscribe(
Observer(send: { event in
self.someInternalSubscriptionFunc(
event, self.buttonEvents.observers[event]!)
})
}
public class ButtonEvents {
private let newEventTypeAdding = Subject<UIControl.Event>()
private(set) lazy var newEventTypeDidAdd
: Observable<UIControl.Event>
= newEventsTypeAdding
private var subjects: [UIControl.Event : Subject<Point>] = [:]
fileprivate private(set) lazy var observers
: [UIControl.Event : Observer<Point>]
= subjects.mapValues({ subject in subject.observer })
public subscript(event: UIControl.Event) -> Observable<Point> {
if subjects[event] == nil {
subjects[event] = Subject<Point>()
newEventTypeAdding.send(event)
}
return subjects[event]!
}
}
}
Как мы видим, ButtonEvents.observers
- это семя проблемы.
Я могу переопределить observers
как вычисляемое свойство, но я потеряю производительность O (1) при доступе к элементам словаря.