Question

Je cherche à construire une EFM pour contrôler une minuterie objectif (iphone sdk) c. Je sentais qu'il était une étape nécessaire, parce que je sinon finir avec le code méchant spaghetti contenant des pages de if-then. La complexité, non-lisibilité, et la difficulté d'ajouter / caractéristiques changeantes me conduisent à tenter une solution plus formelle comme celui-ci.

Dans le cadre de l'application, l'état de la minuterie détermine certaines interactions complexes avec NSManagedObjects, les données de base, et ainsi de suite. J'ai tout quitté cette fonctionnalité pour l'instant, dans une tentative d'obtenir une vision claire du code EFM.

Le problème est, je ne peux pas trouver des exemples de ce genre de code dans Obj-C, et je ne suis pas si confiant sur la façon dont je l'ai traduit du code exemple C de j'utilisais. (Je ne sais pas C ++ du tout, donc il est un peu devinant impliqués.) Je fonde cette version d'une conception de modèle d'état sur cet article: http://www.ai-junkie.com/architecture/state_driven/tut_state1.html . Je ne fais pas un jeu, mais cet article donne un aperçu des concepts qui travaillent pour ce que je fais.

Pour créer le code (affiché ci-dessous), je devais apprendre beaucoup de nouveaux concepts, y compris des protocoles obj-c, et ainsi de suite. Parce que ce sont nouveaux pour moi, tout comme le modèle de conception de l'Etat, j'espérais quelques commentaires au sujet de cette mise en œuvre. Est-ce que vous travaillez avec des objets de protocole efficacement dans obj-c?

Voici le protocole:

@class Timer;
@protocol TimerState 

-(void) enterTimerState:(Timer*)timer;
-(void) executeTimerState:(Timer*)timer;
-(void) exitTimerState:(Timer*)timer;

@end

Voici l'objet Timer (dans sa forme la plus dépouillée) fichier d'en-tête:

@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;

Et la mise en œuvre de l'objet 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

Ne vous inquiétez pas qu'il y manque des choses dans cette classe. Il ne fait rien encore intéressant. Je me bats actuellement un peu à obtenir la syntaxe correcte. il compile actuellement (et travaille), mais les appels de méthode isKindOfClass provoquent des avertissements du compilateur (méthode ne se trouve pas dans le protocole). Je ne suis pas sûr que je veux utiliser isKindOfClass de toute façon. Je pensais à donner à chaque objet id<TimerState> une chaîne de nom et en utilisant cette place.

Sur une autre note: toutes ces déclarations de id<TimerState> étaient à l'origine TimerState déclarations *. Il semblait logique de les conserver comme des propriétés. Je ne sais pas s'il est logique avec son id<TimerState>.

Voici un exemple de l'une des classes d'état:

#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

Encore une fois, jusqu'à présent, il ne fait rien sauf annoncer que quelle phase (ou sous-état), il est. Mais ce n'est pas le point.

Ce que je suis l'espoir d'apprendre est de savoir si cette architecture se compose correctement dans la langue obj-c. Un problème spécifique je rencontre est la création des objets id dans la fonction d'initialisation de la minuterie. Comme vous pouvez le voir, je commentais les communiqués, parce qu'ils étaient à l'origine un avertissement « libération non trouvé dans le protocole ». Je ne savais pas comment gérer cela.

Ce que je ne ai pas besoin est des commentaires au sujet de ce code étant formalisme excessif ou vide de sens, ou autre chose. Il vaut la peine de me apprendre ce même pas ces idées sont vraies. Si elle aide, penser comme une conception théorique pour un EFM dans obj-c.

Je vous remercie à l'avance pour les commentaires utiles.

(cela n'a pas aidé trop: Finite State Machine à Objective-C )

Était-ce utile?

La solution

Lorsque vous utilisez un protocole en tant que type de modification, vous pouvez fournir une liste séparée par des virgules des protocoles. Donc, tout ce que vous devez faire pour se débarrasser de l'avertissement du compilateur est d'ajouter NSObject à la liste des protocoles comme ceci:

- (void)setupTimer:(id<TimerState,NSObject>) timerState {

    // Create scheduled timers, etc...
}

Autres conseils

Je suggère d'utiliser , il affichera Code Objective-C . J'ai eu un bon succès dans l'utilisation de ce Java et Python.

Vous ne devriez pas être en train d'écrire le code machine d'état à la main, vous devriez utiliser quelque chose pour générer le code pour vous. SMC va générer un code propre et claire, alors vous pouvez regarder si vous voulez apprendre, ou vous pouvez simplement l'utiliser et être fait avec elle.

Si vous voulez un très simple, la mise en œuvre Objective-C d'une machine d'état que je viens de publier TransitionKit , qui fournit une API bien conçu pour la mise en œuvre des machines d'état. Il est soigneusement testé, bien documenté, très facile à utiliser et ne nécessite pas de génération de code ou des outils externes.

Je vous suggère de vérifier Statec il a un joli petit dsl pour faire EFM et sorties du code ObjC . Il est un peu comme mogenerator pour les machines d'état.

Je suis assez nouveau à Objective-C, mais je suggère que vous regardez la mise en œuvre droite ANSI C pour la machine d'état.

Tout simplement parce que vous utilisez Cocoa ne signifie pas que vous devez utiliser des messages Objective-C ici.

En ANSI C, une implémentation de la machine d'état peut être très simple et facile à lire.

Ma dernière implémentation en C d'un #define STATE_x spécifié ou EFM énumérer les types pour les états et avait une table de pointeurs vers des fonctions à exécuter chaque état.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top