iOS架構(gòu):AOP實(shí)現(xiàn)局部解耦

一、寫在前面

前些時(shí)間聽朋友說(shuō)了一個(gè)話題,利用 AOP 解耦細(xì)節(jié)業(yè)務(wù),確實(shí)有趣。因?yàn)槲覀兺ǔG闆r下說(shuō)起 AOP,都會(huì)想起比如“埋點(diǎn)”、“method swizzing”等字眼,角度比較宏觀。AOP 國(guó)內(nèi)開發(fā)者喜歡稱之為面向切面編程,其作為面向?qū)ο缶幊痰囊环N補(bǔ)充,在實(shí)際業(yè)務(wù)場(chǎng)景中發(fā)揮著巨大作用。

二、為什么使用 AOP

面向切面編程,也可以理解為面向功能面編程,將某一特定的功能視為一個(gè)切面,不但可以復(fù)用代碼,還可以使代碼邏輯更加清晰,更符合單一功能設(shè)計(jì)原則。

在 iOS 開發(fā)中,經(jīng)常會(huì)有這種需求,比如需要記錄進(jìn)入每一個(gè)控制器的次數(shù)。最次的方案就是在每一個(gè)控制器的viewWillApear:方法里面寫記錄代碼;稍優(yōu)一點(diǎn)的方案是在基類的viewWillApear:里面寫記錄代碼,但是這種方法有個(gè)弊端就是只有繼承于基類的控制器才能記錄到,不友好;而最優(yōu)的方式就是利用runtime的method swizzing交換方法,hook住viewWillApear:在里面做記錄邏輯。

當(dāng)然,本文是為了解決另外一個(gè)問(wèn)題。

在 iOS App 中,MVC 和 MVVM 是比較流行的架構(gòu)模式,而當(dāng)某個(gè)界面業(yè)務(wù)量達(dá)到一個(gè)程度過(guò)后,MVVM 甚至是 VIPER 模式都顯得有些力不從心,為了達(dá)到更高層次的解耦,往往會(huì)做其他方面的工作,比如講Scrollview等代理的配置獨(dú)立出來(lái),然而這種方式仍然有個(gè)弊端,那就是代理方法里面的邏輯太多導(dǎo)致獨(dú)立出來(lái)的類仍然臃腫。

所以,這就是寫這篇文章的目的,提供一種更深層次的解耦的方案。


三、實(shí)際應(yīng)用

其實(shí)之前我對(duì) AOP 的思想還不是很了解,后來(lái)發(fā)現(xiàn)其實(shí)我已經(jīng)在之前的框架中有了應(yīng)用,實(shí)現(xiàn)該架構(gòu)實(shí)現(xiàn)的主要技術(shù)點(diǎn)是:利用方法重定向?qū)崿F(xiàn)多接收者的方法轉(zhuǎn)發(fā)。

詳情可看這篇文章,文章中間部分有對(duì)消息轉(zhuǎn)發(fā)流程的簡(jiǎn)述:

iOS解決方案:文本輸入控制(獻(xiàn)上框架)

本文就不講解消息發(fā)送機(jī)制了,在 Demo 中有封裝 ——YBAOPManager,我們將利用它來(lái)做局部解耦。

在實(shí)際業(yè)務(wù)需求中,出場(chǎng)率很高的是UITalbeView和UICollecitonView等需要用大量代理方法配置的視圖,當(dāng)然這是蘋果程序設(shè)計(jì)的慣例。當(dāng)UI界面很復(fù)雜,業(yè)務(wù)邏輯相當(dāng)多的時(shí)候,雖然把網(wǎng)絡(luò)請(qǐng)求、數(shù)據(jù)處理、視圖封裝等都解耦出去了,但是配置代理里面的邏輯太多,我們想要每一個(gè)類處理一部分代理方法。

Demo 以 UITableView 為例。

首先,創(chuàng)建實(shí)現(xiàn) UITableView 代理的三個(gè)類:


@implementation?TestTableViewDigitConfig

-?(NSInteger)tableView:(UITableView?*)tableView?numberOfRowsInSection:(NSInteger)section?{

????return?20;

}

-?(CGFloat)tableView:(UITableView?*)tableView?heightForRowAtIndexPath:(NSIndexPath?*)indexPath?{

????return?80;

}

@end


@implementation?TestTableViewClickConfig

-?(void)tableView:(UITableView?*)tableView?didSelectRowAtIndexPath:(NSIndexPath?*)indexPath?{

????NSLog(@"click?--?section:%ld,?row:%ld",?indexPath.section,?indexPath.row);

}

@end


@implementation?TestTableViewCellConfig

-?(UITableViewCell?*)tableView:(UITableView?*)tableView?cellForRowAtIndexPath:(NSIndexPath?*)indexPath?{

????UITableViewCell?*cell?=?[tableView?dequeueReusableCellWithIdentifier:NSStringFromClass(UITableViewCell.class)];

????if?(!cell)?{

????????cell.selectionStyle?=?UITableViewCellSelectionStyleNone;

????????cell?=?[[UITableViewCell?alloc]?initWithStyle:UITableViewCellStyleValue1?reuseIdentifier:NSStringFromClass(UITableViewCell.class)];

????}

????cell.textLabel.text?=?[NSString?stringWithFormat:@"第%ld行",?indexPath.row];

????return?cell;

}

@end

如代碼所見(jiàn),這里將 tableView 的代理用三個(gè)類來(lái)分別實(shí)現(xiàn),然后在 UIViewController 里面只需要寫這些代碼:


@interface?TestVC?()

@property?(nonatomic,?strong)?UITableView?*tableView;

@property?(nonatomic,?strong)?YBAOPManager?*aopManager;

@property?(nonatomic,?strong)?TestTableViewDigitConfig?*digitConfig;

@property?(nonatomic,?strong)?TestTableViewClickConfig?*clickConfig;

@property?(nonatomic,?strong)?TestTableViewCellConfig?*cellConfig;

@end

@implementation?TestVC

#pragma?mark?life?cycle

-?(void)viewDidLoad?{

????[super?viewDidLoad];

????[self.view?addSubview:self.tableView];

}

#pragma?mark?getter

-?(UITableView?*)tableView?{

????if?(!_tableView)?{

????????_tableView?=?[[UITableView?alloc]?initWithFrame:[UIScreen?mainScreen].bounds?style:UITableViewStylePlain];

????????_tableView.tableFooterView?=?[UIView?new];


????????_digitConfig?=?[TestTableViewDigitConfig?new];

????????_clickConfig?=?[TestTableViewClickConfig?new];

????????_cellConfig?=?[TestTableViewCellConfig?new];


????????_aopManager?=?[YBAOPManager?new];

????????[_aopManager?addTarget:_digitConfig];

????????[_aopManager?addTarget:_clickConfig];

????????[_aopManager?addTarget:_cellConfig];


????????_tableView.delegate?=?_aopManager;

????????_tableView.dataSource?=?_aopManager;

????}

????return?_tableView;

}

@end

核心代碼就是將YBAOPManager類的使用:

當(dāng)你需要使用多個(gè)對(duì)象(target)來(lái)承接一些方法的實(shí)現(xiàn),初始化 YBAOPManager 實(shí)例,將這些對(duì)象實(shí)例添加到

YBAOPManager 實(shí)例中(addTarget),最后將 YBAOPManager 實(shí)例作為這些方法的第一承接者。剩下的方法分發(fā)工作就交給該類了。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 概述在iOS開發(fā)中UITableView可以說(shuō)是使用最廣泛的控件,我們平時(shí)使用的軟件中到處都可以看到它的影子,類似...
    liudhkk閱讀 9,289評(píng)論 3 38
  • UITableViewCell控件空間構(gòu)造 cell的子控件是contentView,contentView的子控...
    CoderZXS閱讀 845評(píng)論 0 1
  • 前言 最近忙完項(xiàng)目比較閑,想寫一篇博客來(lái)分享一些自學(xué)iOS的心得體會(huì),希望對(duì)迷茫的你有所幫助。博主非科班出身,一些...
    GitHubPorter閱讀 1,574評(píng)論 9 5
  • #pragma mark someValueAboutTableView 1.tableView的樣式:UITab...
    瀟巖閱讀 1,049評(píng)論 0 0
  • 華子的人生蛻變之旅原創(chuàng)458篇 2018年3月15日 星期四 陰有雨(農(nóng)歷正月二十八) 此刻,在火車上轟隆轟...
    譽(yù)仔媽媽閱讀 260評(píng)論 3 6

友情鏈接更多精彩內(nèi)容