我正在尝试构建一个 FSM 来控制(iphone sdk)目标 c 中的计时器。我觉得这是一个必要的步骤,因为否则我会得到包含 if-then 语句页面的令人讨厌的意大利面条代码。添加/更改功能的复杂性、不可读性和困难性导致我尝试像这样更正式的解决方案。
在应用程序的上下文中,计时器的状态决定了与 NSManagedObjects、Core Data 等的一些复杂交互。我暂时忽略了所有这些功能,试图清楚地了解 FSM 代码。
问题是,我在 Obj-C 中找不到此类代码的任何示例,而且我对如何从我正在使用的 C++ 示例代码中翻译它并不太自信。(我根本不懂 C++,所以有一些猜测。)我将这个版本的状态模式设计基于这篇文章:http://www.ai-junkie.com/architecture/state_driven/tut_state1。 .html _ 我不是在制作游戏,但本文概述了适用于我正在做的事情的概念。
为了创建代码(发布在下面),我必须学习很多新概念,包括 obj-c 协议等等。因为这些对我来说是新的,就像状态设计模式一样,我希望得到一些关于这个实现的反馈。这是您在 obj-c 中有效地使用协议对象的方式吗?
这是协议:
@class Timer;
@protocol TimerState
-(void) enterTimerState:(Timer*)timer;
-(void) executeTimerState:(Timer*)timer;
-(void) exitTimerState:(Timer*)timer;
@end
这是 Timer 对象(最精简的形式)头文件:
@interface Timer : NSObject
{
id<TimerState> currentTimerState;
NSTimer *secondTimer;
id <TimerViewDelegate> viewDelegate;
id<TimerState> setupState;
id<TimerState> runState;
id<TimerState> pauseState;
id<TimerState> resumeState;
id<TimerState> finishState;
}
@property (nonatomic, retain) id<TimerState> currentTimerState;
@property (nonatomic, retain) NSTimer *secondTimer;
@property (assign) id <TimerViewDelegate> viewDelegate;
@property (nonatomic, retain) id<TimerState> setupState;
@property (nonatomic, retain) id<TimerState> runState;
@property (nonatomic, retain) id<TimerState> pauseState;
@property (nonatomic, retain) id<TimerState> resumeState;
@property (nonatomic, retain) id<TimerState> finishState;
-(void)stopTimer;
-(void)changeState:(id<TimerState>) timerState;
-(void)executeState:(id<TimerState>) timerState;
-(void) setupTimer:(id<TimerState>) timerState;
以及定时器对象的实现:
#import "Timer.h"
#import "TimerState.h"
#import "Setup_TS.h"
#import "Run_TS.h"
#import "Pause_TS.h"
#import "Resume_TS.h"
#import "Finish_TS.h"
@implementation Timer
@synthesize currentTimerState;
@synthesize viewDelegate;
@synthesize secondTimer;
@synthesize setupState, runState, pauseState, resumeState, finishState;
-(id)init
{
if (self = [super init])
{
id<TimerState> s = [[Setup_TS alloc] init];
self.setupState = s;
//[s release];
id<TimerState> r = [[Run_TS alloc] init];
self.runState = r;
//[r release];
id<TimerState> p = [[Pause_TS alloc] init];
self.pauseState = p;
//[p release];
id<TimerState> rs = [[Resume_TS alloc] init];
self.resumeState = rs;
//[rs release];
id<TimerState> f = [[Finish_TS alloc] init];
self.finishState = f;
//[f release];
}
return self;
}
-(void)changeState:(id<TimerState>) newState{
if (newState != nil)
{
[self.currentTimerState exitTimerState:self];
self.currentTimerState = newState;
[self.currentTimerState enterTimerState:self];
[self executeState:self.currentTimerState];
}
}
-(void)executeState:(id<TimerState>) timerState
{
[self.currentTimerState executeTimerState:self];
}
-(void) setupTimer:(id<TimerState>) timerState
{
if ([timerState isKindOfClass:[Run_TS class]])
{
secondTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(currentTime) userInfo:nil repeats:YES];
}
else if ([timerState isKindOfClass:[Resume_TS class]])
{
secondTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(currentTime) userInfo:nil repeats:YES];
}
}
-(void) stopTimer
{
[secondTimer invalidate];
}
-(void)currentTime
{
//This is just to see it working. Not formatted properly or anything.
NSString *text = [NSString stringWithFormat:@"%@", [NSDate date]];
if (self.viewDelegate != NULL && [self.viewDelegate respondsToSelector:@selector(updateLabel:)])
{
[self.viewDelegate updateLabel:text];
}
}
//TODO: releases here
- (void)dealloc
{
[super dealloc];
}
@end
不用担心这堂课有遗漏的东西。它还没有做任何有趣的事情。我目前正在努力使语法正确。目前它可以编译(并且可以工作),但是 isKindOfClass 方法调用会导致编译器警告(在协议中找不到该方法)。我不确定我是否要使用 isKindOfClass 。我正在考虑给每个id<TimerState>
对象一个名称字符串并改用它。
另一方面:所有这些id<TimerState>
声明最初都是 TimerState * 声明。将它们保留为属性似乎是有意义的。不确定id<TimerState>
's 是否有意义。
以下是其中一个状态类的示例:
#import "TimerState.h"
@interface Setup_TS : NSObject <TimerState>{
}
@end
#import "Setup_TS.h"
#import "Timer.h"
@implementation Setup_TS
-(void) enterTimerState:(Timer*)timer{
NSLog(@"SETUP: entering state");
}
-(void) executeTimerState:(Timer*)timer{
NSLog(@"SETUP: executing state");
}
-(void) exitTimerState:(Timer*)timer{
NSLog(@"SETUP: exiting state");
}
@end
同样,到目前为止,除了宣布它处于哪个阶段(或子状态)之外,它什么也没做。但这不是重点。
我希望在这里学到的是这个架构是否用 obj-c 语言正确组合。我遇到的一个具体问题是在计时器的 init 函数中创建 id 对象。如您所见,我注释掉了这些版本,因为它们导致了“在协议中找不到版本”警告。我不知道如何处理。
我不需要的是关于此代码过度杀伤或无意义的形式主义或其他什么的评论。即使这些想法是正确的,我也值得学习这一点。如果有帮助,请将其视为 obj-c 中 FSM 的理论设计。
预先感谢您提供任何有用的意见。
(这并没有太大帮助:Finite State Machine in Objective-C)