objc:Issue13——Architecture【3】

在iOS應(yīng)用中的行為——by Krzysztof Zab?ocki

作為開發(fā)者前域,我們力求編寫整潔且組織良好的代碼。達(dá)到這個(gè)目的我們有很多模式可以使用封孙,其中最好的一個(gè)當(dāng)屬組合(composition)模式了迹冤。組合更容易讓我們遵循單一職責(zé)原則(Single Responsibility Principe并簡化類文件。

不像重視圖控制器(Massive View Controller)同時(shí)服務(wù)于不同的角色(如數(shù)據(jù)源和委托)那樣敛瓷,你可以把這些角色分離到不同的類文件中叁巨。視圖控制器只負(fù)責(zé)配置它們并協(xié)調(diào)工作斑匪。畢竟呐籽,代碼寫的越少,需要調(diào)試和維護(hù)的代碼也就越少蚀瘸。

那么行為究竟是什么狡蝶?

行為是一個(gè)負(fù)責(zé)實(shí)現(xiàn)特定角色的對象,例如贮勃,你可以有一個(gè)實(shí)現(xiàn)視差動畫的行為贪惹。

這篇文章中的行為將利用Interface Builder限制代碼量,同時(shí)與非編碼人員進(jìn)行有效的合作寂嘉。然而奏瞬,如果你不使用Interface Builder你也可以使用行為,仍然可以獲取大多數(shù)的好處泉孩。

很多行為除了設(shè)置之外不需要任何額外的代碼硼端,你完全可以通過Interface Builder和代碼(同樣的設(shè)置方法)完成這些設(shè)置。很多情況下寓搬,你甚至不需要用屬性引用它們珍昨。

為什么使用行為?

許多iOS項(xiàng)目最后都成了重視圖控制器(Massive View Controller)類句喷,因?yàn)槿藗儼褢?yīng)用中80%的邏輯放到了這里镣典。這是一個(gè)嚴(yán)重的問題,因?yàn)樵噲D控制器是我們代碼中復(fù)用率最少的部分唾琼,很難對他們進(jìn)行測試和維護(hù)兄春。

行為可以幫我們避免這種情形,那么它給我們帶來了那些好處呢锡溯?

輕視圖控制器(Lighter View Controller)

使用行為意味著可以吧很多代碼從控制器中移入到分離的類文件中赶舆。如果使用行為肴裙,通常都會形成輕量的視圖控制器。例如涌乳,我的通常少于100行代碼蜻懦。

代碼復(fù)用

因?yàn)樾袨閮H僅只負(fù)責(zé)一個(gè)角色,它很容易避免特定行為和特定應(yīng)用之間邏輯的依賴夕晓。這允許你在不同的應(yīng)用之間共享香味宛乃。

測試性

行為是像黑盒一樣工作的小類。這意味著他們很容易被單元測試覆蓋蒸辆。你甚至不用創(chuàng)建真實(shí)的視圖只用提供模擬對象就可以測試它們征炼。

讓非編碼人員修改應(yīng)用邏輯的能力

如果我們決定使用Interface Builder利用行為,我們可以教設(shè)計(jì)師如何修改應(yīng)用邏輯躬贡。設(shè)計(jì)師可以添加谆奥、移除行為和修改參數(shù),并不需要知道Objective-C的任何相關(guān)知識拂玻。

這對工作流來說是很大的一個(gè)好處酸些,特別是小團(tuán)隊(duì)。

如何創(chuàng)建靈活的行為檐蚜?

行為是一個(gè)不需要任何專門代碼的簡單對象魄懂,但是這有幾個(gè)概念可以真正的幫助它們更易使用,更加強(qiáng)大闯第。

運(yùn)行時(shí)屬性

很多開發(fā)者都忽視了Interface Builder市栗,甚至都沒有學(xué)習(xí)過它,同樣的咳短,經(jīng)常會錯(cuò)過它真正的強(qiáng)大之處填帽。

運(yùn)行時(shí)屬性是使用Interface Builder的關(guān)鍵特性之一。它們給你提供一種設(shè)置自定義類的方式咙好,設(shè)置可以為iOS的內(nèi)建類設(shè)置屬性篡腌。例如,你是否設(shè)置過圖層的圓角半徑敷扫?你可以直接在Interface Builder中為其簡單地設(shè)置運(yùn)行時(shí)屬性:

image

當(dāng)在Interface Builder中創(chuàng)建行為的時(shí)候哀蘑,你打算嚴(yán)重依賴運(yùn)行時(shí)屬性去設(shè)置行為選項(xiàng)。結(jié)果葵第,這兒通常會有更多的運(yùn)行時(shí)屬性:
image

行為的生存時(shí)間

如果一個(gè)對象從Interface Builder創(chuàng)建绘迁,它會立即創(chuàng)建立即移除,除非其他的對象擁有它的強(qiáng)引用卒密。然而缀台,這對行為來說并不是完美的,因?yàn)樗枰饔糜诘囊晥D控制器存活的時(shí)間一樣長哮奇。

你可以在視圖控制器中創(chuàng)建一個(gè)屬性并強(qiáng)引用行為膛腐,但是這并不完美睛约,原因有如下幾個(gè):

  • 當(dāng)創(chuàng)建并配置好行為后,你不需要同很多行為進(jìn)行交互哲身。
  • 創(chuàng)建屬性僅僅只為了保持對象生存這很麻煩辩涝。
  • 如果需要移除特定的行為,你需要去清理那些未使用的屬性勘天。

使用Objective-C運(yùn)行時(shí)去反轉(zhuǎn)生存時(shí)間綁定

而不是手動的在視圖控制器中設(shè)置行為的強(qiáng)引用怔揩,如果需要的話,我們可以把行為當(dāng)做視圖的一個(gè)關(guān)聯(lián)對象脯丝,作為配置過程的一部分商膊。

這意味著,在某種情況下如果我們需要移除特定的行為宠进,我們只需要移除配置這個(gè)行為的代碼或者Interface Builder對象晕拆,并不需要額外的改變。

這可以像下面那樣實(shí)現(xiàn):

@interface KZBehavior: UIControl
@property(nonatomic, weak) IBOutlet id owner;
@end

@implementation KZBehavior
- (void)setOwner:(id)owner {
    if(_owner != owner) {
        [self releaseLifetimeFromObject:_owner];
        _owner = owner;
        [self bindLifetimeToObject:_owner];
    }
}

- (void)bindLifetimeToObject:(id)object {
    objc_setAssociatedObject(object, (__bridge void *)self, self, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (void)releaseLifetimeFromObject:(id)object {
    objc_setAssociatedObject(object, (__bridge void *), nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end

這里我們利用關(guān)聯(lián)對象來創(chuàng)建特定所有者對象的強(qiáng)引用材蹬。

行為事件

讓行為能夠發(fā)布事件非常有用实幕,例如,當(dāng)一個(gè)動畫結(jié)束時(shí)赚导〔缢酰可以通過從UIControl繼承行為來在Interface Builder中啟用該功能赤惊。然后吼旧,特定的行為可以調(diào)用:

[self sendActionsForControlEvents:UIControlEventValueChanged];

這允許你把行為連接到視圖控制器的代碼上。

一個(gè)簡單行為的例子

因此未舟,什么東西最容易作為行為來實(shí)現(xiàn)圈暗?

下面是將視差動畫添加到UIViewController類(不是自定義類)的簡單方法:

視頻

是否曾經(jīng)從你的照片庫和相機(jī)選擇一張圖片?

視頻

更為高級的特性

上面的行為很簡單裕膀,但是员串,當(dāng)我們需要更高級的特性的時(shí)候,以是否香菇應(yīng)該怎么做昼扛?行為可以做到你想讓他有多強(qiáng)大它就有多強(qiáng)大寸齐,我們看幾個(gè)更為復(fù)雜的例子。

如果行為需要幾個(gè)像UIScrollViewDelegate這類委托的話抄谐,你很快就會看到在一個(gè)特定的界面上你最多只能有一個(gè)行為的情況渺鹦。但是,我們可以通過實(shí)現(xiàn)一個(gè)簡單地多路代理的對象來處理這種問題:

@interface MutiplexerProxyBehavior: KZBehavior
@property(nonatomic, strong) IBOutletCollection(id) NSArray *targets;
@end

@implementation MutiplexerProxyBehavior
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
    NSMethodSignature *sig = [super methodSignatureForSelector:sel];
    if(!sig) {
        for(id obj in self.targets) {
            if((sig = [obj methodSignatureForSelector:sel)) {
                break;
            }
        }
    }
    return sig;
}
- (BOOL)respondsToSelector:(SEL)aSelector {
    BOOL base = [super respondsToSelector:aSelector];
    if(base) {
        return base;
    }
    return [self.targets.firstObject respondsToSelector:aSelector];
}
- (void)forwardInvocation:(NSInvocation *)anInvocation {
    for(id obj in self.targets) {
        if([obj respondsToSelector:anInvocation.selector]) {
            [anInvocation invokeWithTarget:obj];
        }
    }
}
@end

通過創(chuàng)建一個(gè)多路行為的實(shí)例蛹含,你可以把它指定為滾動視圖的一個(gè)委托(或者任何一個(gè)有委托的對象)毅厚,這樣委托調(diào)用將會轉(zhuǎn)發(fā)給所有人。

結(jié)論

行為是一個(gè)有趣的概念浦箱,它可以簡化你的代碼庫吸耿,允許你在不同的應(yīng)用間復(fù)用很多代碼祠锣。它們還將允許你通過微調(diào)或者修改應(yīng)用中的行為,從而同團(tuán)隊(duì)中的非編碼人員有效的協(xié)作咽安。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末伴网,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子妆棒,更是在濱河造成了極大的恐慌是偷,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件募逞,死亡現(xiàn)場離奇詭異蛋铆,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)放接,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進(jìn)店門刺啦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人纠脾,你說我怎么就攤上這事玛瘸。” “怎么了苟蹈?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵糊渊,是天一觀的道長。 經(jīng)常有香客問我慧脱,道長渺绒,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任菱鸥,我火速辦了婚禮宗兼,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘氮采。我一直安慰自己殷绍,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布鹊漠。 她就那樣靜靜地躺著主到,像睡著了一般。 火紅的嫁衣襯著肌膚如雪躯概。 梳的紋絲不亂的頭發(fā)上登钥,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天,我揣著相機(jī)與錄音楞陷,去河邊找鬼怔鳖。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的结执。 我是一名探鬼主播度陆,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼献幔!你這毒婦竟也來了懂傀?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤蜡感,失蹤者是張志新(化名)和其女友劉穎蹬蚁,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體郑兴,經(jīng)...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡犀斋,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了情连。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片叽粹。...
    茶點(diǎn)故事閱讀 38,605評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖却舀,靈堂內(nèi)的尸體忽然破棺而出虫几,到底是詐尸還是另有隱情,我是刑警寧澤挽拔,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布辆脸,位于F島的核電站,受9級特大地震影響螃诅,放射性物質(zhì)發(fā)生泄漏啡氢。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一州刽、第九天 我趴在偏房一處隱蔽的房頂上張望空执。 院中可真熱鬧,春花似錦穗椅、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至宣鄙,卻和暖如春袍镀,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背冻晤。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工苇羡, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人鼻弧。 一個(gè)月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓设江,卻偏偏與公主長得像锦茁,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子叉存,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,472評論 2 348

推薦閱讀更多精彩內(nèi)容