之前在做公司的項目開發(fā)中泣懊,有一個模塊具有比較多的視頻編輯功能,大致畫了下面一張圖:
如上圖信夫,在編輯頁面支持剪輯卡啰,效果,濾鏡功能振湾,每個功能又有若干個子功能亡脸。按照常規(guī)的做法的話,會創(chuàng)建相對應的剪輯浅碾,效果,濾鏡view厦画,在創(chuàng)建相對應的子功能view滥朱,這樣的話,會創(chuàng)建很多視圖购裙,性能會受到影響鹃栽;或者只使用一個view躯畴,加入邏輯判斷該如何展示具體的視圖薇芝,但這個邏輯判斷就會變得很復雜。
基于以上困擾嚷缭,在某個版本項目做了次大重構耍贾,采用了GKState來管理以上復雜的剪輯功能。效果是理想的荐开。
GKState與GKStateMachine
GKState類是一個被定義了的state類,可以在GKStateMachine中使用百侧。每一個分離的不同的狀態(tài)GKState子類組成狀態(tài)機GKStateMachine能扒。GKState類提供了一個可以放置狀態(tài)依賴類型的邏輯,比如進入或脫離某個狀態(tài)時的行為辛润,又或者每一幀進行一個有效的狀態(tài)邏輯越平。
GKState的相關方法
+ (instancetype)state;
- (instancetype)init;
- (BOOL)isValidNextState:(Class)stateClass;//返回一個布爾值,該值指示當前處于該狀態(tài)的狀態(tài)機是否允許轉(zhuǎn)換到指定狀態(tài)
- (void)didEnterWithPreviousState:(nullable GKState *)previousState;//當從其他狀態(tài)轉(zhuǎn)換到該狀態(tài)時觸發(fā)的方法
- (void)updateWithDeltaTime:(NSTimeInterval)seconds;//狀態(tài)機更新時觸發(fā)的方法晦溪。
- (void)willExitWithNextState:(GKState *)nextState;//即將從當前狀態(tài)過渡到其他狀態(tài)時觸發(fā)的方法
GKStateMachine的相關方法
+ (instancetype)stateMachineWithStates:(NSArray<GKState *> *)states;
- (instancetype)initWithStates:(NSArray<GKState *> *)states;
- (void)updateWithDeltaTime:(NSTimeInterval)sec;//更新狀態(tài)機
- (nullable GKState*)stateForClass:(Class)stateClass;//通過stateClass獲取GKState
- (BOOL)canEnterState:(Class)stateClass;//判斷是否可以進入stateClass
- (BOOL)enterState:(Class)stateClass;//進入stateClass
GKStateMachine管理的是GKState挣跋,也就是狀態(tài)機管理狀態(tài)。
在接入了GKState之后舟肉,上面的示意圖就變成了下面這樣:
1.編輯的下面有剪輯路媚,效果樊销,濾鏡三個子狀態(tài)脏款,剪輯裤园,效果,濾鏡又分別有自己的子狀態(tài)拧揽。
2.編輯(mainState)會有一個實例對象GKStateMachine淤袜,管理剪輯,效果饮怯,濾鏡三個子狀態(tài)嚎研,通過這個實例對象GKStateMachine,可以enterState:
進入子狀態(tài)论矾。
3..剪輯杆勇,效果,濾鏡屬于同一層級的狀態(tài)闰靴,他們互為兄弟狀態(tài)钻注,被同一個GKStateMachine實例對象管理。如果剪輯狀態(tài)能訪問到這個實例對象GKStateMachine幅恋,就可以通過實例對象GKStateMachine實現(xiàn)跳轉(zhuǎn)到效果,濾鏡的狀態(tài)淑翼,實現(xiàn)了同層級的狀態(tài)間的跳轉(zhuǎn)品追。
4.在狀態(tài)的進入與退出時,會調(diào)用到didEnterWithPreviousState:
和willExitWithNextState:
,那么相對應狀態(tài)下的視圖創(chuàng)建布局銷毀遭京,展示邏輯等就可以在這里開始編寫。GKState提供了一套state生命周期的回調(diào)方法蛹疯。
基于以上邏輯热监,可以在進入狀態(tài)時,創(chuàng)建對應的UI展示和邏輯孝扛,離開狀態(tài)時,銷毀對應的UI寞钥。
代碼實踐:
首先創(chuàng)建繼承自GKState的基類XYBaseState陌选。
@interface XYBaseState : GKState
//主vc
@property (nonatomic, weak) UIViewController *rootVC;
//父視圖
@property (nonatomic, weak) UIView *fatherView;
//父狀態(tài)
@property (nonatomic, weak) GKState *fatherState;
//當前狀態(tài)下的視圖布局都是基于contentView咨油,加在fatherView上
@property (nonatomic, strong) UIView *contentView;
//管理子狀態(tài)的狀態(tài)機
@property (nullable, nonatomic, strong) XYBaseStateMachine *childStateMachine;
//管理兄弟狀態(tài)的狀態(tài)機
@property (nullable, nonatomic, weak) XYBaseStateMachine *brotherStateMachine;
//全局共享的數(shù)據(jù)板
@property (nonatomic, strong) id commonDataBoard;
@end
@implementation XYBaseState
- (instancetype)init
{
if (self = [super init]) {
}
return self;
}
- (UIView *)contentView
{
if (!_contentView) {
_contentView = [[UIView alloc]init];
}
return _contentView;
}
- (void)didEnterWithPreviousState:(XYBaseState *)preState
{
[self freeChildStates:preState];
[super didEnterWithPreviousState:preState];
[self.fatherView addSubview:self.contentView];
[self loadChildStates];
}
/*
前一個狀態(tài)節(jié)點的子狀態(tài)以及contentView實時釋放,從而可以及時
釋放部分內(nèi)存赚爵,盡可能做到內(nèi)存輕量化
*/
- (void)freeChildStates:(XYBaseState *)preState
{
[preState.childStateMachine.currentState willExitWithNextState:[XYBaseState new]];
preState.childStateMachine = nil;
}
- (void)willExitWithNextState:(XYBaseState *)nextState
{
[super willExitWithNextState:nextState];
[_contentView removeFromSuperview];
_contentView = nil;
}
//子類繼承實現(xiàn)
- (NSArray *)childViewStates
{
return @[];
}
- (void)loadChildStates
{
NSMutableArray *viewStates = [NSMutableArray array];
for (NSString *obj in [self childViewStates]) {
Class class = NSClassFromString(obj);
if (!class) continue;
__kindof XYBaseState *state = [[class alloc]init];
state.rootVC = self.rootVC;
state.fatherView = self.contentView;
state.commonDataBoard = self.commonDataBoard;
[viewStates addObject:state];
}
self.childStateMachine = [[XYBaseStateMachine alloc] initWithStates:viewStates];
//對于每種狀態(tài)冀膝,它的子狀態(tài)之間霎挟,互為兄弟狀態(tài)
for (XYBaseViewState *state in viewStates) {
state.brotherStateMachine = self.childStateMachine;
}
}
@end
以上圖的效果狀態(tài)為例,創(chuàng)建效果state
@implementation EffectState
- (NSArray *)childStates
{
self.subStateArray = @[@"subStickerState",@"subTextState"];
return self.subStateArray;
}
- (void)didEnterWithPreviousState:(nullable GKState *)previousState
{
[super didEnterWithPreviousState:previousState];
[self configData];
[self configSubviews];
}
- (void) configData {
NSLog(@"initData");
}
- (void) configSubviews
{
NSLog(@"configSubviews");
}
- (void)willExitWithNextState:(GKState *)nextState
{
[super willExitWithNextState:nextState];
//在這里釋放資源,降低內(nèi)存消耗
[self removeView];
[self removeData];
}
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
//進入子狀態(tài)
[self.childStateMachine enterState:self.subStateArray[indexPath.row]];
}
- (void)removeData {
}
- (void) removeView {
}
基于此枯芬,就可以把效果狀態(tài)的UI和邏輯進行單獨處理采郎,當有很多個state需要管理的時候,在代碼維護和功能擴展上就方便了很多淫痰。