Михаил Капелько 1 year ago
parent
commit
769ade70c9
4 changed files with 30 additions and 116 deletions
  1. +0
    -27
      src/SrcFmt.swift
  2. +17
    -0
      src/TextFieldValueOwner.swift
  3. +4
    -12
      src/V.swift
  4. +9
    -77
      src/VM.swift

+ 0
- 27
src/SrcFmt.swift View File

@@ -1,27 +0,0 @@
import Foundation

class SrcFmt: Formatter {
override func string(for obj: Any?) -> String? {
/**///print("ИГР SrcF.string obj: '\(obj)'")
guard let str = obj as? String else { return nil }
return String(str.dropFirst(2))
}

override func getObjectValue(
_ obj: AutoreleasingUnsafeMutablePointer<AnyObject?>?,
for string: String,
errorDescription error: AutoreleasingUnsafeMutablePointer<NSString?>?
) -> Bool {
/**///print("ИГР SrcF.getOV string: '\(string)'")
let val: String
if string.hasPrefix("a:") || string.hasPrefix("u:") {
/**///print("ИГР SrcF.getOV-1")
val = string
} else {
/**///print("ИГР SrcF.getOV-2")
val = "u:\(string)"
}
obj?.pointee = val as AnyObject
return true
}
}

+ 17
- 0
src/TextFieldValueOwner.swift View File

@@ -0,0 +1,17 @@
import Foundation

class TextFieldValueOwner: Formatter {
override func string(for obj: Any?) -> String? {
guard let str = obj as? String else { return nil }
return String(str.dropFirst(2))
}

override func getObjectValue(
_ obj: AutoreleasingUnsafeMutablePointer<AnyObject?>?,
for string: String,
errorDescription error: AutoreleasingUnsafeMutablePointer<NSString?>?
) -> Bool {
obj?.pointee = "u:\(string)" as AnyObject
return true
}
}

+ 4
- 12
src/V.swift View File

@@ -7,21 +7,13 @@ struct V: View {
VStack {
HStack {
Text("Check text field:")
Text("'\(vm.t3)'")
Text("'\(vm.text)'")
.fontWeight(.bold)
}
/*
TextField("Placeholder", text: $vm.text)
.padding(8)
.border(Color.red, width: 2)
TextField("Binding-2", text: vm.bt2)

TextField("Binding-3", value: $vm.text, formatter: TextFieldValueOwner())
.padding(8)
.border(Color.blue, width: 2)
*/
TextField("Binding-3", value: $vm.t3, formatter: SrcFmt())
.padding(8)
.border(Color.green, width: 4)
.border(Color.green, width: 4)
}
.frame(width: 320)
.padding()


+ 9
- 77
src/VM.swift View File

@@ -2,93 +2,25 @@ import Combine
import SwiftUI

final class VM: ObservableObject {
/*
@Published var text = ""
let changeText = PassthroughSubject<String, Never>()
@Published var t2 = "a:value"
var bt2: Binding<String>!
*/

@Published var t3 = "a:value"
@Published var text = "a:"
var subscriptions = Set<AnyCancellable>()

init() {
$t3
$text
// Исключаем конфликты от UI и App путём игнорирования спама.
.debounce(for: .seconds(0.3), scheduler: DispatchQueue.main)
.sink { v in
/**/print("ИГР VM.init t3: '\(v)'")
// Ignore repoting application initiated strings
// Only report user initiated strings
guard v.hasPrefix("u:") else { return }
Bus.send(MeetupId.Keys.meetupIdTextUI.rawValue, String(v.dropFirst(2)))
}
// Нужны лишь значения от UI.
.filter { $0.hasPrefix("u:") }
// Убираем источник.
.map { String($0.dropFirst(2)) }
.sink { Bus.send(MeetupId.Keys.meetupIdTextUI.rawValue, $0) }
.store(in: &subscriptions)

Bus.receiveAsync(
&subscriptions,
[MeetupId.Keys.meetupIdTextApp.rawValue],
{ [weak self] _, v in self?.applyFormattedValue(v) }
)


/*
bt2 = Binding<String>(
get: { [weak self] in
String(self?.t2.dropFirst(2) ?? "")
},
set: { [weak self] v in
if v.hasPrefix("a:") {
self?.t2 = v
} else {
self?.t2 = "u:\(v)"
}
}
)
$t2
.debounce(for: .seconds(0.3), scheduler: DispatchQueue.main)
.sink { v in
/**/print("ИГР VM.init t2: '\(v)'")
// Ignore repoting application initiated strings
// Only report user initiated strings
guard v.hasPrefix("u:") else { return }
Bus.Service.singleton?.send(MeetupId.Keys.meetupIdTextUI.rawValue, String(v.dropFirst(2)))
}
.store(in: &subscriptions)
Bus.receive(
&subscriptions,
[MeetupId.Keys.meetupIdTextApp.rawValue],
{ [weak self] k, v in self?.handleAppValue(k, v) }
{ [weak self] (_, v: String) in self?.text = "a:\(v)" }
)
// Интерпретируем текст с задержкой, потому что:
// 1. смена @Published в ту же секунду игнорируется
// полем ввода, т.е. нужна задержка
// 2. ожидаем окончания ввода (спама), чтобы
// обработать введённое без потерь из-за конфликта
// старых данных и новых.
$text
.debounce(for: .seconds(0.3), scheduler: DispatchQueue.main)
.sink { [weak self] v in
guard
let out = MeetupId.shouldFormat(v),
v != out
else {
return
}
/**/print("ИГР TFCVM.init changeT in/out: '\(v)'/'\(out)'")
self?.text = out
}
.store(in: &subscriptions)
*/
}
func applyFormattedValue(_ value: String) {
/**/print("ИГР VM.handleFV value: '\(value)'")
t3 = "a:\(value)"
}
}

Loading…
Cancel
Save