Я пытаюсь создать FSM для управления таймером в (iphone sdk) объекте c. Я чувствовал, что это был необходимый шаг, потому что в противном случае у меня был неприятный код спагетти, содержащий страницы операторов if-then. Сложность, не читаемость и сложность добавления/изменения функций приводят меня к попытке более формального решения, подобного этому.
В контексте приложения состояние таймера определяет некоторые сложные взаимодействия с NSManagedObjects, Core Data и т.д. На данный момент я оставил всю эту функциональность, пытаясь получить четкое представление о коде FSM.
Проблема в том, что я не могу найти примеры такого кода в Obj-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;
И реализация объекта Timer:
#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>
.
Вот пример одного из классов состояний:
#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. Одной конкретной проблемой, с которой я сталкиваюсь, является создание объектов id в функции init таймера. Как вы можете видеть, я прокомментировал выпуски, потому что они вызывают предупреждение "релиз, не найденный в протоколе". Я не был уверен, как с этим справиться.
Мне не нужны комментарии о том, что этот код является излишним или бессмысленным формализмом или что-то еще. Это стоит того, чтобы я изучил это, даже если эти идеи верны. Если это поможет, подумайте об этом как о теоретическом дизайне для FSM в obj-c.
Заранее благодарим за любые полезные комментарии.
(это не помогло: Конечный автомат в Objective-C)