Objective-Cでの基本的な有限状態機械を作る方法
-
18-09-2019 - |
質問
私は(iPhoneのSDK)Objective Cの中にタイマーを制御するFSMを構築しようとしています。私はそうでない場合-then文のページを含む厄介なスパゲッティコードで終わるたので、私は、それが必要なステップだと感じました。複雑、非可読性、および追加の難しさは、/変更する機能は、このような、より正式な解決策を試みるために私をリードしています。
アプリケーションの文脈において、タイマの状態はNSManagedObjects、コアデータといくつかの複雑な相互作用を決定する、等。私は、FSMコードのクリアな視界を得るための試みで、今のところすべてが機能性を残しています。
トラブルは、私はOBJの-Cのコードのこの種のいずれかの例を見つけることができませんされ、そして私は私が使っていたC ++のコード例からそれを翻訳しているかについてとても自信がないです。 (私はC ++ですべてを知りませんので、いくつかの推測関与があります。)私はこの記事の状態パターンのデザインのこのバージョン基づかています:<のhref = "http://www.ai-junkie.com/architectureを/state_driven/tut_state1.html」のrel = "nofollowをnoreferrer"> 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>
ので理にかなっているかどうかわかりません。
ここでは、状態クラスの一つの例である:
#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のための理論的な設計と考えます。
任意の有用なコメントのために事前にありがとうございます。
(これはあまり役に立ちませんでした:有限状態マシンをObjective-Cで)
解決
あなたは、型修飾子などのプロトコルを使用する場合、あなたはプロトコルのカンマ区切りのリストを提供することができます。ですから、コンパイラの警告を取り除くために行う必要があるすべてはそうのようなプロトコルリストにNSObjectのを追加されます:
- (void)setupTimer:(id<TimerState,NSObject>) timerState {
// Create scheduled timers, etc...
}
他のヒント
私はステートマシンコンパイラに、それの出力は以下となり<のhref = "HTTPを使用することをお勧め:// SMC。 sourceforge.net/SmcManSec3.htm#ObjC」REL = "noreferrer">のObjective-C のコード。私はこれを使用してJavaとPythonで良い成功を収めている。
あなたはあなたのためのコードを生成するために何かを使用する必要があり、手でステート・マシン・コードを書くべきではありません。 SMCは、あなたがそれから学びたい場合は、その後で見ることができる、またはあなたはそれを使用することができますし、それを行うことがクリーンな明確なコードを生成します。
あなたはステートマシンの非常にシンプルな、Objective-Cの実装をしたい場合、私はちょうどリリースした TransitionKit 、ステートマシンを実装するためのうまく設計されたAPIを提供します。徹底的にも非常に使いやすい、文書化、および任意のコード生成や外部ツールを必要としない、テストされています。
私は Statec のそれはFSMを行うためのちょっといいDSLを持って、にObjCコードを出力していますチェックアウトすることをお勧めしたいです。それは一種の状態マシンのmogeneratorのようなものです。
私は、Objective-Cのではなく、新しいですが、私はあなたのステートマシンのためにストレートANSI Cの実装を見ていることを示唆しています。
ちょうどあなたがココアを使用しているので、あなたがここにObjective-Cのメッセージを使用する必要が意味するものではありません。
ANSI Cにおいては、状態マシンの実装が非常に簡単で読み取ることができます。
FSMのCに私の最後の実装が#define STATE_x
指定または状態の種類を列挙し、各状態を実行する関数へのポインタのテーブルを持っています。