From e13389bf76fabf342da22022192a0ac5387f5357 Mon Sep 17 00:00:00 2001 From: Graham Oldfield Date: Mon, 30 Jun 2014 14:05:12 +0100 Subject: [PATCH 1/6] Added (void)dispatchEvent:(NSString*)event withPayload:(id)payLoad --- YBStatechart/YBStatechart.h | 11 ++++++++++- YBStatechart/YBStatechart.m | 37 ++++++++++++++++++++----------------- 2 files changed, 30 insertions(+), 18 deletions(-) diff --git a/YBStatechart/YBStatechart.h b/YBStatechart/YBStatechart.h index d5f34c5..2d4bd26 100644 --- a/YBStatechart/YBStatechart.h +++ b/YBStatechart/YBStatechart.h @@ -19,7 +19,7 @@ extern NSString *YBStateExitStateEvent; The state object itself is passed to the block as the first argument. @param _self : The state object to which the handler belongs. */ -typedef void(^YBStateEventHandler)(YBState *_self); +typedef void(^YBStateEventHandler)(YBState *_self , id payload); @@ -86,6 +86,15 @@ typedef void(^YBStateEventHandler)(YBState *_self); */ - (void)dispatchEvent:(NSString*)event; +/** + Dispatches the given event to the active states in the statechart, causing the registered handlers to get called. + This method will also be called when an unknown message with no arguments and void return type is sent to a statechart, e.g.: + Sending [statechart buttonUp] will result in [statechart dispatchEvent:@"buttonUp"]. + @param event - The event to dispatch. + @param payLoad - Payload to dispatch with the event for context. + */ +- (void)dispatchEvent:(NSString*)event withPayload:(id)payLoad; + @end diff --git a/YBStatechart/YBStatechart.m b/YBStatechart/YBStatechart.m index 9ee9fbc..2681087 100644 --- a/YBStatechart/YBStatechart.m +++ b/YBStatechart/YBStatechart.m @@ -38,8 +38,7 @@ - (void)activateDefaultSubstatesRecursive:(BOOL)recursive saveToHistory:(BOOL)sa - (void)activateSubstate:(YBState*)substate saveToHistory:(BOOL)saveToHistory; - (void)deactivate; - (void)deactivateSubstatesExcept:(YBState*)exceptSubstate recursive:(BOOL)recursive; -- (void)handleEvent:(NSString*)event; -- (NSMutableArray*)collectActiveSubstates; +- (void)handleEventAndDispatchToActiveSubstates:(NSString*)event withPayload:(id)payLoad; #if DEBUG - (BOOL)debugValidate; #endif @@ -157,12 +156,14 @@ - (void)activateState:(YBState*)state saveToHistory:(BOOL)saveToHistory { [state activateDefaultSubstatesRecursive:YES saveToHistory:saveToHistory]; } -- (void)dispatchEvent:(NSString*)event { +- (void)dispatchEvent:(NSString*)event withPayload:(id)payLoad { NSAssert(_rootState != nil, @"No rootState set."); - NSArray* activeSubstates = [_rootState collectActiveSubstates]; - [activeSubstates enumerateObjectsUsingBlock:^(YBState* state, NSUInteger idx, BOOL *stop) { - [state handleEvent: event]; - }]; + [_rootState handleEventAndDispatchToActiveSubstates:event withPayload:payLoad]; +} + + +- (void)dispatchEvent:(NSString*)event { + [self dispatchEvent:event withPayload:nil]; } - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector { @@ -407,14 +408,14 @@ - (void)activateDefaultSubstatesRecursive:(BOOL)recursive saveToHistory:(BOOL)sa - (void)deactivate { if (_active == YES) { _active = NO; - [self handleEvent:YBStateExitStateEvent]; + [self handleEvent:YBStateExitStateEvent withPayload:nil]; } } - (void)activate { if (_active == NO) { _active = YES; - [self handleEvent:YBStateEnterStateEvent]; + [self handleEvent:YBStateEnterStateEvent withPayload:nil]; } } @@ -437,24 +438,26 @@ - (void)activateSubstate:(YBState*)substate saveToHistory:(BOOL)saveToHistory { } } -- (NSMutableArray *)collectActiveSubstates { - NSMutableArray *activeSubstates = [[NSMutableArray alloc] initWithObjects: self, nil]; - if ([_substates count] == 1) { - [activeSubstates addObjectsFromArray: [[_substates anyObject] collectActiveSubstates]]; +- (void)handleEventAndDispatchToActiveSubstates:(NSString*)event withPayload:(id)payLoad { + [self handleEvent:event withPayload:payLoad]; + + if ([_substates count] == 0) { + return; + } else if ([_substates count] == 1) { + [[_substates anyObject] handleEventAndDispatchToActiveSubstates:event withPayload:payLoad]; } else { [_substates enumerateObjectsUsingBlock:^(YBState *substate, BOOL *stop) { if (substate->_active) { - [activeSubstates addObjectsFromArray: [substate collectActiveSubstates]]; + [substate handleEventAndDispatchToActiveSubstates:event withPayload:payLoad]; } }]; } - return activeSubstates; } -- (void)handleEvent:(NSString*)event { +- (void)handleEvent:(NSString*)event withPayload:(id)payLoad { YBStateEventHandler handler = [_eventHandlers objectForKey:event]; if (handler) { - handler(self); + handler(self,payLoad); } } From 8d144f55b9bbddc24d4e2d5a162537ab78daa797 Mon Sep 17 00:00:00 2001 From: GrahO23 Date: Mon, 30 Jun 2014 14:07:08 +0100 Subject: [PATCH 2/6] Update README.md --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ecd4ca9..1e04fbb 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ -YBStatechart -============ +YBStatechart with Payloads +========================== + +Fork of YBStateChart with the ability to dispatch payloads with events, also soon to come the ability to dispatch a payload with a state change. YBStatechart is a statechart framework. Statecharts are a formalized type of finite state machine, which resulted from [David Harel's research] [1] on software architecture design for aircraft systems in 1986. His [white paper article] [1] is well worth the (somewhat lengthy) read. From a3cfcc9548905853524839e013fcbb22aabac926 Mon Sep 17 00:00:00 2001 From: Graham Oldfield Date: Mon, 30 Jun 2014 14:21:03 +0100 Subject: [PATCH 3/6] Fixed unit tests for payload --- YBStatechart.xcodeproj/project.pbxproj | 27 ++++++++++++++++--- .../xcschemes/YBStatechart.xcscheme | 1 + YBStatechart/YBStatechart-Prefix.pch | 0 YBStatechartTests/YBStatechartTests.m | 4 +-- 4 files changed, 27 insertions(+), 5 deletions(-) create mode 100644 YBStatechart/YBStatechart-Prefix.pch diff --git a/YBStatechart.xcodeproj/project.pbxproj b/YBStatechart.xcodeproj/project.pbxproj index 80602e8..0379944 100644 --- a/YBStatechart.xcodeproj/project.pbxproj +++ b/YBStatechart.xcodeproj/project.pbxproj @@ -15,6 +15,7 @@ 102591BE1521143200B11680 /* libYBStatechart.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 102591A61521143200B11680 /* libYBStatechart.a */; }; 102591C71521143200B11680 /* YBStatechartTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 102591C61521143200B11680 /* YBStatechartTests.m */; }; 102591D41522A3FA00B11680 /* YBStatechart.h in Headers */ = {isa = PBXBuildFile; fileRef = 102591AE1521143200B11680 /* YBStatechart.h */; settings = {ATTRIBUTES = (); }; }; + 813FBBD919619B6D005E0811 /* YBStatechart-Prefix.pch in Headers */ = {isa = PBXBuildFile; fileRef = 813FBBD819619B6D005E0811 /* YBStatechart-Prefix.pch */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -40,6 +41,7 @@ 102591C61521143200B11680 /* YBStatechartTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = YBStatechartTests.m; sourceTree = ""; }; 5262D63C1651980C008A3670 /* YBStatechart.podspec */ = {isa = PBXFileReference; lastKnownFileType = text; path = YBStatechart.podspec; sourceTree = SOURCE_ROOT; }; 5262D6521651C3A7008A3670 /* LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE; sourceTree = SOURCE_ROOT; }; + 813FBBD819619B6D005E0811 /* YBStatechart-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "YBStatechart-Prefix.pch"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -127,6 +129,7 @@ children = ( 5262D63C1651980C008A3670 /* YBStatechart.podspec */, 5262D6521651C3A7008A3670 /* LICENSE */, + 813FBBD819619B6D005E0811 /* YBStatechart-Prefix.pch */, ); name = "Supporting Files"; sourceTree = ""; @@ -139,6 +142,7 @@ buildActionMask = 2147483647; files = ( 102591D41522A3FA00B11680 /* YBStatechart.h in Headers */, + 813FBBD919619B6D005E0811 /* YBStatechart-Prefix.pch in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -188,7 +192,7 @@ isa = PBXProject; attributes = { CLASSPREFIX = YB; - LastUpgradeCheck = 0440; + LastUpgradeCheck = 0510; ORGANIZATIONNAME = Yobble; }; buildConfigurationList = 102591A01521143200B11680 /* Build configuration list for PBXProject "YBStatechart" */; @@ -267,8 +271,13 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; @@ -279,10 +288,14 @@ ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 5.0; + ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; }; name = Debug; @@ -291,13 +304,21 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 5.0; SDKROOT = iphoneos; diff --git a/YBStatechart.xcodeproj/xcshareddata/xcschemes/YBStatechart.xcscheme b/YBStatechart.xcodeproj/xcshareddata/xcschemes/YBStatechart.xcscheme index 622730a..c871eae 100644 --- a/YBStatechart.xcodeproj/xcshareddata/xcschemes/YBStatechart.xcscheme +++ b/YBStatechart.xcodeproj/xcshareddata/xcschemes/YBStatechart.xcscheme @@ -1,5 +1,6 @@ Date: Mon, 30 Jun 2014 16:16:23 +0100 Subject: [PATCH 4/6] Added payload to activate Event --- YBStatechart/YBStatechart.h | 7 ++++ YBStatechart/YBStatechart.m | 70 ++++++++++++++++++++++++------------- 2 files changed, 53 insertions(+), 24 deletions(-) diff --git a/YBStatechart/YBStatechart.h b/YBStatechart/YBStatechart.h index 2d4bd26..6e114d2 100644 --- a/YBStatechart/YBStatechart.h +++ b/YBStatechart/YBStatechart.h @@ -56,10 +56,17 @@ typedef void(^YBStateEventHandler)(YBState *_self , id payload); Methods to activate a given state in the statechart, either by passing in the state object itself or by passing in the name of the state. By default, automatic setting the historySubstate is enabled, but can be disabled using the saveToHistory argument. */ + + + - (void)activateStateWithName:(NSString*)stateName; +- (void)activateStateWithName:(NSString*)stateName withPayload:(id)payload; - (void)activateStateWithName:(NSString*)stateName saveToHistory:(BOOL)saveToHistory; +- (void)activateStateWithName:(NSString*)stateName saveToHistory:(BOOL)saveToHistory withPayload:(id)payload; - (void)activateState:(YBState*)state; +- (void)activateState:(YBState*)state withPayload:(id)payload; - (void)activateState:(YBState*)state saveToHistory:(BOOL)saveToHistory; +- (void)activateState:(YBState*)state saveToHistory:(BOOL)saveToHistory withPayload:(id)payload; /** Activates the statechart. All initial and/or history substates will be entered/activated. diff --git a/YBStatechart/YBStatechart.m b/YBStatechart/YBStatechart.m index 2681087..21225f7 100644 --- a/YBStatechart/YBStatechart.m +++ b/YBStatechart/YBStatechart.m @@ -33,9 +33,9 @@ @interface YBState () { BOOL _useHistory; } - (void)setStatechart:(YBStatechart*)statechart; -- (void)activate; -- (void)activateDefaultSubstatesRecursive:(BOOL)recursive saveToHistory:(BOOL)saveToHistory; -- (void)activateSubstate:(YBState*)substate saveToHistory:(BOOL)saveToHistory; +- (void)activate:(id)payload ; +- (void)activateDefaultSubstatesRecursive:(BOOL)recursive saveToHistory:(BOOL)saveToHistory withPayload:(id)payload; +- (void)activateSubstate:(YBState*)substate saveToHistory:(BOOL)saveToHistory withPayload:(id)payload ; - (void)deactivate; - (void)deactivateSubstatesExcept:(YBState*)exceptSubstate recursive:(BOOL)recursive; - (void)handleEventAndDispatchToActiveSubstates:(NSString*)event withPayload:(id)payLoad; @@ -118,27 +118,47 @@ - (YBState*)findStateWithName:(NSString*)stateName { return [_registeredStates objectForKey:stateName]; } -- (void)activateStateWithName:(NSString*)stateName { - [self activateStateWithName:stateName saveToHistory:YES]; + +- (void)activateStateWithName:(NSString*)stateName{ + [self activateStateWithName:stateName withPayload:nil]; +} + + +- (void)activateStateWithName:(NSString*)stateName saveToHistory:(BOOL)saveToHistory{ + [self activateStateWithName:stateName saveToHistory:saveToHistory withPayload:nil]; +} + +- (void)activateState:(YBState*)state{ + [self activateState:state withPayload:nil]; +} + + +- (void)activateState:(YBState*)state saveToHistory:(BOOL)saveToHistory{ + [self activateState:state saveToHistory:saveToHistory withPayload:nil]; } -- (void)activateStateWithName:(NSString*)stateName saveToHistory:(BOOL)saveToHistory { + +- (void)activateStateWithName:(NSString*)stateName withPayload:(id)payload{ + [self activateStateWithName:stateName saveToHistory:YES withPayload:payload]; +} + +- (void)activateStateWithName:(NSString*)stateName saveToHistory:(BOOL)saveToHistory withPayload:(id)payload { YBState *state = [self findStateWithName:stateName]; NSAssert(state != nil, @"Couldn't find state with name: %@", stateName); if (state->_active) { return; } - [self activateState:state saveToHistory:saveToHistory]; + [self activateState:state saveToHistory:saveToHistory withPayload:payload]; } -- (void)activateState:(YBState*)state { +- (void)activateState:(YBState*)state withPayload:(id)payload{ if (state->_active) { return; } - [self activateState:state saveToHistory:YES]; + [self activateState:state saveToHistory:YES withPayload:payload]; } -- (void)activateState:(YBState*)state saveToHistory:(BOOL)saveToHistory { +- (void)activateState:(YBState*)state saveToHistory:(BOOL)saveToHistory withPayload:(id)payload { if (state->_active) { return; } @@ -146,14 +166,15 @@ - (void)activateState:(YBState*)state saveToHistory:(BOOL)saveToHistory { YBState *downState = state; while (downState != nil) { if (downState->_superstate) { - [downState->_superstate activateSubstate:downState saveToHistory:saveToHistory]; + [downState->_superstate activateSubstate:downState saveToHistory:saveToHistory withPayload:payload + ]; } else { // rootState doesn't have a superstate - [downState activate]; + [downState activate:payload]; } downState = downState->_superstate; } // Traverse the graph up the leaves of the tree: - [state activateDefaultSubstatesRecursive:YES saveToHistory:saveToHistory]; + [state activateDefaultSubstatesRecursive:YES saveToHistory:saveToHistory withPayload:payload]; } - (void)dispatchEvent:(NSString*)event withPayload:(id)payLoad { @@ -373,11 +394,11 @@ - (void)deactivateSubstatesExcept:(YBState*)exceptSubstate recursive:(BOOL)recur } } -- (void)activateDefaultSubstatesRecursive:(BOOL)recursive saveToHistory:(BOOL)saveToHistory { +- (void)activateDefaultSubstatesRecursive:(BOOL)recursive saveToHistory:(BOOL)saveToHistory withPayload:(id)payload { if ([_substates count] == 0) { return; } else if ([_substates count] == 1) { - [self activateSubstate:[_substates anyObject] saveToHistory:saveToHistory]; + [self activateSubstate:[_substates anyObject] saveToHistory:saveToHistory withPayload:payload]; } else { if (_substatesAreOrthogonal == NO) { // Figure out which substate to activate: @@ -389,16 +410,16 @@ - (void)activateDefaultSubstatesRecursive:(BOOL)recursive saveToHistory:(BOOL)sa defaultSubstate = [self initialSubstate]; NSAssert(defaultSubstate != nil, @"There is no initialSubstate set on `%@`. The statechart is not fully-defined!", _name); } - [self activateSubstate:defaultSubstate saveToHistory:saveToHistory]; + [self activateSubstate:defaultSubstate saveToHistory:saveToHistory withPayload:payload]; if (recursive) { - [defaultSubstate activateDefaultSubstatesRecursive:recursive saveToHistory:saveToHistory]; // recurse + [defaultSubstate activateDefaultSubstatesRecursive:recursive saveToHistory:saveToHistory withPayload:payload]; // recurse } } else { // Activate all substates (they're orthogonal): [_substates enumerateObjectsUsingBlock:^(YBState *substate, BOOL *stop) { - [self activateSubstate:substate saveToHistory:saveToHistory]; + [self activateSubstate:substate saveToHistory:saveToHistory withPayload:payload]; if (recursive) { - [substate activateDefaultSubstatesRecursive:recursive saveToHistory:saveToHistory]; + [substate activateDefaultSubstatesRecursive:recursive saveToHistory:saveToHistory withPayload:payload]; } }]; } @@ -412,28 +433,29 @@ - (void)deactivate { } } -- (void)activate { +- (void)activate:(id)payload { if (_active == NO) { _active = YES; - [self handleEvent:YBStateEnterStateEvent withPayload:nil]; + [self handleEvent:YBStateEnterStateEvent withPayload:payload]; } } -- (void)activateSubstate:(YBState*)substate saveToHistory:(BOOL)saveToHistory { + +- (void)activateSubstate:(YBState*)substate saveToHistory:(BOOL)saveToHistory withPayload:(id)payload { NSAssert([_substates containsObject:substate], @"State `%@` does not contain substate `%@`", _name, substate.name); if (substate->_active) { return; } else { if (_substatesAreOrthogonal) { [_substates enumerateObjectsUsingBlock:^(YBState *otherSubstate, BOOL *stop) { - [otherSubstate activate]; + [otherSubstate activate:payload]; }]; } else { [self deactivateSubstatesExcept:substate recursive:YES]; if (saveToHistory) { [self setHistorySubstate:substate]; } - [substate activate]; + [substate activate:payload]; } } } From 82ebe1ab2ece1d554a931ef80d1a554a5d3607c2 Mon Sep 17 00:00:00 2001 From: Graham Oldfield Date: Sat, 2 Aug 2014 14:13:13 +0100 Subject: [PATCH 5/6] Added debug log --- YBStatechart.podspec | 2 +- YBStatechart/YBStatechart.m | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/YBStatechart.podspec b/YBStatechart.podspec index e21f4d4..bd7a4d7 100644 --- a/YBStatechart.podspec +++ b/YBStatechart.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "YBStatechart" - s.version = "1.0.3" + s.version = "1.0.4" s.summary = "Framework for statecharts. A statecharts is a formalized type of finite state machine." s.homepage = "https://github.com/ronaldmannak/YBStatechart" s.license = 'Apache 2.0' diff --git a/YBStatechart/YBStatechart.m b/YBStatechart/YBStatechart.m index 21225f7..6676ee1 100644 --- a/YBStatechart/YBStatechart.m +++ b/YBStatechart/YBStatechart.m @@ -272,11 +272,18 @@ - (void)on:(NSString*)event doBlock:(YBStateEventHandler)handler { } } +#define LOG_DEBUG - (void)onEnterState:(YBStateEventHandler)handler { +#ifdef LOG_DEBUG + NSLog(@">> %@",self.name); +#endif [self on:YBStateEnterStateEvent doBlock:handler]; } - (void)onExitState:(YBStateEventHandler)handler { +#ifdef LOG_DEBUG + NSLog(@"<< %@",self.name); +#endif [self on:YBStateExitStateEvent doBlock:handler]; } From a6a443afcd9e7343cf06b6949059db9eadf790c5 Mon Sep 17 00:00:00 2001 From: Graham Oldfield Date: Thu, 28 Aug 2014 16:43:04 +0100 Subject: [PATCH 6/6] Merge new dispatch Event that is thread safe --- YBStatechart.podspec | 2 +- YBStatechart/YBStatechart.m | 37 +++++++++++++++++-------------------- 2 files changed, 18 insertions(+), 21 deletions(-) diff --git a/YBStatechart.podspec b/YBStatechart.podspec index bd7a4d7..bc71b8f 100644 --- a/YBStatechart.podspec +++ b/YBStatechart.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "YBStatechart" - s.version = "1.0.4" + s.version = "1.0.5" s.summary = "Framework for statecharts. A statecharts is a formalized type of finite state machine." s.homepage = "https://github.com/ronaldmannak/YBStatechart" s.license = 'Apache 2.0' diff --git a/YBStatechart/YBStatechart.m b/YBStatechart/YBStatechart.m index 6676ee1..ce5a6aa 100644 --- a/YBStatechart/YBStatechart.m +++ b/YBStatechart/YBStatechart.m @@ -38,16 +38,13 @@ - (void)activateDefaultSubstatesRecursive:(BOOL)recursive saveToHistory:(BOOL)sa - (void)activateSubstate:(YBState*)substate saveToHistory:(BOOL)saveToHistory withPayload:(id)payload ; - (void)deactivate; - (void)deactivateSubstatesExcept:(YBState*)exceptSubstate recursive:(BOOL)recursive; -- (void)handleEventAndDispatchToActiveSubstates:(NSString*)event withPayload:(id)payLoad; +- (void)handleEvent:(NSString*)event withPayload:(id)payLoad; +- (NSMutableArray*)collectActiveSubstates; #if DEBUG - (BOOL)debugValidate; #endif @end - - - - @implementation YBStatechart //- (void)dealloc { @@ -177,14 +174,16 @@ - (void)activateState:(YBState*)state saveToHistory:(BOOL)saveToHistory withPayl [state activateDefaultSubstatesRecursive:YES saveToHistory:saveToHistory withPayload:payload]; } -- (void)dispatchEvent:(NSString*)event withPayload:(id)payLoad { - NSAssert(_rootState != nil, @"No rootState set."); - [_rootState handleEventAndDispatchToActiveSubstates:event withPayload:payLoad]; +- (void)dispatchEvent:(NSString*)event{ + [self dispatchEvent:event withPayload:nil]; } - -- (void)dispatchEvent:(NSString*)event { - [self dispatchEvent:event withPayload:nil]; +- (void)dispatchEvent:(NSString*)event withPayload:(id)payLoad { + NSAssert(_rootState != nil, @"No rootState set."); + NSArray* activeSubstates = [_rootState collectActiveSubstates]; + [activeSubstates enumerateObjectsUsingBlock:^(YBState* state, NSUInteger idx, BOOL *stop) { + [state handleEvent:event withPayload:payLoad]; + }]; } - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector { @@ -467,20 +466,18 @@ - (void)activateSubstate:(YBState*)substate saveToHistory:(BOOL)saveToHistory wi } } -- (void)handleEventAndDispatchToActiveSubstates:(NSString*)event withPayload:(id)payLoad { - [self handleEvent:event withPayload:payLoad]; - - if ([_substates count] == 0) { - return; - } else if ([_substates count] == 1) { - [[_substates anyObject] handleEventAndDispatchToActiveSubstates:event withPayload:payLoad]; +- (NSMutableArray *)collectActiveSubstates { + NSMutableArray *activeSubstates = [[NSMutableArray alloc] initWithObjects: self, nil]; + if ([_substates count] == 1) { + [activeSubstates addObjectsFromArray: [[_substates anyObject] collectActiveSubstates]]; } else { [_substates enumerateObjectsUsingBlock:^(YBState *substate, BOOL *stop) { if (substate->_active) { - [substate handleEventAndDispatchToActiveSubstates:event withPayload:payLoad]; + [activeSubstates addObjectsFromArray: [substate collectActiveSubstates]]; } }]; } + return activeSubstates; } - (void)handleEvent:(NSString*)event withPayload:(id)payLoad { @@ -491,7 +488,7 @@ - (void)handleEvent:(NSString*)event withPayload:(id)payLoad { } - (NSString*)description { - return [NSString stringWithFormat:@"<%@ %p: `%@` (%@), %i substates, statechart=%p, superstate=%p, path=%@>", [self class], self, _name, _active ? @"active" : @"inactive", [_substates count], _statechart, _superstate, [self path]]; + return [NSString stringWithFormat:@"<%@ %p: `%@` (%@), %lu substates, statechart=%p, superstate=%p, path=%@>", [self class], self, _name, _active ? @"active" : @"inactive", (unsigned long)[_substates count], _statechart, _superstate, [self path]]; } @synthesize initialSubstate = _initialSubstate;