Created
July 27, 2019 12:40
-
-
Save rizumita/79c235d6b1ce2b23b143835a4d69e101 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import UIKit | |
public typealias Send<A> = (A) -> () | |
public typealias Receive<A> = (A) -> () | |
public typealias Observe<A> = (@escaping Receive<A>) -> (ObserveToken) | |
public typealias OPipe<A> = (send: Send<A>, observe: Observe<A>) | |
public class ObserveToken: Hashable { | |
let uuid = UUID() | |
let receive: Any | |
init<A>(_ receive: @escaping Receive<A>) { | |
self.receive = receive | |
} | |
public func hash(into hasher: inout Hasher) { | |
hasher.combine(uuid) | |
} | |
public static func ==(_ lhs: ObserveToken, _ rhs: ObserveToken) -> Bool { | |
if lhs.uuid != rhs.uuid { return false } | |
return true | |
} | |
} | |
public func opipe<A>(_ type: A.Type = A.self) -> OPipe<A> { | |
let tokens = NSHashTable<ObserveToken>.weakObjects() | |
let observe: Observe<A> = { [weak tokens] receive in | |
let token = ObserveToken(receive) | |
tokens?.add(token) | |
return token | |
} | |
let send: Send<A> = { a in | |
tokens.allObjects.forEach { token in | |
guard let receive = token.receive as? Receive<A> else { return } | |
receive(a) | |
} | |
} | |
return (send, observe) | |
} | |
class MessageDraftViewController: UIViewController { | |
@IBOutlet weak var messageTextField: UITextField! | |
@IBOutlet weak var sendButton: UIButton! | |
var draft: MessageDraft = MessageDraft() | |
var messageTextFieldProxy: MessageDraftingProxyProtocol! | |
var messageProxy: MessageDraftingProxyProtocol! | |
var configureProxy: (MessageDraftViewController) -> () = { _ in } | |
private var observeTokens = [ObserveToken]() | |
override func viewDidLoad() { | |
super.viewDidLoad() | |
configureProxy(self) | |
observeTokens += [ | |
messageProxy.observe { [weak self] update in | |
guard let this = self else { return } | |
this.draft = update(this.draft) | |
} | |
] | |
} | |
@IBAction func sendButtonTapped(_ sender: Any) { | |
messageTextField.resignFirstResponder() | |
print(draft.message.content) | |
} | |
} | |
protocol MessageDraftViewControllerConfigureProtocol { | |
func configure(_ controller: UIViewController) | |
} | |
class MessageDraftViewControllerConfigurator: MessageDraftViewControllerConfigureProtocol { | |
func configure(_ controller: UIViewController) { | |
guard let controller = controller as? MessageDraftViewController else { fatalError() } | |
controller.configureProxy = { controller in | |
let proxy = MessageProxy() | |
controller.messageProxy = proxy | |
controller.messageTextField.delegate = proxy | |
} | |
} | |
} | |
struct Message { | |
var content: String = "" | |
} | |
struct MessageDraft { | |
var message: Message | |
init() { message = Message() } | |
} | |
protocol MessageDraftingProxyProtocol { | |
var observe: Observe<(MessageDraft) -> MessageDraft> { get } | |
} | |
class MessageProxy: NSObject, MessageDraftingProxyProtocol, UITextFieldDelegate { | |
var observe: Observe<(MessageDraft) -> MessageDraft> { return pipe.observe } | |
private var pipe: OPipe<(MessageDraft) -> MessageDraft> = opipe() | |
func textFieldDidEndEditing(_ textField: UITextField) { | |
pipe.send { draft in | |
var draft = draft | |
draft.message.content = textField.text ?? "" | |
return draft | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment