本章主要講解委托模式已經通過委托模式實現的回調接口。
委托模式是OC語法獨有的開發模式。是基於組件拼裝的一種快速開發模式。該模式下,可以保證組件的高度靈活性和通用性。屬於組件的一種開放式接口。
下面通過一個現實生活中的場景簡單理解下委托模式的應用。
例如我們現在有一個公司。公司想要進行IPO。可是公司老總並不熟悉資本操作,這時候就需要委托一個人或者一個機構來作這件事。
公司首先要提出能做IPO這件事的詳細要求,然後在通過獵頭尋找合適的人選。
用代碼描述應該是這樣的:
//公司的用人協議
@protocol CompanyProtocol
-(void)doIPO;
@end
//公司類的聲明
@interface Company : NSObject
@property(nonatomic,strong)idonePerson;
-(void)stratIPO;
@end
//公司類的實現
@implementation Company
-(void)stratIPO
{
if(self.onePerson)
{
[self.onePerson doIPO];
}
}
@end
公司的聲明代碼中有一個屬性。這種模式和復合開發模式有些相似,但本質上不同。
我們拿之前通過復合模式開發的高級空調來分析。在准備要開發高級空調的時候,除甲醛的模塊已經存在,所有直接聲明一個除甲醛的屬性並且在初始化的時候為這個屬性分配內存,就可以讓空調具有除甲醛的功能。
但在描述公司的時候,我們並不知道,誰能夠帶領公司進行IPO,但是不能因為一個人崗位的人選沒有確定,而整個公司停止運轉。所有采用委托的方式,將這件事進行外包處理。公司不關心具體是哪個對象做的,但是關系這件事是否能完成。
下面我們來創建一個可以完成上市操作的對象,讓其幫助公司完成上市任務。
@interface Finance : NSObject
@end
@implementation Finance
-(void)doIPO
{
NSLog(@"開始上市!");
}
@end
現在公司和能帶領公司的人都齊全,就可以進行下一步開發了。
main()
{
Finance * per = [[Finance alloc] init];
Company * company = [[Company alloc] init];
company.onePerson = per;
[company startIPO];//當公司開始IPO時,本質上是調用Finance對象per的doIPO方法。
}
雖然從代碼上面看,是公司進行IPO,但開發本質是公司委托per對象進行IPO操作。這樣的模式就是委托模式。
委托模式的實現較為復雜,且需要根據實際應用場景進行設計。但之後我們使用的並不多,在這裡制作簡單了解即可。
委托回調模式是基於委托模式基礎上進行的事件反饋接口封裝。
仍然那上一章的開關作為講解案例。上一章我們已經知道回調的概念,已經回調的意義。核心就是讓組件的狀態能夠及時反饋到使用者。在目標動作模式下通過配置組件的回調對象和回調方法來監控組件的狀態。
本章的委托回調模式,則是通過設置組件的委托人和實現委托方法來監控組件的狀態。
委托(代理)人:從上文中公司上市的例子可以看出,公司委托財務人員進行上市操作。所以,從公司的角度看,財務人員是公司的委托人。從上市這個操作來說,財務人員是公司的代表,也稱代理人。委托人和代理人本質上是一個意思,只是從不同角度對同一個對象的不同描述。
委托(代理)方法:公司通過協議來聲明委托人的行為。作為公司的委托人,當然必須具有這些行為。協議中聲明的方法從公司角度說是委托方法,從財務人員角度來說是代理方法。
通常組件需要通過委托方法反饋自身狀態信息。使用者如果想監控組件狀態,只需作為組件的委托人,並且實現委托方法即可。
下面我們用開關做例子進行代碼的講解。
開關的聲明文件
@protocol SwitchDelegate;//前向聲明,告知編譯器SwitchDelegate為一個協議
@interface SwitchD : NSObject
typedef enum : NSUInteger {
SwitchStateOff,//default
SwitchStateOn,
} SwitchState;
@property(nonatomic,assign,readonly)SwitchState currentState;
@property(nonatomic,weak)iddelegate;
@end
@protocol SwitchDelegate
//當開關狀態改變是,會調用委托人的此方法進行狀態反饋。
-(void)switchD:(SwitchD *)s didChangeState:(SwitchState)currentState;
@end
房間的聲明文件.h
@interface Room : NSObject
@end
房間的實現文件.m
@interface Room ()
@property (strong, nonatomic) Light *aLight;
@property (strong, nonatomic) SwitchD *aSwitch;
@end
@implementation Room
- (instancetype)init
{
self = [super init];
if (self)
{
self.aLight = [[Light alloc] init];
self.aSwitch = [[SwitchD alloc] init];
//設置開關的委托人為自己(Room對象)
self.aSwitch.delegate = self;
}
return self;
}
- (void)switchD:(SwitchD *)s didChangeState:(SwitchState)currentState
{
if (currentState == SwitchStateOff)
{
[self.aLight turnOff];
}
else
{
[self.aLight turnOn];
}
}
@end
通過上述代碼,可以看出,當開關狀態改變的時候,開關對象會調用Room實現的委托方法。通過在委托方法內部的代碼,實現對開關狀態的反饋進行處理。
我們現在已經接觸兩種回調模式,這裡講解一下其中的不同和使用場景。
目標動作回調屬於簡單組件的狀態回調。其特點是靈活,用戶可以自己制定回調方法,但同時這也是目標動作回調的劣勢。由於可以自己指定回調方法,在回調時便無法對回調參數給出明確的聲明。所有,目標動作回調通常帶有一個參數,即觸發回調方法的對象本身,其他參數需要通過對象本身的屬性繼續獲取。
委托模式回調屬於復雜組件回調。其特點是回調方法提前被協議聲明好了。所有可以規定其回調參數,適合攜帶參數的事件回調。在App開發中,一般的事件都會攜帶參數,所以,具有委托回調模式接口的組件更加常見。
但委托回調也有自己的不足之處,就是如果一個類內同時有兩個相同類型的組件。那麼這兩個組件的回調方法也是相同的,我們就需要在方法內進行判斷,是哪一個組件回調了委托方法。無法實現每個組件的獨立回調。在下一章的代碼塊回調中,這個問題被完美解決。