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. diff --git a/YBStatechart.podspec b/YBStatechart.podspec index e21f4d4..bc71b8f 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.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.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 @@ _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; } @@ -147,21 +163,26 @@ - (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 { +- (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]; + [state handleEvent:event withPayload:payLoad]; }]; } @@ -250,11 +271,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]; } @@ -372,11 +400,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: @@ -388,16 +416,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]; } }]; } @@ -407,32 +435,33 @@ - (void)activateDefaultSubstatesRecursive:(BOOL)recursive saveToHistory:(BOOL)sa - (void)deactivate { if (_active == YES) { _active = NO; - [self handleEvent:YBStateExitStateEvent]; + [self handleEvent:YBStateExitStateEvent withPayload:nil]; } } -- (void)activate { +- (void)activate:(id)payload { if (_active == NO) { _active = YES; - [self handleEvent:YBStateEnterStateEvent]; + [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]; } } } @@ -451,15 +480,15 @@ - (NSMutableArray *)collectActiveSubstates { 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); } } - (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; diff --git a/YBStatechartTests/YBStatechartTests.m b/YBStatechartTests/YBStatechartTests.m index d47536c..49110df 100644 --- a/YBStatechartTests/YBStatechartTests.m +++ b/YBStatechartTests/YBStatechartTests.m @@ -200,7 +200,7 @@ - (void)testChartDispatchDirect { STAssertTrue(didButtonDown == NO, nil); YBStatechart *statechart = [[YBStatechart alloc] init]; YBState *rootState = [YBState stateWithName:@"rootState"]; - [rootState on:@"buttonDown" doBlock:^(YBState *_self) { + [rootState on:@"buttonDown" doBlock:^(YBState *_self , id payload) { didButtonDown = YES; }]; @@ -241,7 +241,7 @@ - (void)testNestedDispatch { [loggedIn on:@"up" doBlock:eventHandler]; [loggedOut on:@"up" doBlock:eventHandler]; - [rootState on:@"toggle" doBlock:^(YBState *_self) { + [rootState on:@"toggle" doBlock:^(YBState *_self , id payload) { YBStatechart *statechart = _self.statechart; if (loggedIn.isActive) { [statechart activateState:loggedOut];