¶ÔÓÚÒÆ¶¯Ó¦ÓöøÑÔ£¬Óû§ÌåÑé·Ç³£ÖØÒª£¬ÔÚ¿ª·¢AppµÄ¹ý³ÌÖÐÍùÍùºÜ´óÒ»²¿·Ö¾«Á¦¶¼ÊÇÓÃÓÚUI½çÃæµÄ¹¹½¨ÓëÓÅ»¯¡£¶ÔÓÚ½»»¥Âß¼±È½Ï¼òµ¥µÄÒ³Ãæ£¬ÊµÏÖ˼·±È½Ï¼òµ¥Ö±°×¡£µ«Èç¹û½»»¥½Ï¸´ÔÓ£¬Éæ¼°Öî¶à±äÁ¿¡¢Ê¼þ¡¢UI×é¼þ£¬¶øÇÒËüÃÇÖ®¼ä»¹»áÏ໥ÒÀÀµ¶ø±ä»¯µÄ»°£¬Ð´Æð´úÂë¾Í±È½Ï¼¬ÊÖÁË¡£°´³£¹æµÄ˼·²»ÊDz»ÄÜд£¬Ö»ÊÇдÆðÀ´·Ç³£·±Ëö£¬¶øÇÒ¿Éά»¤ÐԺܲ
Óöµ½ÄÑÒÔ½â¾öµÄÎÊÌ⣬ÓÐʱºòÊÇÎÊÌâ±¾ÉíºÜÄÑ£¬µ«Ò²ÓÐʱºòÊÇÒòΪ˼¿¼ÎÊÌâµÄģʽ²»¶Ô£¬²ÅÔì³ÉÎÊÌâ¿´ÆðÀ´¡°ÄÑÒÔ½â¾ö¡±¡£ÆäʵÕâÖÖ¸´ÔÓ½»»¥ÎÊÌ⣬ÔçÒÑÔÚWebǰ¶Ë¿ª·¢Öб»´ó¼ÒËù×¢Òâµ½¡£´ÓjQueryµ½Angular¡¢ÔÙµ½React£¬¾ÍÊÇÈËÃÇÔÚ³¢ÊÔ½â¾ö¸´ÔÓ½»»¥¿ª·¢ÄÑÌâµÄ¹ý³ÌÖеIJúÎï¡£
jQueryÊǵäÐ͵ÄÃüÁîʽµÄ˼·£¬Ã¿´ÎÓû§´¥·¢ÁËʼþ£¬¾ÍÔÚʼþhandleÖÐÈ¥Ö±½Ó¸ÄдËùÓÐÉæ¼°µ½µÄ±äÁ¿¡¢DOMÔªËØµÈ¡£È»¶øËæ×ÅÐèÇóµÄÔö¼Ó£¬handleÖÐÐèÒª´¦ÀíµÄ¶«Î÷»áÔ½À´Ô½¶à£¬×îÖÕµ¼Ö»ù±¾ÎÞ·¨Î¬»¤¡£
Angular¡¢ReactÔò²ÉÓÃÁËÁíÍâÒ»ÖÖ˼·£¬ËüÃǶ¼Ö÷ÕÅÉùÃ÷ʽµÄUI¡£ÃüÁîʽ±à³ÌºÍÉùÃ÷ʽ±à³ÌµÄÇø±ðÈçÏ£º
1.ÃüÁîʽ±à³Ì£ºÃüÁî¡°»úÆ÷¡±ÈçºÎÈ¥×öÊÂÇé(how)£¬ÕâÑù²»¹ÜÄãÏëÒªµÄÊÇʲô(what)£¬Ëü¶¼»á°´ÕÕÄãµÄÃüÁîʵÏÖ¡£
2.ÉùÃ÷ʽ±à³Ì£º¸æËß¡°»úÆ÷¡±ÄãÏëÒªµÄÊÇʲô(what)£¬ÈûúÆ÷Ïë³öÈçºÎÈ¥×ö(how)¡£
ÔÚAngular¡¢ReactÖУ¬¶ÔÊý¾ÝµÄÐ޸Ļá×Ô¶¯·´Ó³µ½UIÉÏ¡£ÕâÑùÒ»À´¾ÍÎÞÐèдÄÇЩ·±ËöµÄUI¿ØÖÆ´úÂ룬Óеã¶ùWYSIWYG£¨What
You See Is What You Get£©µÄ¸Ð¾õ¡£»Øµ½iOSÀ´½²£¬ÎÒÃǿɲ»¿ÉÒÔ½è¼øÕâÖÖ×ö·¨ÄØ£¿ÈÃUIËæ×ÅmodelµÄ±ä¶¯¶ø±ä¶¯£¿´Ó¶ø´ó·ù¼õÉÙÖ±½Ó²Ù×÷UI×é¼þµÄ´úÂ룿
Objective-CµÄKVO£¨Key-Value Observing£©¾ÍÊǷdz£ÊʺÏʵÏÖÕâÖÖЧ¹ûµÄÌØÐÔ¡£ËüÔ´ÓÚÉè¼ÆÄ£Ê½ÖеĹ۲ìÕßģʽ£¬µ±Ä³¸ö¶ÔÏóµÄkeypathÖµ±ä»¯Ê±£¬¿ÉÒÔÖ÷¶¯Í¨ÖªÆäËûµÄ¶ÔÏó¡£ÀûÓÃKVO£¬ÎÒÃÇ¿ÉÒÔ¼àÌýmodelµÄ±ä»¯ÒÔ×Ô¶¯¸üÐÂUI¡£
²»¹ýSwiftûÓÐKVOµÄÖ±½ÓʵÏÖ£¬ÐèÒªÒýÈëObjective-CÔËÐÐʱÀ´ÊµÏÖ£º¼Ì³ÐNSObject£¬²¢ÔÚÒª¹Û²ìµÄÊôÐÔǰÌí¼Ódynamic¹Ø¼ü×Ö¡£²»¹ýÕâÑù×ܸоõ±ðŤ£¬¶øÇÒKVOµÄÄÇÒ»Ì×APIÓÃÆðÀ´Ò²±È½ÏÂé·³¡£ÄÇô£¬ÓÐûÓÐÆäËûµÄ½â¾ö·½·¨£¿Observable-SwiftÀûÓÃÁËSwiftµÄÊôÐÔ¹Û²ì
(Property Observers) ´ïµ½ÁËÀàËÆµÄЧ¹û¡£
Observable-Swift
Observable-SwiftÊÇGoogleµÄÒ»¸öÔ±¹¤slazyk¿ª·¢µÄswift¿â£¬ËüÖ÷ÒªÌṩÁË2¸ö¶«Î÷£º
1.Observable<T>£ºÌṩÁËvalue observingµÄ¹¦ÄÜ
2.Event<T>£ºÌṩÁËsubscribable
eventsµÄ¹¦ÄÜ
¾ßÌåµÄÓ÷¨Ö±½Ó²Î¿¼ÆäÎĵµ¼´¿É£¬ºÜÈÝÒ׾ͿÉÒÔÀí½â¡£
°¸Àý
¿Õ˵ÎÞÒæ£¬À´¿´Ò»¸öÐèÇó¡£±ÈÈçÓиöApp£¬ÐèÒªÓû§ÌîдËû×îϲ»¶µÄÈý¸öÖйú³ÇÊУ¬Ð§¹ûͼÈçÏ£º

±¾ÎÄÅäÌ×µÄʾÀý¹¤³Ì·ÅÔÚGitHubÉÏÁË£ºhttps://github.com/hustlzp/Observable-Swift-Example£¬½¨Òé¿ÉÒÔÏÂÔØÏÂÀ´£¬pod
install --no-repo-update°²×°ÏÂÒÀÀµ¿â£¬È»ºó±àÒë°²×°µ½ÊÖ»úÉÏÊÔÊÔ¡£´¿ÓÃÎÄ×ÖÃèÊöÐèÇó»¹ÊǺÜÀ۵ģ¬ÓÃÒ»ÏÂApp¾Íʲô¶¼Çå³þÁË...
»¹ÊÇ·ÖÎöÒ»ÏÂÐèÇó°É£¬Õâ¸öÒ³ÃæÐèҪʵÏֵŦÄÜÒªµãÈçÏ£º
1.ËÑË÷³ÇÊУºÊäÈëÎÄ×Ö£¬¿ÉËÑË÷³ÇÊУ¬ËÑË÷½á¹ûÒÔÁбíµÄÐÎʽÁÐÔÚÏ·½
2.Ìí¼Ó³ÇÊУºµã»÷ËÑË÷½á¹ûµÄijһÐУ¬¼´¿ÉÌí¼Ó³ÇÊУ¬Ìí¼Óºó£¬³ÇÊгöÏÖÔÚtextFieldµÄ×ó²à
3.ɾ³ý³ÇÊУºÔÚtextFieldΪ¿Õʱ£¬°´Ï¼üÅ̵Äbackspace¼ü£¬×îÐÂÌí¼ÓµÄtag±»Ñ¡ÖУ»ÔÙ°´Ò»ÏÂbackspace£¬¼´¿Éɾ³ý£»Èç¹û°´ÏµÄÊÇ×Ö·û£¬ÔòÈ¡Ïûɾ³ý
4.Íê³É£ºÊäÈë1-3¸ö³ÇÊк󣬿ɵã»÷ÓÒÉϽǵġ°Íê³É¡±°´Å¥
ͬʱ£¬ÎªÁËÌáÉýÓû§ÌåÑ飬ÔÚ½»»¥µÄ¹ý³ÌÖУ¬»¹ÐèҪʵÏÖÈçϵĽ»»¥Ï¸½Ú£º
5.textFieldµÄplaceholder£ºÔÚÉÐδÌí¼Ó³ÇÊÐʱ£¬ÏÔʾ¡°ÊäÈë³ÇÊÐÃû³Æ¡±£»ÔÚÌí¼ÓµÄ³ÇÊÐСÓÚ3¸öʱ£¬ÏÔʾ¡°×î¶àÈý¸ö¡±£»ÔÚÊÇ
6.ÓÒÉϽǵġ°Íê³É¡±°´Å¥£ºÔÚÌí¼Ó³ÇÊкó¡¢textFieldûÓÐÎÄ×Ö¡¢ÇÒδ´¦ÓÚԤɾ³ý״̬ʱ£¬enable£»·ñÔòdisable
7.ÌáʾÎÄ×Ö£ºÔÚÉÐδÌí¼Ó³ÇÊÐʱ£¬textFieldÏ·½ÏÔʾ¡°Ìí¼Ó³ÇÊУ¬×î¶à²»³¬¹ýÈý¸ö¡±£»Ìí¼Ó³ÇÊкó£¬Òþ²Ø
8.±êÇ©¹ý³¤Ê±£¬Ïò×ó¹ö¶¯£ºµ±Ä³³ÇÊйý³¤Ê±£¬ÐèÒªÏò×ó¹ö¶¯£¬ÒÔÈÃtextField¿É¼û
µ¥¿´ÎÄ×ֵıíÊöÊDz»ÊǾõµÃ±È½Ï¸´ÔÓ£¿½¨Òé°²×°Ò»ÏÂʾÀýÏîÄ¿µÄDEMO App£¬ÓÃÒ»Ó㬾ÍÖªµÀÉÏÃæÒ»´óÅÅÎÄ×Öµ½µ×ÔÚ˵ʲôÁË¡£
·ÖÎö
OK£¬ÏÖÔÚÎÒÃÇÀ´·ÖÎöÈçºÎʵÏÖÕâ¸öÒ³Ãæ¡£
Èç¹û²ÉÓô«Í³µÄ·½·¨£¬ÄÇô´úÂëдÆðÀ´»á·Ç³£¸´ÔÓ¡£µ«Èç¹û²ÉÓá°¼àÌýmodelµÄ±ä»¯ÒÔ×Ô¶¯¸üÐÂUI¡±µÄ˼·À´·ÖÎö£¬»áÇåÎúºÜ¶à¡£
ÎÒÃÇ¿ÉÒÔ°ÑÉÏÃæÌáµ½µÄ¶«Î÷»®·ÖΪÈýÀࣺModel¡¢Action¡¢UI¡£
1.Model£º±íʾ³ÖÓÐÊý¾Ý/״̬µÄ±äÁ¿
2.Action£ºÓû§½»»¥
3.UI£ºÒ³ÃæUI×é¼þµÄ±ä»¯
ÈýÕßÖ®¼äµÄ¹ØÏµÊÇÔõÑùµÄÄØ£¿
1.Model¸üÐÂUI×é¼þ¡¢Ò²»á¸üÐÂÆäËûModel
2.Action¸üÐÂModel
¸ù¾ÝÒÔÉÏÔÔò£¬ÎÒÃÇ¿ÉÒÔ¸ù¾ÝAppµÄÐèÇó£¬×ö³öÈçÏµĻ®·Ö£º
Model£º
1.tags: ÒѾÌí¼ÓµÄ³ÇÊбêÇ©
2.matchedTags£º³ÇÊеÄËÑË÷½á¹û
3.textFieldText£ºtextFieldµÄtextÖµ
4.prepareRemoveTag£ºÊÇ·ñ´¦ÓÚԤɾ³ý³ÇÊеÄ״̬
Action£º
1.textFieldÊäÈë×Ö·û
2.textFieldÓÐbackspace¼ü°´ÏÂ
3.tableViewÓÐrow±»°´ÏÂ
UI£º
1.Õâ¸ö¾Í²»Õ¹¿ªËµÁË£¬Ì«¶àÁË
ʾÒâͼ£º

ÕâÑùÒ»·ÖÎö£¬¾ÍÇåÎú¶àÁË¡£Observable-SwiftÔÚÉÏͼÖаçÑݵĽÇÉ«¾ÍÊÇʹÓÃObservable<T>ÉùÃ÷Model±äÁ¿£¬È»ºóÔÚafterChangeÖÐÌí¼Ó´úÂë¼´¿É¡£
´úÂëµÄÍêÕûʵÏ־Ͳ»ÁгöÀ´ÁË£¬Ö»ÊǰÑÉÏÃæµÄ·ÖÎöÓôúÂë±í´ï³öÀ´¶øÒÑ¡£¾Ù¸öСÀý×Ó°É£¬tagsµÄ±ä»¯»áÓ°Ïìµ½5¸öUI±ä»¯£¬Í¬Ê±»á¸üÐÂtextFieldTextµÄÖµ£¬´úÂëÈçÏ£º
private var tags = Observable([String]())
tags.afterChange += { (_) in
// TextField placeholder
if self.tags^.count == 0 {
self.textField.placeholder = "ÊäÈë³ÇÊÐÃû³Æ..."
} else if self.tags^.count >= 3 {
self.textField.placeholder = ""
} else {
self.textField.placeholder = "×î¶àÈý¸ö"
}
// TextField left constraint
self.textField.snp_updateConstraints { (make)
-> Void in
if self.tags^.count == 0 {
make.left.equalTo(self.tagsView.snp_right)
} else {
make.left.equalTo(self.tagsView.snp_right).offset(8)
}
}
// Update tagsView
self.tagsView.updateTags(self.tags^)
// scrollView»¬¶¯µ½×îÓÒ±ß
self.scrollView.setNeedsLayout()
self.scrollView.layoutIfNeeded()
if self.scrollView.contentSize.width > self.scrollView.bounds.size.width
{
let bottomOffset = CGPointMake(self.scrollView.contentSize.width
- self.scrollView.bounds.size.width, 0)
self.scrollView.setContentOffset(bottomOffset,
animated: true)
}
self.updateTableViewVisibility()
self.updateFinishButtonEnable()
// Empty textField
self.textFieldText <- "" |
¾ÖÏÞÐÔ
´ó¼Ò¿ÉÄÜ×¢Òâµ½£¬ÉÏÃæµÄͼÖгöÏÖÁËij¸öUI×é¼þͬʱÊܶà¸öModelÓ°ÏìµÄÇé¿ö¡£±ÈÈçtableViewµÄhiddenͬʱÓëtagsºÍtextFieldTextÏà¹Ø¡£ÈçºÎÓÃObservable-Swift×ÔÈ»µØ±í´ïÕâ¸ö¹ý³ÌÄØ£¿Observable-SwiftÌṩÁËÒ»¸öδдÈëÎĵµµÄÀàPairObservable£¬Ó÷¨ÈçÏ£º
(tags & textFieldText).afterChange += { (_) in // Do something } |
tags & textFieldTextµÄÀàÐÍΪPairObservable<Observable<[String]>,
Observable<Bool>>¡£ÕâÖÖÓ÷¨µÄȱµãÔÚÓÚ£¬ÐèÒªÒýÈëÒ»¸öÀà±äÁ¿È¥±£´ætags
& textFieldTextµÄÖµÒÔ·ÀÆä±»dealloc¡£ÂÔÏÔÀÛ׸¡£
Èç¹ûÏà¹ØµÄModel³¬¹ý2¸ö£¬Äã»áÏÂÒâʶµØÕâôд£º
(tags & textFieldText & prepareRemoveTag). afterChange += { (_) in // Do something } |
ËüÉú³ÉµÄ²¢²»ÊÇPairObservable<Observable<A>, Observable<B>,
Observable<C>>ÀàÐÍ£¬¶øÊÇPairObservable<PairObservable<Observable<A>,
Observable<B>>, Observable<C>>£¬ËäÈ»¿ÉÄÜ´ïµ½¼à¿Ø±ä»¯µÄЧ¹û£¬µ«×ܸоõ·Ç³£µØhacky...
½áÓï
µ±È»»¹ÓÐÆäËûµÄ·½·¨À´Ó¦¶Ô¸´ÔÓ½»»¥UIµÄ¿ª·¢ÎÊÌâ¡£±ÈÈç×î½üÒ»Ö±ºÜ»ðÈȵÄReactiveCocoa£¬ÀûÓõ½Á˺¯ÊýÏìӦʽ±à³ÌµÄ˼Ïë¡£±ÈÈ绹ÓÐÈ˽«ReduxµÄ˼ÏëÒýÈëiOSÖУ¬ÓÚÊÇÓÐÁËReSwiftÕâ¸öÏîÄ¿¡£ |