è¯ãäžæ¥ã ãã®èšäºã¯ãæ¯æ¥ã€ã³ã¿ãŒãã§ã€ã¹ã®ããŒã¿ã®å€åã«èŠåŽããŠãã人ãMVVMã®ååšããŸã ç¥ããªã人ãããã³iOSã¢ããªã±ãŒã·ã§ã³ã®éçºæã«ãã®ãã¿ãŒã³ãå®éã«ããŸãé©çšã§ããããšãçã人ã«åœ¹ç«ã¡ãŸãã ç«ã®äžã§èå³ãæã£ãŠãã ããã
æè©ã®æãšèæ¯èªåãçµéšè±å¯ãªiOSéçºè
ãšåŒã¶ããšã¯ã§ããŸããã iOSã®äžçãšã®ç¥ãåãã¯æ°å¹Žåã«è¡ãããŸããããiOSåãã¢ããªã±ãŒã·ã§ã³ã®éçºã«åãå
¥ããããšããèŠæãæè¿çŸããŸããã ç§ã®éã¯åä»ã§ããã Obj-Cã¯ããã«ã¯æå¿ããŸããã§ããã䜿ãæ
£ãããã®ã§ã¢ããªã±ãŒã·ã§ã³ãéçºãããã£ãã®ã§ãã ãããã£ãŠãPhoneGapãApcelerator Titaniumã䜿çšãããŸãããããã ãã§ãã ããããåœç¶ã®ããšãªããããããã®åãçµã¿ããã¯äœãçãŸããŸããã§ããã é·ãäŒæ©ã®åŸãç§ãåããŠããäŒç€Ÿã¯ãã¢ãã€ã«ã¢ããªã±ãŒã·ã§ã³ã®éçºã«ã€ããŠçå£ã«èããŸããã ç§ã¯äœãçºæããã人çãåçŽåããŸããã§ããããµãŒãããŒãã£ã®ãã¬ãŒã ã¯ãŒã¯ã䜿çšããã«ãObjCã®ã¿ã§äœæ¥ãè¡ããŸããã ãããŠãããã¯ç§ã«ãšã£ãŠèŠçã§ããã åçŽãªããšãè€éã§ããããšã倿ããèªåã¬ã€ã¢ãŠãã«å¯ŸåŠã§ãããã³ãŒããèŠãããšãã§ããŸããã§ããã ãããã£ãŠã次ã®ãããžã§ã¯ãã§ã¯ãXamarin Formsãéå§ãããŸããã ãããžã§ã¯ãã§çŽ2ãæäœæ¥ããåŸããã®æè¡ã¯ãŸã å®å
šã«ã¯ã»ã©é ãããšãæããã«ãªããŸããïŒæçµçã«ã¯ãããžã§ã¯ããããŒã¿ç¶æ
ã§ããããšã倿ããŸããããããã«ã€ããŠã¯ããŸãèšåãããŠããŸããã§ããïŒã ããããXamarin Formsã䜿çšããŠããéããã®ãããžã§ã¯ãã飜åããŠããå€ãã®ãã¿ãŒã³ã«è§ŠçºãããŸãã;ããã«ãã«ã¹ã¿ã ã³ã³ããŒãã³ãã倧éã«äœæããå¿
èŠããã£ããããUIKitã®åäœãããæç¢ºã«çè§£ããããšãã§ããŸããã ãã®ç¬éããããžã§ã¯ãããã€ãã£ãã«æžãçŽãå¿
èŠãããããšãæããã«ãªã£ããšããSwiftã¯æ¥éã«ãªãªãŒã¹ã«è¿ã¥ããŠããŸããã ç§ã¯ãã®èšèªã®æ¬ãèªã¿ãæåããããçŽãããšãã§ããèªåã®åŒ·ããæããŸããã ããããæåã®äœéšã¯ãŸã èªåã飿³ããããã®ã ã£ãã®ã§ãiOSã§MVVMãæ¢ãå§ããŸããã ç§ã¯ãã®ã³ã³ã»ãããæ¬åœã«å¥œãã§ããã
åœæãç§ã®ç®ã«çãŸã£ãèšäºã¯ãã¹ãŠãReactiveCocoaã䜿çšããŠåé¡ã解決ããããšãææ¡ããŸããã ãã®ã©ã€ãã©ãªã®ã³ãŒããµã³ãã«ãèŠããšãç§ã¯ãŸã å匷ããªããã°ãªããªãããšã«æ°ä»ããŸããã ç§ã¯äœãèŠãã®ãåãããªãã£ãã Swiftã«ã€ããŠã¯ãReactiveCocoaã®äœ¿çšãææ¡ããŸããã å®éãColin Eberhardtã®
èšäºãç§ã®åºçºç¹ã§ããã ãããããã«ãåè¿°ã®èè
ã説æããã¢ãããŒããã¡ã¢ãªãªãŒã¯ã«ã€ãªãã£ããšããäºå®ã«çŽé¢ããªããã°ãªããŸããã§ããã ã©ãããç§ã¯äœãééã£ãããšãããŠããŠãããããäœãæ£ç¢ºã«çè§£ããªãã£ãããã§ãã ããã«ãReactiveCocoaã¯ç§ã«ãšã£ãŠãã©ãã¯ããã¯ã¹ã®ãŸãŸã§ããã ãã¥ãŒã¢ãã«ãšãã¥ãŒããªã³ã¯ããããã ãã«äœ¿çšãããããšãèãããšããã®ã©ã€ãã©ãªãåé€ããããšã決å®ãããŸããã ãã€ã³ãã£ã³ã°ã®åé¡ã解決ãã
Observable Swiftãããžã§ã¯ãã«åºäŒããŸããã ããã«ç§ãã¡ã®ãããžã§ã¯ããå®äºããå°å¹³ç·äžã§æ°ãããããžã§ã¯ãã宿ããŸãããç§ã¯ããã培åºçã«æºåãããã£ãã®ã§ãã
åé¡ã®å£°æ
çŸæç¹ã§ã¯ãMVVMãUIKitã«å®å
šã«å°å
¥ããæ¹æ³ãæ³åããããšã¯ã§ããŸããã ããã¯ãXamarin Formsã§èŠãMVVMã®ããšã§ããšãŠãæéãåããŸããã ã»ãšãã©ã®å Žåããã®ããã«UIKitã®äžã«ãã¬ãŒã ã¯ãŒã¯ãèšè¿°ããéçºè
ããã®ãã¬ãŒã ã¯ãŒã¯ã«ãã€ã³ãããå¿
èŠããããŸãã æµæãæãå°ãªãçµè·¯ããã©ããŸããAppleãæäŸãããã®ã䜿çšããŸãã ãã ããåæã«ãUIã®ãã宣èšçãªèšè¿°ã«åªããŸãã
MVVMã«æ¹ãããæåã§æãéèŠãªããšã¯ãViewModelãšViewã®åçãªã³ã¯ã§ããã ããã«ããããã¬ãŒã³ããŒã·ã§ã³ããåé¢ããŠããžãã¹ããžãã¯ãèšè¿°ããããšãã§ããŸãã ViewControllerã§ã®ããžãã¯ã®èšè¿°ã«ã¯ãã§ã«æ
£ããŠããŸãã ãããŠãããã¯æ¬åœã«å°çã§ãã ViewControllerã®ã³ãŒããæå°éã«æããããšãç®æããŸãããã æåã«ãViewModelã®ç¶æ
ã倿Žããããã®å€æŽãUIã«åæ ãããå¿
èŠãããããšãçè§£ããå¿
èŠããããŸãã Appleã¯ãããšãã°KVOã®äœ¿çšãææ¡ããŠããŸãã ReactiveCocoaã¯ãã®ã¿ã¹ã¯ãç°¡çŽ åããŸãã ããããSwiftããããŸãã ãããŠãç§ãã¡ã¯ã§ããã ãã·ã³ãã«ã§ã¯ãªãŒã³ãªæ±ºæãããããšèããŠããŸãã ååããã®åé¡ã解決ããæ¹æ³ã以äžã«ç€ºããŸãã
ãšããã§ã
Reactive Cocoa 3.0ã®ä»åŸã®ãªãªãŒã¹ãå¿ããªãã§ãã ããã ãããã
Bondã©ã€ãã©ãªã¯ç§ãã¡ã®ã¿ã¹ã¯ã«æãé©ããŠããŸãã ç§ã以äžã«ç€ºããã®ã«åãçµãã§ããéã
ãã³ãã¯ã¡ããã©å§ãŸã£ãã°ããã§ãç§ã®èŠä»¶ã«é©åããŸããã§ããã ä»ã§ãããã¯åœŒãã«å°ãã¯åããŸãããå ããŠãéçºè
ãäœããã®åœ¢ã§ãã¹ãŠãè€éã«ããŠããããã«æããŸããã ãã¹ãŠãå¯èœãªéãç°¡çŽ åãããã£ãã ããããå®ã¯ãããŒã¿ã衚çŸã«é¢é£ä»ããæ¹æ³ã«ã€ããŠã®ããžã§ã³ã«åãçµãã§ãããšãã«è¡ãæ¢ãŸãã«ãªã£ããšãã
ãã³ããœãŒã¹ã§çããèŠã€ãç¶ããŸããã
ãã€ãããã¯
å°ããããšããå§ããŸããããåæã«ãæãéèŠãªããšããå§ããŸãããã 倿°ã®ç¶æ
ã®å€åã«ã€ããŠåŠã³ãäœããã®åœ¢ã§ãããã®å€åã«åå¿ã§ããå¿
èŠããããŸãã ç§ãã¡ã¯ã·ã³ãã«ããšç°¡æœãã®ããã«åªåããŠããããšãæãåºãããŠãã ããã ãããŠãã®å Žåãã¹ãŠã£ããã¯ãã®æ å
ã®ãã¹ãŠã«çŸããŸãã ãžã§ããªãã¯ãé©ãã¹ãæ§æãæã€ã©ã ãã芳枬å¯èœãªããããã£ãæäŸããŸãã ããã§äœããäœããŸãããã
class Dynamic<T> { init(_ v: T) { value = v } var value: T { didSet { println(value) } } }
ããã§ãå€
valueã®å€åãç£èŠããæ©äŒããã
ãŸã ã å®éã«ã¯ã次ã®ããã«ãªããŸãã
let dynamicInt: Dynamic<Int> = Dynamic(0) println(dynamicInt.value) dynamicInt.value = 1 dynamicInt.value = 17
å¯å€ãšã³ãã£ãã£ã®ãªã¹ããŒãµããŒãã远å ããŸãã ãªã¹ããŒã¯å¿å颿°ã«ãªããåŒæ°ã«æ°ããå€
valueãæž¡ã
ãŸã ã
class Dynamic<T> { typealias Listener = T -> () private var listeners: [Listener] = [] init(_ v: T) { value = v } var value: T { didSet { for l in listeners { l(value) } } } func bind(l: Listener) { listeners.append(l) l(value) } func addListener(l: Listener) { listeners.append(l) } }
addListenerã¡ãœããã¯ããªã¹ããŒã®ãªã¹ãã«ãã³ãã©ãŒã远å ããã ãã§ã
bindã¡ãœãããåãããšãè¡ããŸããã远å ããããªã¹ããŒãããã«åŒã³åºããŠãçŸåšã®
å€ãæž¡ã
ãŸã ã
let dynText: Dynamic<String> = Dynamic("") dynText.bind { someLabel.text = $0 } dynText.addListener { otherLabel.text = $0 } dynText.value = "New text"
ãžã§ããªãã¯ã䜿çšããŠãããããããŒã¿åã確èªããããã£ã¹ããããããå¿
èŠã¯ãããŸããã ã³ã³ãã€ã©ãŒããããè¡ããŸãã ããšãã°ã次ã®å Žåãã³ãŒãã¯ã³ã³ãã€ã«ãããŸããã
let dynInt: Dynamic<Int> = Dynamic(0) dynInt.bind { someLabel.text = $0 }
ã³ã³ãã€ã©ã¯ããªã¹ããŒã®åŒæ°ã
Intåã§ããããšãèªèããŠããããã®ãã£ãŒã«ãã®åã
Stringã§ããããããã®åŒæ°ã®å€ã
UILabelã¯ã©ã¹ã®ãªããžã§ã¯ãã®
ããã¹ããã£ãŒã«ãã«å²ãåœãŠãããšã¯ã§ããŸããã ããã«ãå¿å颿°ã®åçŽåãããæ§æã®ãããã§ãäžå¿
èŠãªèšè¿°ãããã«ãªã¹ããŒã远å ããããšãã§ããŸããã ããããå®ç§ã«å¶éã¯ãããŸããã ããã€ãã®æŒç®åãå®çŸ©ããããã³ãŒããããã«åæžããç®çã§äœ¿çšå¯èœãªæŒç®åããªãŒããŒããŒãã§ããŸãã
func >> <T>(left: Dynamic<T>, right: T -> Void) { return left.addListener(right) } infix operator >>> {} func >>> <T>(left: Dynamic<T>, right: T -> Void) { left.bind(right) }
let dynText: Dynamic<String> = Dynamic("") dynText >>> { someLabel.text = $0 } dynText >> { otherLabel.text = $0 } dynText.value = "New text"
ææãããŠããªãã匱ãããã€ããšãã€ãã«ã€ããŠã®èãïŒå®éã«ã¯ãäžèšã®äŸã§ã¯ã¡ã¢ãªãªãŒã¯ãçºçããŸãã 以äžã«äŸã瀺ããŸãã
class MyViewController: UIViewController { @IBOutlet weak var label: UILabel! let viewModel = MyViewModel() override func viewDidLoad() { viewModel.someText >>> { self.label.text = $0 } super.viewDidLoad() } }
æããã«ãä»ã§ã¯ãªã¹ããŒé¢æ°ãš
selfã¯äºãã«å³å¯ã«æ¥ç¶ãããŠããã
MyViewControllerã¯ã©ã¹
ãªããžã§ã¯ãã¯æ±ºããŠ
åé€ãããŸããã ãããé²ãã«ã¯ãæ¥ç¶ãç·©ããå¿
èŠããããŸãã
viewModel.someText >>> { [unowned self] in self.label.text = $0 }
è¯ãã§ã ããããäžã€ã ããããŸãã
MyViewControllerãªããžã§ã¯ãã®åé€åŸã«ãªã¹ããŒé¢æ°ãåŒã³åºãããªããšããä¿èšŒã¯ãããŸããã èªåèªèº«ãä¿è·ããããã«ã
weakã䜿çšããŸãã
viewModel.someText >>> { [weak self] in self?.label.text = $0 }
ãã ãããã®å Žåãã³ãŒãã¯ã³ã³ãã€ã«ãããŸããã ãªã¹ããŒã®ã¿ã€ãã¯
String-> VoidïŒ ããã ããæ£åžžãªã³ã³ãã€ã«ã®ããã«ã¯
String-> Voidåã§ãªããã°ãªããŸããã ãããã£ãŠãæåã«
Dynamicã« 2çš®é¡ã®ãªã¹ããŒã远å ããŸãããæ»ãå€VoidãšVoidïŒ..ãããã£ãŠã
bind ã¡ãœãããš
addListenerã¡ãœããããªãŒããŒããŒãããŠã2çš®é¡ã®ãªã¹ããŒããµããŒãããŸããã ããããããšãã°æ¬¡ã®å Žåãã³ã³ãã€ã©ã¯ã©ã®ã¡ãœãããåŒã³åºãããæ±ºå®ã§ããªãããšãããã«æããã«ãªããŸããã
viewModel.someText >>> { [weak self] in if self != nil { self!.label.text = $0 } }
ãããã£ãŠã2çš®é¡ã®ãªã¹ããŒããµããŒããããšããèããæšãŠããã®ãããªããªãã¯ã掻çšããå¿
èŠããããŸããã
viewModel.someText >>> { [weak self] in self?.label.text = $0; return } viewModel.someText >>> { [weak self] in self?.label.text = $0; () } viewModel.someText >>> { [weak self] v in v; self?.label.text = v }
ãã¡ããããã³ãã©ãŒé¢æ°ã«å ããŠããªããžã§ã¯ããžã®åç
§ã«å ããŠãåçãªããžã§ã¯ããæž¡ãããã«
weakã䜿çšããããšãæåŠãããªããžã§ã¯ããçªç¶åé€ãããå Žåã颿°ãåŒã³åºãããšã¯ã§ããŸããã
Bondã©ã€ãã©ãªã§äœ¿çšãããã®ã¯ãã®ã¢ãããŒãã§ãã ããããããã¯ç§ã®ããæ¹ã§ã¯ãããŸããã§ãã:)
UIKitã䜿çšããäœæ¥ã®ç°¡çŽ å
åæããŸããããã¹ããšUILabelããªã³ã¯ããããã«åãã©ã ããåžžã«èª¬æããã®ã¯äžå¿«ã§ãã ã·ã³ãã«ã«ãããïŒ
viewModel.someText >>> label
äžå¯èœã¯ãããŸããã çµå±ããã®ãããªæ§æã«ç°¡åã«å°éã§ããŸãã å®è£
ã¢ã€ãã¢ã¯åã³
Bondãã芪åã«åããããŸããã ã¢ã€ãã¢ã¯ç°¡åã§ãããªã¹ããŒãæã€ãã£ãŒã«ããäœããã®ãªããžã§ã¯ãã«ä¿åãããã®ãªã¹ããŒãåçãªããžã§ã¯ãã«ãã€ã³ãã§ããŸãã
final class PropertyModifier<T> { typealias Modifier = (T) -> () let modifier: Modifier init (_ l: Modifier) { self.modifier = l } }
PropertyModifierã¯ã©ã¹ã®ãªããžã§ã¯ãã¯ãã¥ãŒèªäœã«ãã£ãŠäœæãããã©ã ãã¯ãã¥ãŒã®ç¹å®ã®ãã£ãŒã«ãã®å€ã倿Žããã³ãŒããšãšãã«ã³ã³ã¹ãã©ã¯ã¿ãŒã«æž¡ãããŸãã
private var UILabelPropertyKeyTextModifier: UInt8 = 0 extension UILabel { var textModifier: PropertyModifier<String?> { if let pm: AnyObject = objc_getAssociatedObject(self, &UILabelPropertyKeyTextModifier) { return pm as PropertyModifier<String?> } else { let pm = PropertyModifier<String?> { [weak self] in self?.text = v; () } objc_setAssociatedObject(self, &UILabelPropertyKeyTextModifier, pm, objc_AssociationPolicy(OBJC_ASSOCIATION_RETAIN_NONATOMIC)) return pm } } }
æ¡åŒµã§ã¯ãä¿åããããã£ãŒã«ããèšè¿°ããããšãã§ããªããããObjCã©ã³ã¿ã€ã ãšé¢æ°
objc_setAssociatedObject ã
objc_getAssociatedObjectã å©ãã«
ãªããŸã ã ãããè¡ãããšãã§ããŸãïŒ
viewModel.someText >>> label.textModifier.modifier
ç°¡åã«ããŸãããïŒ
func >> <T>(left: Dynamic<T>, right: PropertyModifier<T>) { left.addListener(right.modifier) } func >>> <T>(left: Dynamic<T>, right: PropertyModifier<T>) { left.bind(right.modifier) } viewModel.someText >>> label.textModifier
ã¯ããã«è¯ãã ããããããã ãã§ã¯ãããŸããã ãã¥ãŒã®æã䜿çšãããŠããããããã£ã®äžéšã匷調衚瀺ããããã©ã«ãã§
PropertyModifierãå²ãåœãŠãããšãã§ããŸãã
protocol BindableObject { typealias DefaultPropertyModifierTargetType var defaulPropertytModifier: PropertyModifier<DefaultPropertyModifierTargetType> { get } } extension UILabel: BindableObject { typealias DefaultPropertyModifierTargetType = String? var defaulPropertytModifier: PropertyModifier<DefaultPropertyModifierTargetType> { return textModifier } } func >> <T, B: BindableObject where B.DefaultPropertyModifierTargetType == T>(left: Dynamic<T>, right: B) { left.addListener(right.defaulPropertytModifier.modifier) } func >>> <T, B: BindableObject where B.DefaultPropertyModifierTargetType == T>(left: Dynamic<T>, right: B) { left.bind(right.defaulPropertytModifier.modifier) }
以äžã§ãã
UILabelã«ã¯ ã
ããã¹ããã£ãŒã«ãã®å€ã倿Žããæšæºã®
PropertyModifierããããŸãã ãããŠãæå®ãããç®æšã«å°éããŸãããã€ãŸããæ¬¡ã®ãããªé¢ä¿ãäœæã§ããŸãã
viewModel.someText >>> label
ããŒã
ç§ãæ°ã«å
¥ã£ãXamarin Formsã®æ³šç®ãã¹ãæŠå¿µã®1ã€ã¯ãããŒã ã§ããã å®éã2ã€ã®é¢æ°ã䜿çšããŠã³ãã³ããèšè¿°ã§ããŸãã1ã€ã¯
trueãŸãã¯
falseãè¿ããã³ãã³ããå®è¡å¯èœã§ããããšã瀺ãã2çªç®ã¯ã³ãã³ããå®è¡ããã¢ã¯ã·ã§ã³ã§ãã ãã¿ã³ïŒ
UIButton ïŒããããšããŸãã ãã¿ã³ã«ã¯
æå¹ãªãã£ãŒã«ããããããŠãŒã¶ãŒã¯ãã¿ã³ãæŒãããšãã§ããŸãããã®åŸãäœããã®ã¢ã¯ã·ã§ã³ãçºçããŸãã ã€ã³ã¿ãŒãã§ã€ã¹ã®åäœã®å®£èšçãªèšè¿°ãç®æããŠããããšãèŠããŠããŸããïŒ ãã®ã¢ã€ãã¢ãã³ã³ãããŒã«ã«æ¡åŒµããŸãããã
final class Command<T> { typealias CommandType = (value: T, sender: AnyObject?) -> () weak var enabled: Dynamic<Bool>? private let command: CommandType init (enabled: Dynamic<Bool>, command: CommandType) { self.enabled = enabled self.command = command } init (command: CommandType) { self.command = command } func execute(value: T) { execute(value, sender: nil) } func execute(value: T, sender: AnyObject?) { var enabled = true if let en = self.enabled?.value { enabled = en } if enabled { command(value: value, sender: sender) } } } protocol Commander { typealias CommandType func setCommand(command: Command<CommandType>) } func >> <T, B: Commander where B.CommandType == T>(left: B, right: Command<T>) { left.setCommand(right) } private var UIButtonPropertyKeyCommand: UInt8 = 0 extension UIButton: Commander { typealias CommandType = () func setCommand(command: Command<CommandType>) { if let c: AnyObject = objc_getAssociatedObject(self, &UIButtonPropertyKeyCommand) { fatalError("Multiple assigment to command") return } objc_setAssociatedObject(self, &UIButtonPropertyKeyCommand, command, objc_AssociationPolicy(OBJC_ASSOCIATION_ASSIGN)) command.enabled?.bind { [weak self] in self?.enabled = $0; () } addTarget(self, action: Selector("buttonTapped:"), forControlEvents: .TouchUpInside) } func buttonTapped(sender: AnyObject?) { if let c: Command<CommandType> = objc_getAssociatedObject(self, &UIButtonPropertyKeyCommand) as? Command<CommandType> { c.execute((), sender: sender) } } }
ãããã£ãŠã
æå¹ãªãã£ãŒã«ããšã
executeã¡ãœãããåŒã³åºããããšãã«
å®è¡ããå¿
èŠããã颿°ãæã€ã³ãã³ãããããŸãã ããŒã ããã¿ã³ã«é¢é£ä»ããå¿
èŠããããŸãã ãããè¡ãããã«ã
setCommandã¡ãœããã䜿çšããŠ
Commanderãããã³ã«ã
å
¥åããŸãã ã
æå¹ãªã³ãã³ãã®åçãã£ãŒã«ãã察å¿ãã
UIButtonããããã£ã«é¢é£ä»ããããšã«ããã
UIButtonã®ãããã³ã«ãå®è£
ã
ãŸã ã ãŸãã䟿å®äž
>>æŒç®åããªãŒããŒããŒãããŸããã çµæãšããŠäœãåŸãããŸããïŒ
class PageModel { let nextPageEnabled: Dynamic<Bool> = Dynamic(true) lazy var openNextPage: Command<()> = Command ( enabled: self.nextPageEnabled, command: { [weak self] value, sender in
ãããã«
ç§ãã¡ãèªç±ã«äœ¿ããã®ã¯ããããããã®ã«é¢é£ä»ããããšãã§ããåçãªããžã§ã¯ãã§ãã ãã¿ã³ããã衚æ
è±ãã«ã¯ãªãã¯ããããšã§ã¢ã¯ã·ã§ã³ã説æã§ããã³ãã³ããçšæãããŸããã ãããŠãããã¯ãã§ã«
UIViewControllerãåçŽåããã®ã«
ååã§ãã èå°è£ã«ã¯ã
åçãªåæ¹åãã€ã³ããŒçšã®
ããããš
ãã£ã«ã¿ãŒ ãããã³
UITableViewã®ç°¡ç¥åãããäœæ¥ããããŸããã ããããããªãã¯ãããèªåã§èŠãããšãã§ããŸãã ãã®ã¢ãããŒãã®æ©èœã瀺ããããžã§ã¯ãã¯ã
GitHubã§å
¥æã§ã
ãŸã ã ã芧ã«ãªãããšããå§ãããŸãã
ã·ãŒãã®äŸ class TwoWayBindingPage: Page { typealias PMT = TwoWayBindingPageModel @IBOutlet weak var switchLabel: UILabel! @IBOutlet weak var switchControl: UISwitch! @IBOutlet weak var switchButton: UIButton! @IBOutlet weak var textFieldLabel: UILabel! @IBOutlet weak var textField: UITextField! @IBOutlet weak var textFieldButton: UIButton! @IBOutlet weak var sliderLabel: UILabel! @IBOutlet weak var slider: UISlider! @IBOutlet weak var sliderButton: UIButton! override func bindPageModel() { super.bindPageModel() let pm = pageModel as PMT switchButton >> pm.changeSomethingEnabled textFieldButton >> pm.changeUserName sliderButton >> pm.changeAccuracy pm.somethingEnabled | { "Current dynamic value: \($0)" } >>> switchLabel pm.userName | { "Current dynamic value: \($0)" } >>> textFieldLabel pm.accuracy | { "Current dynamic value: \($0)" } >>> sliderLabel pm.somethingEnabled <<>>> switchControl pm.userName <<>>> textField pm.accuracy <<>>> slider } } class BeerListPage: Page { typealias PMT = BeerListPageModel @IBOutlet weak var tableView: UITableView! private var tableViewHelper: SimpleTableViewHelper! override func bindPageModel() { super.bindPageModel() let pm = pageModel as PMT tableViewHelper = SimpleTableViewHelper(tableView: tableView, data: pm.beerList, cellType: BeerTableCell.self, command: pm.openBeerPage) tableView.pullToRefreshControl >> pm tableView.infiniteScrollControl >> pm } }
ãæž
èŽããããšãããããŸããã ã³ã¡ã³ããææ¡ãæ¹å€ãæè¿ããŸãã