dependency injection 關(guān)于IOS依賴注入那些事
本文介紹的是另一個屎上最牛叉的ios開發(fā)新框架,最大的特點(diǎn)就是:幫助我們開發(fā)出松散耦合(loose coupled)、可維護(hù)、可測試的代碼和程序。這條原則的做法是大家熟知的面向接口,或者說是面向抽象編程。 眾所周知 該編程思想在各大語言中都有體現(xiàn)如 jave C++ PHP以及.net中。當(dāng)然設(shè)計(jì)模式的廣泛程度遠(yuǎn)遠(yuǎn)大于這些,IOS 當(dāng)然也不例外。 本文主要介紹本人在學(xué)習(xí)dependency injection的時候的學(xué)習(xí)過程以及對一些學(xué)習(xí)資料的總結(jié),主要介紹ios中的兩大框架objection和Typhoon。 閑話不多吹下面進(jìn)入正題。
什么是dependency injection?
簡單來說:
關(guān)于什么是依賴注入,在Stack Overflow上面有一個問題,如何向一個5歲的小孩解釋依賴注入,其中得分最高的一個答案是:
“When you go and get things out of the refrigerator for yourself, you can cause problems. You might leave the door open, you might get something Mommy or Daddy doesn’t want you to have. You might even be looking for something we don’t even have or which has expired.
What you should be doing is stating a need, “I need something to drink with lunch,” and then we will make sure you have something when you sit down to eat.”
映射到面向?qū)ο蟪绦蜷_發(fā)中就是:高層類(5歲小孩)應(yīng)該依賴底層基礎(chǔ)設(shè)施(家長)來提供必要的服務(wù)。
編寫松耦合的代碼說起來很簡單,但是實(shí)際上寫著寫著就變成了緊耦合。
更詳細(xì)點(diǎn)的解釋:
依賴倒置解決了高層次模塊依賴于低層次模塊和其細(xì)節(jié)的問題。
Dependency injection 是一個將行為從依賴中分離的技術(shù),簡單地說,它允許開發(fā)者定義一個方法函數(shù)依賴于外部其他各種交互,而不需要編碼如何獲得這些外部交互的實(shí)例。 這樣就在各種組件之間解耦,從而獲得干凈的代碼,相比依賴的硬編碼, 一個組件只有在運(yùn)行時才調(diào)用其所需要的其他組件,因此在代碼運(yùn)行時,通過特定的框架或容器,將其所需要的其他依賴組件進(jìn)行注入,主動推入。
依賴注入可以看成是 反轉(zhuǎn)控制 inversion of control 的一個特例。反轉(zhuǎn)的是依賴,而不是其他,JNDI也是一種反轉(zhuǎn)控制,它反轉(zhuǎn)的JNDI名稱或資源。參考: “Inversion of Control Containers and the Dependency Injection pattern”。
依賴注入是最早Spring和piconcontainer等提出,如今已經(jīng)是一個缺省主流模式,并擴(kuò)展到前端如Angular.js等等。
依賴注入與IOC模式類似工廠模式,是一種解決調(diào)用者和被調(diào)用者依賴耦合關(guān)系的模式,自2004年誕生以來,至今已經(jīng)成為Java和其他領(lǐng)域的主流模式。它解決了對象之間的依賴關(guān)系,使得對象只依賴IOC/DI容器,不再直接相互依賴,實(shí)現(xiàn)松耦合,然后在對象創(chuàng)建時,由IOC/DI容器將其依賴的對象注入Inject其體內(nèi),故又稱依賴注入依賴注射模式,最大程度實(shí)現(xiàn)松耦合,特別是Autowiring/Autowired自動配對引入,再結(jié)合Java的垃圾回收機(jī)制,使得在Java中,對象不再需要開發(fā)者自己創(chuàng)建,也需要開發(fā)者自己銷毀,只需要直接使用即可,大大提升了開發(fā)效率。
詳細(xì)解釋:依賴注入說白一點(diǎn),就是容器將某個類依賴的其他類注入到這個類中。
為什么要用dependency injection
依賴注入框架的運(yùn)用可以幫我們將APP的設(shè)計(jì)分割成好幾個模塊,分給不同的開人員,當(dāng)完成開發(fā)之后再進(jìn)行合并充分解決了團(tuán)隊(duì)之間模塊化分工的不足.借objic.io上一篇關(guān)于Dependency Injection的一句話:
My initial motivation for exploring DI came from doing test-driven development, because in TDD you constantly wrestle with the question of “How do I write a unit test for this?” But I discovered that DI is actually concerned with a bigger idea: that our code should be composed of modules that we snap together to build an application.
There are many benefits to such an approach. Graham Lee’s article, “Dependency Injection, iOS and You,” describes some of them: “to adapt… to new requirements, make bug fixes, add new features, and test components in isolation.”
大體意思:
我在探索DI最初的動機(jī)來自做測試驅(qū)動的開發(fā),因?yàn)樵赥DD你不斷地與問題搏斗“我怎樣寫單元測試嗎?”但我發(fā)現(xiàn),DI實(shí)際上是涉及一個更大的想法:即我們的代碼應(yīng)該由我們扣合在一起來構(gòu)建應(yīng)用程序模塊。
有許多好處,這樣的做法。格雷厄姆李的文章,“依賴注入,iOS和你”,介紹了其中一些:“適應(yīng)......新的要求,作出錯誤修復(fù),隔離增加新的功能以及測試組件?!?/p>
用文字說這些概念其實(shí)很抽象,下面用幾張圖片說明下:
通過objection實(shí)現(xiàn)依賴注入后,就能更好地實(shí)現(xiàn)SRP(Single Responsibility Principle),代碼更簡潔,心情更舒暢,生活更美好。拿Pinterest來說,下面的頁面就可以劃分為3個Section。

各個Section可以由不同的人負(fù)責(zé),然后串到一起就行,也能一定程度地避免MVC(Mess View Controller)的出現(xiàn),對于提高開發(fā)成員的效率也會有不少的幫助。
其實(shí)用簡單的一句話來說就是: 通過DI設(shè)計(jì)模式,將項(xiàng)目模塊化,以提高開發(fā)效率。
dependency injection試圖解決什么問題呢
我們知道,在IOS基本教程中有一個定律告訴我們:所有的對象都必須創(chuàng)建;或者說:使用對象之前必須創(chuàng)建,但是現(xiàn)在我們可以不必一定遵循這個定律了,我們可以從DI容器中直接獲得一個對象然后直接使用,無需事先創(chuàng)建它們。
這種變革,就如同我們無需考慮對象銷毀一樣;因?yàn)镮OS的 ARC 幫助我們實(shí)現(xiàn)了對象銷毀;現(xiàn)在又無需考慮對象創(chuàng)建,對象的創(chuàng)建和銷毀都無需考慮了,這給編程帶來的影響是巨大的
我們可以通過一篇博文了解下原理,該文章是由Limboy大神寫的使用objection來模塊化開發(fā)iOS項(xiàng)目
這里提前介紹了一個DI框架就是Objection,詳細(xì)介紹就去看博文,在此只分析下DI的設(shè)計(jì)原理:
類似于Objection的大部分DI框架,主要為我們提供了一個容器,來管理創(chuàng)建銷毀對象,我們并不會過多考慮創(chuàng)建對象的方法內(nèi)容以及其再其他類中的依賴關(guān)系,這些都在框架中為我們解決了,我們只需要再需要的時候調(diào)用即可,并不需要重復(fù)的導(dǎo)入import,避免不同類直接多次重復(fù)的import導(dǎo)致的依賴循環(huán)問題。
那么問題來了?如何學(xué)習(xí)dependency injection呢
ios有關(guān)DI依賴注入的框架比較好用的有兩個:objection 和 Typhoon
下面就從幾個方便來介紹下這兩個框架
一:objection 和 Typhoon這兩個框架有什么區(qū)別呢
其實(shí)這兩個框架各有優(yōu)勢:
1.objection框架,使用起來比較靈活,用法比較簡單。示例代碼如下:
屬性注冊:
@class Engine, Brakes;
@interface Car : NSObject
{
Engine *engine;
Brakes *brakes;
BOOL awake;
}
// Will be filled in by objection
@property(nonatomic, strong) Engine *engine;
// Will be filled in by objection
@property(nonatomic, strong) Brakes *brakes;
@property(nonatomic) BOOL awake;
@implementation Car
objection_requires(@"engine", @"brakes") //屬性的依賴注入
@synthesize engine, brakes, awake;
@end
方法注入:
@implementation Truck
objection_requires(@"engine", @"brakes")
objection_initializer(truckWithMake:model:)//方法的依賴注入
+ (instancetype)truckWithMake:(NSString *) make model: (NSString *)model {
...
}
@end
2.對比來說Typhoon的使用起來就比較規(guī)范,首先需要創(chuàng)建一個 TyphoonAssembly的子類。其需要注入的方法和屬性都需要寫在這個統(tǒng)一個子類中,當(dāng)然可以實(shí)現(xiàn)不同的子類來完成不同的功能
@interface MiddleAgesAssembly : TyphoonAssembly
- (Knight*)basicKnight;
- (Knight*)cavalryMan;
- (id<Quest>)defaultQuest;
@end
屬性注入:
- (Knight *)cavalryMan
{
return [TyphoonDefinition withClass:[CavalryMan class]
configuration:^(TyphoonDefinition *definition) {
[definition injectProperty:@selector(quest) with:[self defaultQuest]];
[definition injectProperty:@selector(damselsRescued) with:@(12)];
}];
}
方法注入:
- (Knight *)knightWithMethodInjection
{
return [TyphoonDefinition withClass:[Knight class]
configuration:^(TyphoonDefinition *definition) {
[definition injectMethod:@selector(setQuest:andDamselsRescued:)
parameters:^(TyphoonMethod *method) {
[method injectParameterWith:[self defaultQuest]];
[method injectParameterWith:@321];
}];
}];
}
3.當(dāng)然還有一些硬性的區(qū)別就是Typhoon現(xiàn)在已經(jīng)支持Swift。
4.兩者維護(hù)時間都超過2年以上。
Tythoon官方介紹的優(yōu)勢:
1)Non-invasive. No macros or XML required. Uses powerful ObjC runtime instrumentation.
2)No magic strings – supports IDE refactoring, code-completion and compile-time checking.
3)Provides full-modularization and encapsulation of configuration details. Let your architecture tell a story.
4)Dependencies declared in any order. (The order that makes sense to humans).
5)Makes it easy to have multiple configurations of the same base-class or protocol.
6)Supports injection of view controllers and storyboard integration. Supports both initializer and property injection, plus life-cycle management.
7)Powerful memory management features. Provides pre-configured objects, without the memory overhead of singletons.
8)Excellent support for circular dependencies.
9)Lean. Has a very low footprint, so is appropriate for CPU and memory constrained devices.
10)While being feature-packed, Typhoon weighs-in at just 3000 lines of code in total.
11)Battle-tested — used in all kinds of Appstore-featured apps.
大體翻譯過來:
1)非侵入性。不需要宏或XML。使用強(qiáng)大的ObjC運(yùn)行時儀器。
2)沒有魔法字符串——支持IDE重構(gòu),完成和編譯時檢查。
3)提供full-modularization和封裝的配置細(xì)節(jié)。讓你的架構(gòu)告訴一個故事。
4)依賴關(guān)系中聲明的任何順序。(對人類有意義的順序)。
5)很容易有多個配置相同的基類或協(xié)議。
6)支持注射的視圖控制器和故事板集成。同時支持初始化器和屬性注入,以及生命周期管理。
7)強(qiáng)大的內(nèi)存管理功能。提供預(yù)配置對象,沒有單件的內(nèi)存開銷。
8)優(yōu)秀的支持循環(huán)依賴。
9)精益。占用很低,所以適合CPU和內(nèi)存受限的設(shè)備。
10),功能強(qiáng)大,臺風(fēng)重總共只有3000行代碼。
11)久經(jīng)沙場,用于各種Appstore-featured應(yīng)用。
針對這兩個框架網(wǎng)上教程并不多,收集了一些比較有用的資料。最主要的用法還得看官方文檔分別在:
大體學(xué)習(xí)步驟:
(一)了解依賴注入的原理
依賴注入各大語言都一樣,相關(guān)資料:
其中最需要看的是來自
objc.io官網(wǎng)的博文 Dependency Injection 和 Typhoon原創(chuàng)大神(Graham Lee)的文章 Dependency Injection, iOS and You 不看后悔一輩子_
2.某知名博主寫的文章--依賴注入(Dependency Injection)模式
4.國人翻譯的國外牛人的文章---依賴注入——讓iOS代碼更簡潔
進(jìn)階內(nèi)容了解和學(xué)習(xí)框架
首先來看看有關(guān)objection的資料
資料比較少
1.Limboy大大大神的--使用objection來模塊化開發(fā)iOS項(xiàng)目