├── .gitignore ├── ModelViewPresenterDemo ├── .idea │ ├── .name │ ├── ModelViewPresenterDemo.iml │ ├── encodings.xml │ ├── misc.xml │ ├── modules.xml │ ├── scopes │ │ └── scope_settings.xml │ ├── vcs.xml │ ├── workspace.xml │ └── xcode.xml ├── ModelViewPresenterDemo.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcuserdata │ │ │ └── dgadd.xcuserdatad │ │ │ └── UserInterfaceState.xcuserstate │ └── xcuserdata │ │ └── dgadd.xcuserdatad │ │ └── xcschemes │ │ ├── All Tests.xcscheme │ │ ├── ModelViewPresenterDemo.xcscheme │ │ └── xcschememanagement.plist ├── ModelViewPresenterDemo │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── ModelViewPresenterDemo-Info.plist │ ├── ModelViewPresenterDemo-Prefix.pch │ ├── Presenters │ │ ├── BookListPresenter.h │ │ └── BookListPresenter.m │ ├── Repositories │ │ ├── FakeBookStoreRepository.h │ │ ├── FakeBookStoreRepository.m │ │ └── IBookStoreRepository.h │ ├── ViewControllers │ │ ├── DisplayBooksTableViewController.h │ │ └── DisplayBooksTableViewController.m │ ├── Views │ │ └── IDisplayBooksView.h │ ├── en.lproj │ │ ├── InfoPlist.strings │ │ ├── MainStoryboard_iPad.storyboard │ │ └── MainStoryboard_iPhone.storyboard │ └── main.m ├── ModelViewPresenterDemoTests │ ├── BookListPresenterTests.h │ ├── BookListPresenterTests.m │ ├── ModelViewPresenterDemoTests-Info.plist │ └── en.lproj │ │ └── InfoPlist.strings └── OCMocksLibs │ ├── OCMock │ ├── NSNotificationCenter+OCMAdditions.h │ ├── OCMArg.h │ ├── OCMConstraint.h │ ├── OCMock.h │ ├── OCMockObject.h │ └── OCMockRecorder.h │ └── libOCMock.a └── README.markdown /.gitignore: -------------------------------------------------------------------------------- 1 | #OS junk files 2 | [Tt]humbs.db 3 | *.DS_Store 4 | 5 | #Visual Studio files 6 | *.[Oo]bj 7 | *.exe 8 | *.pdb 9 | *.user 10 | *.aps 11 | # This file is required by C projects, so track it: *.pch 12 | *.vspscc 13 | *.vssscc 14 | *_i.c 15 | *_p.c 16 | *.ncb 17 | *.suo 18 | *.tlb 19 | *.tlh 20 | *.bak 21 | *.[Cc]ache 22 | *.ilk 23 | *.log 24 | *.lib 25 | *.sbr 26 | *.sdf 27 | ipch/ 28 | obj/ 29 | [Bb]in 30 | [Dd]ebug*/ 31 | [Rr]elease*/ 32 | Ankh.NoLoad 33 | 34 | #Tooling 35 | _ReSharper*/ 36 | *.resharper 37 | [Tt]est[Rr]esult* 38 | 39 | #Project files 40 | [Bb]uild/ 41 | 42 | #Subversion files 43 | .svn 44 | 45 | # Office Temp Files 46 | -------------------------------------------------------------------------------- /ModelViewPresenterDemo/.idea/.name: -------------------------------------------------------------------------------- 1 | ModelViewPresenterDemo -------------------------------------------------------------------------------- /ModelViewPresenterDemo/.idea/ModelViewPresenterDemo.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /ModelViewPresenterDemo/.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /ModelViewPresenterDemo/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | http://www.w3.org/1999/xhtml 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ModelViewPresenterDemo/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /ModelViewPresenterDemo/.idea/scopes/scope_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /ModelViewPresenterDemo/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ModelViewPresenterDemo/.idea/workspace.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 13 | 14 | 15 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 51 | 52 | 53 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 101 | 102 | 105 | 106 | 107 | 108 | 111 | 112 | 115 | 116 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 137 | 138 | 139 | 140 | 141 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 1341709450042 167 | 1341709450042 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 197 | 198 | 209 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | -------------------------------------------------------------------------------- /ModelViewPresenterDemo/.idea/xcode.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /ModelViewPresenterDemo/ModelViewPresenterDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 72324F3E15A9102B0034CA8A /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72324F3D15A9102B0034CA8A /* UIKit.framework */; }; 11 | 72324F4015A9102B0034CA8A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72324F3F15A9102B0034CA8A /* Foundation.framework */; }; 12 | 72324F4215A9102B0034CA8A /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72324F4115A9102B0034CA8A /* CoreGraphics.framework */; }; 13 | 72324F4815A9102B0034CA8A /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 72324F4615A9102B0034CA8A /* InfoPlist.strings */; }; 14 | 72324F4A15A9102B0034CA8A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 72324F4915A9102B0034CA8A /* main.m */; }; 15 | 72324F4E15A9102B0034CA8A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 72324F4D15A9102B0034CA8A /* AppDelegate.m */; }; 16 | 72324F5115A9102B0034CA8A /* MainStoryboard_iPhone.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 72324F4F15A9102B0034CA8A /* MainStoryboard_iPhone.storyboard */; }; 17 | 72324F5415A9102B0034CA8A /* MainStoryboard_iPad.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 72324F5215A9102B0034CA8A /* MainStoryboard_iPad.storyboard */; }; 18 | 72324F5F15A9102B0034CA8A /* SenTestingKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72324F5E15A9102B0034CA8A /* SenTestingKit.framework */; }; 19 | 72324F6015A9102B0034CA8A /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72324F3D15A9102B0034CA8A /* UIKit.framework */; }; 20 | 72324F6115A9102B0034CA8A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72324F3F15A9102B0034CA8A /* Foundation.framework */; }; 21 | 72324F6915A9102B0034CA8A /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 72324F6715A9102B0034CA8A /* InfoPlist.strings */; }; 22 | 72324F7F15A910820034CA8A /* libOCMock.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 72324F7715A910820034CA8A /* libOCMock.a */; }; 23 | 72324F7F15A910820034CA8D /* BookListPresenterTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 72324F7F15A910820034CA8C /* BookListPresenterTests.m */; }; 24 | 72324F7F15A910820034CA92 /* BookListPresenter.m in Sources */ = {isa = PBXBuildFile; fileRef = 72324F7F15A910820034CA91 /* BookListPresenter.m */; }; 25 | 72324F7F15A910820034CA98 /* DisplayBooksTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 72324F7F15A910820034CA97 /* DisplayBooksTableViewController.m */; }; 26 | 72324F7F15A910820034CA9F /* FakeBookStoreRepository.m in Sources */ = {isa = PBXBuildFile; fileRef = 72324F7F15A910820034CA9E /* FakeBookStoreRepository.m */; }; 27 | /* End PBXBuildFile section */ 28 | 29 | /* Begin PBXContainerItemProxy section */ 30 | 72324F6215A9102B0034CA8A /* PBXContainerItemProxy */ = { 31 | isa = PBXContainerItemProxy; 32 | containerPortal = 72324F3015A9102B0034CA8A /* Project object */; 33 | proxyType = 1; 34 | remoteGlobalIDString = 72324F3815A9102B0034CA8A; 35 | remoteInfo = ModelViewPresenterDemo; 36 | }; 37 | /* End PBXContainerItemProxy section */ 38 | 39 | /* Begin PBXFileReference section */ 40 | 72324F3915A9102B0034CA8A /* ModelViewPresenterDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ModelViewPresenterDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 41 | 72324F3D15A9102B0034CA8A /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 42 | 72324F3F15A9102B0034CA8A /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 43 | 72324F4115A9102B0034CA8A /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 44 | 72324F4515A9102B0034CA8A /* ModelViewPresenterDemo-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "ModelViewPresenterDemo-Info.plist"; sourceTree = ""; }; 45 | 72324F4715A9102B0034CA8A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 46 | 72324F4915A9102B0034CA8A /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 47 | 72324F4B15A9102B0034CA8A /* ModelViewPresenterDemo-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "ModelViewPresenterDemo-Prefix.pch"; sourceTree = ""; }; 48 | 72324F4C15A9102B0034CA8A /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 49 | 72324F4D15A9102B0034CA8A /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 50 | 72324F5015A9102B0034CA8A /* en */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = en; path = en.lproj/MainStoryboard_iPhone.storyboard; sourceTree = ""; }; 51 | 72324F5315A9102B0034CA8A /* en */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = en; path = en.lproj/MainStoryboard_iPad.storyboard; sourceTree = ""; }; 52 | 72324F5D15A9102B0034CA8A /* ModelViewPresenterDemoTests.octest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ModelViewPresenterDemoTests.octest; sourceTree = BUILT_PRODUCTS_DIR; }; 53 | 72324F5E15A9102B0034CA8A /* SenTestingKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SenTestingKit.framework; path = Library/Frameworks/SenTestingKit.framework; sourceTree = DEVELOPER_DIR; }; 54 | 72324F6615A9102B0034CA8A /* ModelViewPresenterDemoTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "ModelViewPresenterDemoTests-Info.plist"; sourceTree = ""; }; 55 | 72324F6815A9102B0034CA8A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 56 | 72324F7715A910820034CA8A /* libOCMock.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libOCMock.a; sourceTree = ""; }; 57 | 72324F7915A910820034CA8A /* NSNotificationCenter+OCMAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSNotificationCenter+OCMAdditions.h"; sourceTree = ""; }; 58 | 72324F7A15A910820034CA8A /* OCMArg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OCMArg.h; sourceTree = ""; }; 59 | 72324F7B15A910820034CA8A /* OCMConstraint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OCMConstraint.h; sourceTree = ""; }; 60 | 72324F7C15A910820034CA8A /* OCMock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OCMock.h; sourceTree = ""; }; 61 | 72324F7D15A910820034CA8A /* OCMockObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OCMockObject.h; sourceTree = ""; }; 62 | 72324F7E15A910820034CA8A /* OCMockRecorder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OCMockRecorder.h; sourceTree = ""; }; 63 | 72324F7F15A910820034CA8B /* BookListPresenterTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BookListPresenterTests.h; sourceTree = ""; }; 64 | 72324F7F15A910820034CA8C /* BookListPresenterTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BookListPresenterTests.m; sourceTree = ""; }; 65 | 72324F7F15A910820034CA91 /* BookListPresenter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BookListPresenter.m; sourceTree = ""; }; 66 | 72324F7F15A910820034CA93 /* BookListPresenter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BookListPresenter.h; sourceTree = ""; }; 67 | 72324F7F15A910820034CA94 /* IDisplayBooksView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IDisplayBooksView.h; sourceTree = ""; }; 68 | 72324F7F15A910820034CA96 /* DisplayBooksTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DisplayBooksTableViewController.h; sourceTree = ""; }; 69 | 72324F7F15A910820034CA97 /* DisplayBooksTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DisplayBooksTableViewController.m; sourceTree = ""; }; 70 | 72324F7F15A910820034CA9D /* IBookStoreRepository.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IBookStoreRepository.h; sourceTree = ""; }; 71 | 72324F7F15A910820034CA9E /* FakeBookStoreRepository.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FakeBookStoreRepository.m; sourceTree = ""; }; 72 | 72324F7F15A910820034CAA0 /* FakeBookStoreRepository.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FakeBookStoreRepository.h; sourceTree = ""; }; 73 | /* End PBXFileReference section */ 74 | 75 | /* Begin PBXFrameworksBuildPhase section */ 76 | 72324F3615A9102B0034CA8A /* Frameworks */ = { 77 | isa = PBXFrameworksBuildPhase; 78 | buildActionMask = 2147483647; 79 | files = ( 80 | 72324F3E15A9102B0034CA8A /* UIKit.framework in Frameworks */, 81 | 72324F4015A9102B0034CA8A /* Foundation.framework in Frameworks */, 82 | 72324F4215A9102B0034CA8A /* CoreGraphics.framework in Frameworks */, 83 | ); 84 | runOnlyForDeploymentPostprocessing = 0; 85 | }; 86 | 72324F5915A9102B0034CA8A /* Frameworks */ = { 87 | isa = PBXFrameworksBuildPhase; 88 | buildActionMask = 2147483647; 89 | files = ( 90 | 72324F5F15A9102B0034CA8A /* SenTestingKit.framework in Frameworks */, 91 | 72324F6015A9102B0034CA8A /* UIKit.framework in Frameworks */, 92 | 72324F6115A9102B0034CA8A /* Foundation.framework in Frameworks */, 93 | 72324F7F15A910820034CA8A /* libOCMock.a in Frameworks */, 94 | ); 95 | runOnlyForDeploymentPostprocessing = 0; 96 | }; 97 | /* End PBXFrameworksBuildPhase section */ 98 | 99 | /* Begin PBXGroup section */ 100 | 72324F2E15A9102B0034CA8A = { 101 | isa = PBXGroup; 102 | children = ( 103 | 72324F7515A910690034CA8A /* ThirdPartyLibs */, 104 | 72324F4315A9102B0034CA8A /* ModelViewPresenterDemo */, 105 | 72324F6415A9102B0034CA8A /* ModelViewPresenterDemoTests */, 106 | 72324F3C15A9102B0034CA8A /* Frameworks */, 107 | 72324F3A15A9102B0034CA8A /* Products */, 108 | ); 109 | sourceTree = ""; 110 | }; 111 | 72324F3A15A9102B0034CA8A /* Products */ = { 112 | isa = PBXGroup; 113 | children = ( 114 | 72324F3915A9102B0034CA8A /* ModelViewPresenterDemo.app */, 115 | 72324F5D15A9102B0034CA8A /* ModelViewPresenterDemoTests.octest */, 116 | ); 117 | name = Products; 118 | sourceTree = ""; 119 | }; 120 | 72324F3C15A9102B0034CA8A /* Frameworks */ = { 121 | isa = PBXGroup; 122 | children = ( 123 | 72324F3D15A9102B0034CA8A /* UIKit.framework */, 124 | 72324F3F15A9102B0034CA8A /* Foundation.framework */, 125 | 72324F4115A9102B0034CA8A /* CoreGraphics.framework */, 126 | 72324F5E15A9102B0034CA8A /* SenTestingKit.framework */, 127 | ); 128 | name = Frameworks; 129 | sourceTree = ""; 130 | }; 131 | 72324F4315A9102B0034CA8A /* ModelViewPresenterDemo */ = { 132 | isa = PBXGroup; 133 | children = ( 134 | 72324F4C15A9102B0034CA8A /* AppDelegate.h */, 135 | 72324F4D15A9102B0034CA8A /* AppDelegate.m */, 136 | 72324F4F15A9102B0034CA8A /* MainStoryboard_iPhone.storyboard */, 137 | 72324F5215A9102B0034CA8A /* MainStoryboard_iPad.storyboard */, 138 | 72324F4415A9102B0034CA8A /* Supporting Files */, 139 | 72324F7F15A910820034CA8E /* Presenters */, 140 | 72324F7F15A910820034CA8F /* Views */, 141 | 72324F7F15A910820034CA90 /* Models */, 142 | 72324F7F15A910820034CA95 /* ViewControllers */, 143 | 72324F7F15A910820034CA9C /* Repositories */, 144 | ); 145 | path = ModelViewPresenterDemo; 146 | sourceTree = ""; 147 | }; 148 | 72324F4415A9102B0034CA8A /* Supporting Files */ = { 149 | isa = PBXGroup; 150 | children = ( 151 | 72324F4515A9102B0034CA8A /* ModelViewPresenterDemo-Info.plist */, 152 | 72324F4615A9102B0034CA8A /* InfoPlist.strings */, 153 | 72324F4915A9102B0034CA8A /* main.m */, 154 | 72324F4B15A9102B0034CA8A /* ModelViewPresenterDemo-Prefix.pch */, 155 | ); 156 | name = "Supporting Files"; 157 | sourceTree = ""; 158 | }; 159 | 72324F6415A9102B0034CA8A /* ModelViewPresenterDemoTests */ = { 160 | isa = PBXGroup; 161 | children = ( 162 | 72324F7F15A910820034CA8C /* BookListPresenterTests.m */, 163 | 72324F7F15A910820034CA8B /* BookListPresenterTests.h */, 164 | 72324F6515A9102B0034CA8A /* Supporting Files */, 165 | ); 166 | path = ModelViewPresenterDemoTests; 167 | sourceTree = ""; 168 | }; 169 | 72324F6515A9102B0034CA8A /* Supporting Files */ = { 170 | isa = PBXGroup; 171 | children = ( 172 | 72324F6615A9102B0034CA8A /* ModelViewPresenterDemoTests-Info.plist */, 173 | 72324F6715A9102B0034CA8A /* InfoPlist.strings */, 174 | ); 175 | name = "Supporting Files"; 176 | sourceTree = ""; 177 | }; 178 | 72324F7515A910690034CA8A /* ThirdPartyLibs */ = { 179 | isa = PBXGroup; 180 | children = ( 181 | 72324F7615A910820034CA8A /* OCMocksLibs */, 182 | ); 183 | name = ThirdPartyLibs; 184 | sourceTree = ""; 185 | }; 186 | 72324F7615A910820034CA8A /* OCMocksLibs */ = { 187 | isa = PBXGroup; 188 | children = ( 189 | 72324F7715A910820034CA8A /* libOCMock.a */, 190 | 72324F7815A910820034CA8A /* OCMock */, 191 | ); 192 | path = OCMocksLibs; 193 | sourceTree = ""; 194 | }; 195 | 72324F7815A910820034CA8A /* OCMock */ = { 196 | isa = PBXGroup; 197 | children = ( 198 | 72324F7915A910820034CA8A /* NSNotificationCenter+OCMAdditions.h */, 199 | 72324F7A15A910820034CA8A /* OCMArg.h */, 200 | 72324F7B15A910820034CA8A /* OCMConstraint.h */, 201 | 72324F7C15A910820034CA8A /* OCMock.h */, 202 | 72324F7D15A910820034CA8A /* OCMockObject.h */, 203 | 72324F7E15A910820034CA8A /* OCMockRecorder.h */, 204 | ); 205 | path = OCMock; 206 | sourceTree = ""; 207 | }; 208 | 72324F7F15A910820034CA8E /* Presenters */ = { 209 | isa = PBXGroup; 210 | children = ( 211 | 72324F7F15A910820034CA93 /* BookListPresenter.h */, 212 | 72324F7F15A910820034CA91 /* BookListPresenter.m */, 213 | ); 214 | path = Presenters; 215 | sourceTree = ""; 216 | }; 217 | 72324F7F15A910820034CA8F /* Views */ = { 218 | isa = PBXGroup; 219 | children = ( 220 | 72324F7F15A910820034CA94 /* IDisplayBooksView.h */, 221 | ); 222 | path = Views; 223 | sourceTree = ""; 224 | }; 225 | 72324F7F15A910820034CA90 /* Models */ = { 226 | isa = PBXGroup; 227 | children = ( 228 | ); 229 | path = Models; 230 | sourceTree = ""; 231 | }; 232 | 72324F7F15A910820034CA95 /* ViewControllers */ = { 233 | isa = PBXGroup; 234 | children = ( 235 | 72324F7F15A910820034CA97 /* DisplayBooksTableViewController.m */, 236 | 72324F7F15A910820034CA96 /* DisplayBooksTableViewController.h */, 237 | ); 238 | path = ViewControllers; 239 | sourceTree = ""; 240 | }; 241 | 72324F7F15A910820034CA9C /* Repositories */ = { 242 | isa = PBXGroup; 243 | children = ( 244 | 72324F7F15A910820034CAA0 /* FakeBookStoreRepository.h */, 245 | 72324F7F15A910820034CA9E /* FakeBookStoreRepository.m */, 246 | 72324F7F15A910820034CA9D /* IBookStoreRepository.h */, 247 | ); 248 | path = Repositories; 249 | sourceTree = ""; 250 | }; 251 | /* End PBXGroup section */ 252 | 253 | /* Begin PBXNativeTarget section */ 254 | 72324F3815A9102B0034CA8A /* ModelViewPresenterDemo */ = { 255 | isa = PBXNativeTarget; 256 | buildConfigurationList = 72324F6F15A9102B0034CA8A /* Build configuration list for PBXNativeTarget "ModelViewPresenterDemo" */; 257 | buildPhases = ( 258 | 72324F3515A9102B0034CA8A /* Sources */, 259 | 72324F3615A9102B0034CA8A /* Frameworks */, 260 | 72324F3715A9102B0034CA8A /* Resources */, 261 | ); 262 | buildRules = ( 263 | ); 264 | dependencies = ( 265 | ); 266 | name = ModelViewPresenterDemo; 267 | productName = ModelViewPresenterDemo; 268 | productReference = 72324F3915A9102B0034CA8A /* ModelViewPresenterDemo.app */; 269 | productType = "com.apple.product-type.application"; 270 | }; 271 | 72324F5C15A9102B0034CA8A /* ModelViewPresenterDemoTests */ = { 272 | isa = PBXNativeTarget; 273 | buildConfigurationList = 72324F7215A9102B0034CA8A /* Build configuration list for PBXNativeTarget "ModelViewPresenterDemoTests" */; 274 | buildPhases = ( 275 | 72324F5815A9102B0034CA8A /* Sources */, 276 | 72324F5915A9102B0034CA8A /* Frameworks */, 277 | 72324F5A15A9102B0034CA8A /* Resources */, 278 | 72324F5B15A9102B0034CA8A /* ShellScript */, 279 | ); 280 | buildRules = ( 281 | ); 282 | dependencies = ( 283 | 72324F6315A9102B0034CA8A /* PBXTargetDependency */, 284 | ); 285 | name = ModelViewPresenterDemoTests; 286 | productName = ModelViewPresenterDemoTests; 287 | productReference = 72324F5D15A9102B0034CA8A /* ModelViewPresenterDemoTests.octest */; 288 | productType = "com.apple.product-type.bundle"; 289 | }; 290 | /* End PBXNativeTarget section */ 291 | 292 | /* Begin PBXProject section */ 293 | 72324F3015A9102B0034CA8A /* Project object */ = { 294 | isa = PBXProject; 295 | attributes = { 296 | LastUpgradeCheck = 0430; 297 | }; 298 | buildConfigurationList = 72324F3315A9102B0034CA8A /* Build configuration list for PBXProject "ModelViewPresenterDemo" */; 299 | compatibilityVersion = "Xcode 3.2"; 300 | developmentRegion = English; 301 | hasScannedForEncodings = 0; 302 | knownRegions = ( 303 | en, 304 | ); 305 | mainGroup = 72324F2E15A9102B0034CA8A; 306 | productRefGroup = 72324F3A15A9102B0034CA8A /* Products */; 307 | projectDirPath = ""; 308 | projectRoot = ""; 309 | targets = ( 310 | 72324F3815A9102B0034CA8A /* ModelViewPresenterDemo */, 311 | 72324F5C15A9102B0034CA8A /* ModelViewPresenterDemoTests */, 312 | ); 313 | }; 314 | /* End PBXProject section */ 315 | 316 | /* Begin PBXResourcesBuildPhase section */ 317 | 72324F3715A9102B0034CA8A /* Resources */ = { 318 | isa = PBXResourcesBuildPhase; 319 | buildActionMask = 2147483647; 320 | files = ( 321 | 72324F4815A9102B0034CA8A /* InfoPlist.strings in Resources */, 322 | 72324F5115A9102B0034CA8A /* MainStoryboard_iPhone.storyboard in Resources */, 323 | 72324F5415A9102B0034CA8A /* MainStoryboard_iPad.storyboard in Resources */, 324 | ); 325 | runOnlyForDeploymentPostprocessing = 0; 326 | }; 327 | 72324F5A15A9102B0034CA8A /* Resources */ = { 328 | isa = PBXResourcesBuildPhase; 329 | buildActionMask = 2147483647; 330 | files = ( 331 | 72324F6915A9102B0034CA8A /* InfoPlist.strings in Resources */, 332 | ); 333 | runOnlyForDeploymentPostprocessing = 0; 334 | }; 335 | /* End PBXResourcesBuildPhase section */ 336 | 337 | /* Begin PBXShellScriptBuildPhase section */ 338 | 72324F5B15A9102B0034CA8A /* ShellScript */ = { 339 | isa = PBXShellScriptBuildPhase; 340 | buildActionMask = 2147483647; 341 | files = ( 342 | ); 343 | inputPaths = ( 344 | ); 345 | outputPaths = ( 346 | ); 347 | runOnlyForDeploymentPostprocessing = 0; 348 | shellPath = /bin/sh; 349 | shellScript = "# Run the unit tests in this test bundle.\n\"${SYSTEM_DEVELOPER_DIR}/Tools/RunUnitTests\"\n"; 350 | }; 351 | /* End PBXShellScriptBuildPhase section */ 352 | 353 | /* Begin PBXSourcesBuildPhase section */ 354 | 72324F3515A9102B0034CA8A /* Sources */ = { 355 | isa = PBXSourcesBuildPhase; 356 | buildActionMask = 2147483647; 357 | files = ( 358 | 72324F4A15A9102B0034CA8A /* main.m in Sources */, 359 | 72324F4E15A9102B0034CA8A /* AppDelegate.m in Sources */, 360 | 72324F7F15A910820034CA92 /* BookListPresenter.m in Sources */, 361 | 72324F7F15A910820034CA98 /* DisplayBooksTableViewController.m in Sources */, 362 | 72324F7F15A910820034CA9F /* FakeBookStoreRepository.m in Sources */, 363 | ); 364 | runOnlyForDeploymentPostprocessing = 0; 365 | }; 366 | 72324F5815A9102B0034CA8A /* Sources */ = { 367 | isa = PBXSourcesBuildPhase; 368 | buildActionMask = 2147483647; 369 | files = ( 370 | 72324F7F15A910820034CA8D /* BookListPresenterTests.m in Sources */, 371 | ); 372 | runOnlyForDeploymentPostprocessing = 0; 373 | }; 374 | /* End PBXSourcesBuildPhase section */ 375 | 376 | /* Begin PBXTargetDependency section */ 377 | 72324F6315A9102B0034CA8A /* PBXTargetDependency */ = { 378 | isa = PBXTargetDependency; 379 | target = 72324F3815A9102B0034CA8A /* ModelViewPresenterDemo */; 380 | targetProxy = 72324F6215A9102B0034CA8A /* PBXContainerItemProxy */; 381 | }; 382 | /* End PBXTargetDependency section */ 383 | 384 | /* Begin PBXVariantGroup section */ 385 | 72324F4615A9102B0034CA8A /* InfoPlist.strings */ = { 386 | isa = PBXVariantGroup; 387 | children = ( 388 | 72324F4715A9102B0034CA8A /* en */, 389 | ); 390 | name = InfoPlist.strings; 391 | sourceTree = ""; 392 | }; 393 | 72324F4F15A9102B0034CA8A /* MainStoryboard_iPhone.storyboard */ = { 394 | isa = PBXVariantGroup; 395 | children = ( 396 | 72324F5015A9102B0034CA8A /* en */, 397 | ); 398 | name = MainStoryboard_iPhone.storyboard; 399 | sourceTree = ""; 400 | }; 401 | 72324F5215A9102B0034CA8A /* MainStoryboard_iPad.storyboard */ = { 402 | isa = PBXVariantGroup; 403 | children = ( 404 | 72324F5315A9102B0034CA8A /* en */, 405 | ); 406 | name = MainStoryboard_iPad.storyboard; 407 | sourceTree = ""; 408 | }; 409 | 72324F6715A9102B0034CA8A /* InfoPlist.strings */ = { 410 | isa = PBXVariantGroup; 411 | children = ( 412 | 72324F6815A9102B0034CA8A /* en */, 413 | ); 414 | name = InfoPlist.strings; 415 | sourceTree = ""; 416 | }; 417 | /* End PBXVariantGroup section */ 418 | 419 | /* Begin XCBuildConfiguration section */ 420 | 72324F6D15A9102B0034CA8A /* Debug */ = { 421 | isa = XCBuildConfiguration; 422 | buildSettings = { 423 | ALWAYS_SEARCH_USER_PATHS = NO; 424 | ARCHS = "$(ARCHS_STANDARD_32_BIT)"; 425 | CLANG_ENABLE_OBJC_ARC = YES; 426 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 427 | COPY_PHASE_STRIP = NO; 428 | GCC_C_LANGUAGE_STANDARD = gnu99; 429 | GCC_DYNAMIC_NO_PIC = NO; 430 | GCC_OPTIMIZATION_LEVEL = 0; 431 | GCC_PREPROCESSOR_DEFINITIONS = ( 432 | "DEBUG=1", 433 | "$(inherited)", 434 | ); 435 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 436 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0; 437 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 438 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 439 | GCC_WARN_UNUSED_VARIABLE = YES; 440 | IPHONEOS_DEPLOYMENT_TARGET = 5.1; 441 | SDKROOT = iphoneos; 442 | TARGETED_DEVICE_FAMILY = "1,2"; 443 | }; 444 | name = Debug; 445 | }; 446 | 72324F6E15A9102B0034CA8A /* Release */ = { 447 | isa = XCBuildConfiguration; 448 | buildSettings = { 449 | ALWAYS_SEARCH_USER_PATHS = NO; 450 | ARCHS = "$(ARCHS_STANDARD_32_BIT)"; 451 | CLANG_ENABLE_OBJC_ARC = YES; 452 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 453 | COPY_PHASE_STRIP = YES; 454 | GCC_C_LANGUAGE_STANDARD = gnu99; 455 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0; 456 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 457 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 458 | GCC_WARN_UNUSED_VARIABLE = YES; 459 | IPHONEOS_DEPLOYMENT_TARGET = 5.1; 460 | OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; 461 | SDKROOT = iphoneos; 462 | TARGETED_DEVICE_FAMILY = "1,2"; 463 | VALIDATE_PRODUCT = YES; 464 | }; 465 | name = Release; 466 | }; 467 | 72324F7015A9102B0034CA8A /* Debug */ = { 468 | isa = XCBuildConfiguration; 469 | buildSettings = { 470 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 471 | GCC_PREFIX_HEADER = "ModelViewPresenterDemo/ModelViewPresenterDemo-Prefix.pch"; 472 | INFOPLIST_FILE = "ModelViewPresenterDemo/ModelViewPresenterDemo-Info.plist"; 473 | PRODUCT_NAME = "$(TARGET_NAME)"; 474 | WRAPPER_EXTENSION = app; 475 | }; 476 | name = Debug; 477 | }; 478 | 72324F7115A9102B0034CA8A /* Release */ = { 479 | isa = XCBuildConfiguration; 480 | buildSettings = { 481 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 482 | GCC_PREFIX_HEADER = "ModelViewPresenterDemo/ModelViewPresenterDemo-Prefix.pch"; 483 | INFOPLIST_FILE = "ModelViewPresenterDemo/ModelViewPresenterDemo-Info.plist"; 484 | PRODUCT_NAME = "$(TARGET_NAME)"; 485 | WRAPPER_EXTENSION = app; 486 | }; 487 | name = Release; 488 | }; 489 | 72324F7315A9102B0034CA8A /* Debug */ = { 490 | isa = XCBuildConfiguration; 491 | buildSettings = { 492 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/ModelViewPresenterDemo.app/ModelViewPresenterDemo"; 493 | FRAMEWORK_SEARCH_PATHS = ( 494 | "$(SDKROOT)/Developer/Library/Frameworks", 495 | "$(DEVELOPER_LIBRARY_DIR)/Frameworks", 496 | ); 497 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 498 | GCC_PREFIX_HEADER = "ModelViewPresenterDemo/ModelViewPresenterDemo-Prefix.pch"; 499 | INFOPLIST_FILE = "ModelViewPresenterDemoTests/ModelViewPresenterDemoTests-Info.plist"; 500 | LIBRARY_SEARCH_PATHS = ( 501 | "$(inherited)", 502 | "\"$(SRCROOT)/OCMocksLibs\"", 503 | ); 504 | "OTHER_LDFLAGS[arch=*]" = ( 505 | "-force_load", 506 | OCMocksLibs/libOCMock.a, 507 | ); 508 | PRODUCT_NAME = "$(TARGET_NAME)"; 509 | TEST_HOST = "$(BUNDLE_LOADER)"; 510 | WRAPPER_EXTENSION = octest; 511 | }; 512 | name = Debug; 513 | }; 514 | 72324F7415A9102B0034CA8A /* Release */ = { 515 | isa = XCBuildConfiguration; 516 | buildSettings = { 517 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/ModelViewPresenterDemo.app/ModelViewPresenterDemo"; 518 | FRAMEWORK_SEARCH_PATHS = ( 519 | "$(SDKROOT)/Developer/Library/Frameworks", 520 | "$(DEVELOPER_LIBRARY_DIR)/Frameworks", 521 | ); 522 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 523 | GCC_PREFIX_HEADER = "ModelViewPresenterDemo/ModelViewPresenterDemo-Prefix.pch"; 524 | INFOPLIST_FILE = "ModelViewPresenterDemoTests/ModelViewPresenterDemoTests-Info.plist"; 525 | LIBRARY_SEARCH_PATHS = ( 526 | "$(inherited)", 527 | "\"$(SRCROOT)/OCMocksLibs\"", 528 | ); 529 | "OTHER_LDFLAGS[arch=*]" = ( 530 | "-force_load", 531 | OCMocksLibs/libOCMock.a, 532 | ); 533 | PRODUCT_NAME = "$(TARGET_NAME)"; 534 | TEST_HOST = "$(BUNDLE_LOADER)"; 535 | WRAPPER_EXTENSION = octest; 536 | }; 537 | name = Release; 538 | }; 539 | /* End XCBuildConfiguration section */ 540 | 541 | /* Begin XCConfigurationList section */ 542 | 72324F3315A9102B0034CA8A /* Build configuration list for PBXProject "ModelViewPresenterDemo" */ = { 543 | isa = XCConfigurationList; 544 | buildConfigurations = ( 545 | 72324F6D15A9102B0034CA8A /* Debug */, 546 | 72324F6E15A9102B0034CA8A /* Release */, 547 | ); 548 | defaultConfigurationIsVisible = 0; 549 | defaultConfigurationName = Release; 550 | }; 551 | 72324F6F15A9102B0034CA8A /* Build configuration list for PBXNativeTarget "ModelViewPresenterDemo" */ = { 552 | isa = XCConfigurationList; 553 | buildConfigurations = ( 554 | 72324F7015A9102B0034CA8A /* Debug */, 555 | 72324F7115A9102B0034CA8A /* Release */, 556 | ); 557 | defaultConfigurationIsVisible = 0; 558 | defaultConfigurationName = Release; 559 | }; 560 | 72324F7215A9102B0034CA8A /* Build configuration list for PBXNativeTarget "ModelViewPresenterDemoTests" */ = { 561 | isa = XCConfigurationList; 562 | buildConfigurations = ( 563 | 72324F7315A9102B0034CA8A /* Debug */, 564 | 72324F7415A9102B0034CA8A /* Release */, 565 | ); 566 | defaultConfigurationIsVisible = 0; 567 | defaultConfigurationName = Release; 568 | }; 569 | /* End XCConfigurationList section */ 570 | }; 571 | rootObject = 72324F3015A9102B0034CA8A /* Project object */; 572 | } 573 | -------------------------------------------------------------------------------- /ModelViewPresenterDemo/ModelViewPresenterDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ModelViewPresenterDemo/ModelViewPresenterDemo.xcodeproj/project.xcworkspace/xcuserdata/dgadd.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dgadd/iOSModelViewPresenter/d07d26b8f18073f0f917afef32f3b68fee194862/ModelViewPresenterDemo/ModelViewPresenterDemo.xcodeproj/project.xcworkspace/xcuserdata/dgadd.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /ModelViewPresenterDemo/ModelViewPresenterDemo.xcodeproj/xcuserdata/dgadd.xcuserdatad/xcschemes/All Tests.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 9 | 15 | 16 | 17 | 18 | 19 | 21 | 22 | 23 | 29 | 30 | 31 | 32 | 33 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /ModelViewPresenterDemo/ModelViewPresenterDemo.xcodeproj/xcuserdata/dgadd.xcuserdatad/xcschemes/ModelViewPresenterDemo.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | 14 | 20 | 21 | 22 | 23 | 24 | 29 | 30 | 32 | 38 | 39 | 40 | 41 | 42 | 48 | 49 | 50 | 51 | 60 | 61 | 67 | 68 | 69 | 70 | 71 | 72 | 78 | 79 | 85 | 86 | 87 | 88 | 90 | 91 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /ModelViewPresenterDemo/ModelViewPresenterDemo.xcodeproj/xcuserdata/dgadd.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | ModelViewPresenterDemo.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 72324F3815A9102B0034CA8A 16 | 17 | primary 18 | 19 | 20 | 72324F5C15A9102B0034CA8A 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /ModelViewPresenterDemo/ModelViewPresenterDemo/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // ModelViewPresenterDemo 4 | // 5 | // Created by David Gadd on 12-07-07. 6 | // Copyright (c) 2012 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /ModelViewPresenterDemo/ModelViewPresenterDemo/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // ModelViewPresenterDemo 4 | // 5 | // Created by David Gadd on 12-07-07. 6 | // Copyright (c) 2012 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @implementation AppDelegate 12 | 13 | @synthesize window = _window; 14 | 15 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 16 | { 17 | // Override point for customization after application launch. 18 | return YES; 19 | } 20 | 21 | - (void)applicationWillResignActive:(UIApplication *)application 22 | { 23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 24 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 25 | } 26 | 27 | - (void)applicationDidEnterBackground:(UIApplication *)application 28 | { 29 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 31 | } 32 | 33 | - (void)applicationWillEnterForeground:(UIApplication *)application 34 | { 35 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 36 | } 37 | 38 | - (void)applicationDidBecomeActive:(UIApplication *)application 39 | { 40 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 41 | } 42 | 43 | - (void)applicationWillTerminate:(UIApplication *)application 44 | { 45 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 46 | } 47 | 48 | @end 49 | -------------------------------------------------------------------------------- /ModelViewPresenterDemo/ModelViewPresenterDemo/ModelViewPresenterDemo-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | com.gaddzeit.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | UIMainStoryboardFile 28 | MainStoryboard_iPhone 29 | UIMainStoryboardFile~ipad 30 | MainStoryboard_iPad 31 | UIRequiredDeviceCapabilities 32 | 33 | armv7 34 | 35 | UISupportedInterfaceOrientations 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationLandscapeLeft 39 | UIInterfaceOrientationLandscapeRight 40 | 41 | UISupportedInterfaceOrientations~ipad 42 | 43 | UIInterfaceOrientationPortrait 44 | UIInterfaceOrientationPortraitUpsideDown 45 | UIInterfaceOrientationLandscapeLeft 46 | UIInterfaceOrientationLandscapeRight 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /ModelViewPresenterDemo/ModelViewPresenterDemo/ModelViewPresenterDemo-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'ModelViewPresenterDemo' target in the 'ModelViewPresenterDemo' project 3 | // 4 | 5 | #import 6 | 7 | #ifndef __IPHONE_5_0 8 | #warning "This project uses features only available in iOS SDK 5.0 and later." 9 | #endif 10 | 11 | #ifdef __OBJC__ 12 | #import 13 | #import 14 | #endif 15 | -------------------------------------------------------------------------------- /ModelViewPresenterDemo/ModelViewPresenterDemo/Presenters/BookListPresenter.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @protocol IDisplayBooksView; 4 | @protocol IBookStoreRepository; 5 | 6 | 7 | @interface BookListPresenter : NSObject 8 | @property(nonatomic, strong) id displayBooksView; 9 | @property(nonatomic, strong) id bookStoreRepository; 10 | 11 | - (BookListPresenter *)initWithBookStoreRepository:(id )bookStoreRepository andDisplayBooksView:(id )displayBooksView; 12 | 13 | - (void)displayBooksFromBookstore; 14 | @end -------------------------------------------------------------------------------- /ModelViewPresenterDemo/ModelViewPresenterDemo/Presenters/BookListPresenter.m: -------------------------------------------------------------------------------- 1 | #import "BookListPresenter.h" 2 | #import "IDisplayBooksView.h" 3 | #import "IBookStoreRepository.h" 4 | 5 | 6 | @implementation BookListPresenter { 7 | 8 | @private 9 | id _bookStoreRepository; 10 | } 11 | @synthesize displayBooksView = _displayBooksView; 12 | @synthesize bookStoreRepository = _bookStoreRepository; 13 | 14 | 15 | - (BookListPresenter *)initWithBookStoreRepository:(id )bookStoreRepository andDisplayBooksView:(id )displayBooksView { 16 | if (self = [super init]) { 17 | _bookStoreRepository = bookStoreRepository; 18 | _displayBooksView = displayBooksView; 19 | } 20 | 21 | return self; 22 | } 23 | 24 | - (void)displayBooksFromBookstore { 25 | NSArray *const books = [_bookStoreRepository findAllBooks]; 26 | [_displayBooksView displayBooks:books]; 27 | } 28 | @end -------------------------------------------------------------------------------- /ModelViewPresenterDemo/ModelViewPresenterDemo/Repositories/FakeBookStoreRepository.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "IBookStoreRepository.h" 3 | 4 | 5 | @interface FakeBookStoreRepository : NSObject 6 | @end -------------------------------------------------------------------------------- /ModelViewPresenterDemo/ModelViewPresenterDemo/Repositories/FakeBookStoreRepository.m: -------------------------------------------------------------------------------- 1 | #import "FakeBookStoreRepository.h" 2 | 3 | 4 | @implementation FakeBookStoreRepository { 5 | 6 | 7 | } 8 | - (NSArray *)findAllBooks { 9 | return [NSArray arrayWithObjects:@"Moby Dick", 10 | @"A Tale of Two Cities", 11 | @"Great Expectations", 12 | @"Absalom, Absalom", 13 | @"Cat's Eye", 14 | nil]; 15 | } 16 | 17 | 18 | @end -------------------------------------------------------------------------------- /ModelViewPresenterDemo/ModelViewPresenterDemo/Repositories/IBookStoreRepository.h: -------------------------------------------------------------------------------- 1 | @protocol IBookStoreRepository 2 | 3 | @required 4 | -(NSArray *)findAllBooks; 5 | @end -------------------------------------------------------------------------------- /ModelViewPresenterDemo/ModelViewPresenterDemo/ViewControllers/DisplayBooksTableViewController.h: -------------------------------------------------------------------------------- 1 | #import "IDisplayBooksView.h" 2 | 3 | @interface DisplayBooksTableViewController : UITableViewController 4 | 5 | @property(nonatomic, strong) NSArray *books; 6 | @end 7 | -------------------------------------------------------------------------------- /ModelViewPresenterDemo/ModelViewPresenterDemo/ViewControllers/DisplayBooksTableViewController.m: -------------------------------------------------------------------------------- 1 | #import "DisplayBooksTableViewController.h" 2 | #import "BookListPresenter.h" 3 | #import "IBookStoreRepository.h" 4 | #import "FakeBookStoreRepository.h" 5 | 6 | @interface DisplayBooksTableViewController () 7 | - (BookListPresenter *)delegateDependencyInjectionToAnIocContainer; 8 | 9 | 10 | @end 11 | 12 | @implementation DisplayBooksTableViewController 13 | @synthesize books = _books; 14 | 15 | 16 | - (id)initWithStyle:(UITableViewStyle)style 17 | { 18 | self = [super initWithStyle:style]; 19 | if (self) { 20 | // Custom initialization 21 | } 22 | return self; 23 | } 24 | 25 | - (void)displayBooks:(NSArray *)books { 26 | _books = books; 27 | } 28 | 29 | - (void)viewDidLoad { 30 | [super viewDidLoad]; 31 | BookListPresenter *presenter = [self delegateDependencyInjectionToAnIocContainer]; 32 | [presenter displayBooksFromBookstore]; 33 | } 34 | 35 | - (void)viewDidUnload { 36 | [super viewDidUnload]; 37 | } 38 | 39 | - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { 40 | return (interfaceOrientation == UIInterfaceOrientationPortrait); 41 | } 42 | 43 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 44 | return 1; 45 | } 46 | 47 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 48 | return [_books count]; 49 | } 50 | 51 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 52 | static NSString *CellIdentifier = @"BooksCell"; 53 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 54 | [cell textLabel].text = [_books objectAtIndex:indexPath.row]; 55 | 56 | return cell; 57 | } 58 | 59 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 60 | // do nothing 61 | } 62 | 63 | - (BookListPresenter *)delegateDependencyInjectionToAnIocContainer { 64 | id bookStoreRepository = [[FakeBookStoreRepository alloc] init]; 65 | BookListPresenter *const presenter = [[BookListPresenter alloc] initWithBookStoreRepository:bookStoreRepository 66 | andDisplayBooksView:self]; 67 | return presenter; 68 | } 69 | 70 | 71 | @end 72 | -------------------------------------------------------------------------------- /ModelViewPresenterDemo/ModelViewPresenterDemo/Views/IDisplayBooksView.h: -------------------------------------------------------------------------------- 1 | @protocol IDisplayBooksView 2 | 3 | @required 4 | - (void)displayBooks:(NSArray*)books; 5 | @end -------------------------------------------------------------------------------- /ModelViewPresenterDemo/ModelViewPresenterDemo/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /ModelViewPresenterDemo/ModelViewPresenterDemo/en.lproj/MainStoryboard_iPad.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /ModelViewPresenterDemo/ModelViewPresenterDemo/en.lproj/MainStoryboard_iPhone.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /ModelViewPresenterDemo/ModelViewPresenterDemo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // ModelViewPresenterDemo 4 | // 5 | // Created by David Gadd on 12-07-07. 6 | // Copyright (c) 2012 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "AppDelegate.h" 12 | 13 | int main(int argc, char *argv[]) 14 | { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /ModelViewPresenterDemo/ModelViewPresenterDemoTests/BookListPresenterTests.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @class BookListPresenter; 4 | 5 | @interface BookListPresenterTests : SenTestCase { 6 | BookListPresenter *sut; 7 | } 8 | 9 | @end 10 | -------------------------------------------------------------------------------- /ModelViewPresenterDemo/ModelViewPresenterDemoTests/BookListPresenterTests.m: -------------------------------------------------------------------------------- 1 | #import "BookListPresenterTests.h" 2 | #import "BookListPresenter.h" 3 | #import "OCMockObject.h" 4 | #import "IDisplayBooksView.h" 5 | #import "OCMockRecorder.h" 6 | #import "IBookStoreRepository.h" 7 | #import "FakeBookStoreRepository.h" 8 | 9 | @implementation BookListPresenterTests 10 | 11 | - (void)setUp { 12 | [super setUp]; 13 | } 14 | 15 | - (void)testMockDisplayBooksFromBookStoreMethod_callToRepositoryToFindAll_booksAreBoundToView { 16 | NSArray* books = [NSArray arrayWithObjects:@"Moby Dick", @"The Grapes of Wrath", @"Tale of Two Cities", nil]; 17 | 18 | id bookStoreRepository = [OCMockObject mockForProtocol:@protocol(IBookStoreRepository)]; 19 | [[[bookStoreRepository expect] andReturn:books] findAllBooks]; 20 | 21 | id displayBooksView = [OCMockObject mockForProtocol:@protocol(IDisplayBooksView)]; 22 | [[displayBooksView expect] displayBooks:books]; 23 | 24 | sut = [[BookListPresenter alloc] initWithBookStoreRepository:bookStoreRepository andDisplayBooksView:displayBooksView]; 25 | [sut displayBooksFromBookstore]; 26 | 27 | 28 | [bookStoreRepository verify]; 29 | [displayBooksView verify]; 30 | } 31 | 32 | - (void)testDisplayBooksFromBookStoreMethod_callToRepositoryToFindAll_booksAreBoundToView { 33 | NSArray*expectedBooks = [NSArray arrayWithObjects:@"Moby Dick", 34 | @"A Tale of Two Cities", 35 | @"Great Expectations", 36 | @"Absalom, Absalom", 37 | @"Cat's Eye", 38 | nil]; 39 | 40 | id bookStoreRepository = [[FakeBookStoreRepository alloc] init]; 41 | NSArray *const booksReturned = [bookStoreRepository findAllBooks]; 42 | 43 | STAssertEqualObjects(expectedBooks, booksReturned, @"The books returned should match expected."); 44 | } 45 | @end 46 | -------------------------------------------------------------------------------- /ModelViewPresenterDemo/ModelViewPresenterDemoTests/ModelViewPresenterDemoTests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | com.gaddzeit.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /ModelViewPresenterDemo/ModelViewPresenterDemoTests/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /ModelViewPresenterDemo/OCMocksLibs/OCMock/NSNotificationCenter+OCMAdditions.h: -------------------------------------------------------------------------------- 1 | //--------------------------------------------------------------------------------------- 2 | // $Id$ 3 | // Copyright (c) 2009 by Mulle Kybernetik. See License file for details. 4 | //--------------------------------------------------------------------------------------- 5 | 6 | #import 7 | 8 | @class OCMockObserver; 9 | 10 | 11 | @interface NSNotificationCenter(OCMAdditions) 12 | 13 | - (void)addMockObserver:(OCMockObserver *)notificationObserver name:(NSString *)notificationName object:(id)notificationSender; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /ModelViewPresenterDemo/OCMocksLibs/OCMock/OCMArg.h: -------------------------------------------------------------------------------- 1 | //--------------------------------------------------------------------------------------- 2 | // $Id$ 3 | // Copyright (c) 2009-2010 by Mulle Kybernetik. See License file for details. 4 | //--------------------------------------------------------------------------------------- 5 | 6 | #import 7 | 8 | @interface OCMArg : NSObject 9 | 10 | // constraining arguments 11 | 12 | + (id)any; 13 | + (void *)anyPointer; 14 | + (id)isNil; 15 | + (id)isNotNil; 16 | + (id)isNotEqual:(id)value; 17 | + (id)checkWithSelector:(SEL)selector onObject:(id)anObject; 18 | #if NS_BLOCKS_AVAILABLE 19 | + (id)checkWithBlock:(BOOL (^)(id))block; 20 | #endif 21 | 22 | // manipulating arguments 23 | 24 | + (id *)setTo:(id)value; 25 | 26 | // internal use only 27 | 28 | + (id)resolveSpecialValues:(NSValue *)value; 29 | 30 | @end 31 | 32 | #define OCMOCK_ANY [OCMArg any] 33 | #define OCMOCK_VALUE(variable) [NSValue value:&variable withObjCType:@encode(__typeof__(variable))] 34 | -------------------------------------------------------------------------------- /ModelViewPresenterDemo/OCMocksLibs/OCMock/OCMConstraint.h: -------------------------------------------------------------------------------- 1 | //--------------------------------------------------------------------------------------- 2 | // $Id$ 3 | // Copyright (c) 2007-2010 by Mulle Kybernetik. See License file for details. 4 | //--------------------------------------------------------------------------------------- 5 | 6 | #import 7 | 8 | 9 | @interface OCMConstraint : NSObject 10 | 11 | + (id)constraint; 12 | - (BOOL)evaluate:(id)value; 13 | 14 | // if you are looking for any, isNil, etc, they have moved to OCMArg 15 | 16 | // try to use [OCMArg checkWith...] instead of the constraintWith... methods below 17 | 18 | + (id)constraintWithSelector:(SEL)aSelector onObject:(id)anObject; 19 | + (id)constraintWithSelector:(SEL)aSelector onObject:(id)anObject withValue:(id)aValue; 20 | 21 | 22 | @end 23 | 24 | @interface OCMAnyConstraint : OCMConstraint 25 | @end 26 | 27 | @interface OCMIsNilConstraint : OCMConstraint 28 | @end 29 | 30 | @interface OCMIsNotNilConstraint : OCMConstraint 31 | @end 32 | 33 | @interface OCMIsNotEqualConstraint : OCMConstraint 34 | { 35 | @public 36 | id testValue; 37 | } 38 | 39 | @end 40 | 41 | @interface OCMInvocationConstraint : OCMConstraint 42 | { 43 | @public 44 | NSInvocation *invocation; 45 | } 46 | 47 | @end 48 | 49 | #if NS_BLOCKS_AVAILABLE 50 | 51 | @interface OCMBlockConstraint : OCMConstraint 52 | { 53 | BOOL (^block)(id); 54 | } 55 | 56 | - (id)initWithConstraintBlock:(BOOL (^)(id))block; 57 | 58 | @end 59 | 60 | #endif 61 | 62 | 63 | #define CONSTRAINT(aSelector) [OCMConstraint constraintWithSelector:aSelector onObject:self] 64 | #define CONSTRAINTV(aSelector, aValue) [OCMConstraint constraintWithSelector:aSelector onObject:self withValue:(aValue)] 65 | -------------------------------------------------------------------------------- /ModelViewPresenterDemo/OCMocksLibs/OCMock/OCMock.h: -------------------------------------------------------------------------------- 1 | //--------------------------------------------------------------------------------------- 2 | // $Id$ 3 | // Copyright (c) 2004-2008 by Mulle Kybernetik. See License file for details. 4 | //--------------------------------------------------------------------------------------- 5 | 6 | #import 7 | #import 8 | #import 9 | #import 10 | #import 11 | -------------------------------------------------------------------------------- /ModelViewPresenterDemo/OCMocksLibs/OCMock/OCMockObject.h: -------------------------------------------------------------------------------- 1 | //--------------------------------------------------------------------------------------- 2 | // $Id$ 3 | // Copyright (c) 2004-2008 by Mulle Kybernetik. See License file for details. 4 | //--------------------------------------------------------------------------------------- 5 | 6 | #import 7 | 8 | @interface OCMockObject : NSProxy 9 | { 10 | BOOL isNice; 11 | BOOL expectationOrderMatters; 12 | NSMutableArray *recorders; 13 | NSMutableArray *expectations; 14 | NSMutableArray *rejections; 15 | NSMutableArray *exceptions; 16 | } 17 | 18 | + (id)mockForClass:(Class)aClass; 19 | + (id)mockForProtocol:(Protocol *)aProtocol; 20 | + (id)partialMockForObject:(NSObject *)anObject; 21 | 22 | + (id)niceMockForClass:(Class)aClass; 23 | + (id)niceMockForProtocol:(Protocol *)aProtocol; 24 | 25 | + (id)observerMock; 26 | 27 | - (id)init; 28 | 29 | - (void)setExpectationOrderMatters:(BOOL)flag; 30 | 31 | - (id)stub; 32 | - (id)expect; 33 | - (id)reject; 34 | 35 | - (void)verify; 36 | 37 | // internal use only 38 | 39 | - (id)getNewRecorder; 40 | - (BOOL)handleInvocation:(NSInvocation *)anInvocation; 41 | - (void)handleUnRecordedInvocation:(NSInvocation *)anInvocation; 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /ModelViewPresenterDemo/OCMocksLibs/OCMock/OCMockRecorder.h: -------------------------------------------------------------------------------- 1 | //--------------------------------------------------------------------------------------- 2 | // $Id$ 3 | // Copyright (c) 2004-2010 by Mulle Kybernetik. See License file for details. 4 | //--------------------------------------------------------------------------------------- 5 | 6 | #import 7 | 8 | @interface OCMockRecorder : NSProxy 9 | { 10 | id signatureResolver; 11 | NSInvocation *recordedInvocation; 12 | NSMutableArray *invocationHandlers; 13 | } 14 | 15 | - (id)initWithSignatureResolver:(id)anObject; 16 | 17 | - (BOOL)matchesInvocation:(NSInvocation *)anInvocation; 18 | - (void)releaseInvocation; 19 | 20 | - (id)andReturn:(id)anObject; 21 | - (id)andReturnValue:(NSValue *)aValue; 22 | - (id)andThrow:(NSException *)anException; 23 | - (id)andPost:(NSNotification *)aNotification; 24 | - (id)andCall:(SEL)selector onObject:(id)anObject; 25 | #if NS_BLOCKS_AVAILABLE 26 | - (id)andDo:(void (^)(NSInvocation *))block; 27 | #endif 28 | - (id)andForwardToRealObject; 29 | 30 | - (NSArray *)invocationHandlers; 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /ModelViewPresenterDemo/OCMocksLibs/libOCMock.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dgadd/iOSModelViewPresenter/d07d26b8f18073f0f917afef32f3b68fee194862/ModelViewPresenterDemo/OCMocksLibs/libOCMock.a -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 |

Model-View-Presenter Example in iOS

2 | 3 |

4 | NOTE This sample code demonstrates only ONE method in the presenter class, a method to push an array of book titles to the view. In a typical, busy view controller with multiple events being handled, the underlying presenter class might have many methods to serve each of these activities. 5 |

6 | 7 |

8 | Over time, I will try and add additional presenter methods to this example. 9 |

10 | 11 |
12 | 13 |

Explanation of Model-View-Presenter (used with protocols in iOS)

14 |

15 | MVP is a solution to the age-old problem of business logic and external coordination concerns slipping into the presentation layer. The view controllers in iOS are largely concerned with serving the view, either by listening for events and handling them (typically through delegate methods or IBAction methods), or by assigning information to properties. But it is difficult to prevent the rest of the application's concerns slipping into this layer by default. 16 |

17 | 18 |

19 | The best way to prevent this is by writing unit tests against the view controller. However, the view controller has many concerns and couplings that would make truly isolated unit-tests difficult. 20 |

21 | 22 |

23 | The Model-View-Presenter pattern addresses this by creating a new, simple class called a presenter, with no direct dependencies on any concerns above it (presentation) or below it (business logic, IO, data). The Presenter achieves this by only operating against protocols (interfaces in java/C#) which have been injected into the constructor (alloc/init) of the class. Unit tests use a combination of mock objects (that observe and verify behavior), stubs (simple auto-generated implementations of the protocol) or fully-created fake classes to verify the behavior of the presenter, without ever directly connecting to the view controller or underlying data sources. 24 |

25 | 26 |

27 | In this example code, the implementation of Model-View-Presenter uses: 28 |

    29 |
  • groups that store Presenters, Views, Models (and also: Repositories and ViewControllers)
  • 30 |
  • the Presenter init takes as parameters protocols (in Java and C#, this would be interfaces)
  • 31 |
  • the first parameter is a protocol for a repository (to query and return the Model)
  • 32 |
  • the second parameter is a protocol for the View (to receive content that is pushed to it, and to notify of events that it has received)
  • 33 |
  • the Model group is empty; the model in this implementation is merely an NSString* (a book title)
  • 34 |
35 |

36 | 37 |

38 | The first unit test in this sample code uses mock objects to design and verify the behavior of the presenter methods. These methods coordinate the actions of the protocols that have been dependency-injected into the presenter's init. Specifically, the test verifies its expectation that the presenter's displayBooksFromBookstore method will: 39 |

    40 |
  • find all books from the book store repository
  • 41 |
  • "push" those books to the view
  • 42 |
43 |

44 | 45 |

46 | The second unit test uses a fake class to verify that data passed through the presenter matches as expected. 47 |

48 | 49 |

50 | Finally: What should the view controller look like when Model-View-Presenter is used? 51 |

52 | 53 |

54 | It should have 4 main effects: 55 |

    56 |
  • An init or early event in the view controller should instantiate the presenter, passing in "self" as the conforming view protocol
  • 57 |
  • your view controller will still have lots of methods--filled with the event handling and delegate fulfilment methods that are typically required for an objective-C application. But the CONTENT of those methods will have changed.
  • 58 |
  • these methods should now contain only presentation logic. For example, the table row event will still have to retrieve the cell by its identifier and assign values to the cell's contents--those are a presentation-level concern
  • 59 |
  • but any non-presentation logic (coordination logic, business logic, model manipulation) will now be passed to presenter methods instead.
  • 60 |
61 |

62 | 63 |

64 | And those presenter methods will now be isolated/decoupled and therefore can (and should) each be verified and validated by mock and unit tests. 65 |

--------------------------------------------------------------------------------