├── Podfile ├── README.md ├── RxSwiftMVVM.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ └── wangjianwei.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ └── wangjianwei.xcuserdatad │ └── xcschemes │ └── xcschememanagement.plist ├── RxSwiftMVVM ├── AppDelegate.swift ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── Info.plist ├── MVVM │ ├── Base │ │ ├── BaseTabBarViewController.swift │ │ ├── BaseViewController.swift │ │ ├── BaseViewModel.swift │ │ └── DataModel.swift │ ├── Log │ │ └── Log.swift │ ├── Model │ │ ├── API.swift │ │ ├── JsonModel │ │ │ └── Observable+HandyJSON.swift │ │ ├── Model.swift │ │ ├── ModelProtocol.swift │ │ └── RxMoya │ │ │ └── MoyaProvider+Rx.swift │ ├── Router │ │ └── Router.swift │ ├── Stack │ │ └── Stack.swift │ ├── View │ │ ├── View.swift │ │ ├── ViewModelMapper.swift │ │ └── j.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcuserdata │ │ │ └── wangjianwei.xcuserdatad │ │ │ └── UserInterfaceState.xcuserstate │ └── ViewModel │ │ ├── Service.swift │ │ ├── ViewModelProtocol.swift │ │ └── ViewModelService.swift └── Project │ └── Business │ ├── DemoOne │ ├── Model │ │ └── FirstModel.swift │ ├── View │ │ └── ZhihuTableViewCell.swift │ ├── ViewController │ │ └── FirstViewController.swift │ └── ViewModel │ │ └── FirstViewModel.swift │ ├── DemoTwo │ ├── Model │ │ └── SecondModel.swift │ ├── ViewController │ │ └── SecondViewController.swift │ └── ViewModel │ │ └── SecondViewModel.swift │ └── Home │ ├── ViewController │ └── HomeViewController.swift │ └── ViewModel │ └── HomeViewModel.swift ├── RxSwiftMVVMTests ├── Info.plist └── RxSwiftMVVMTests.swift ├── RxSwiftMVVMUITests ├── Info.plist └── RxSwiftMVVMUITests.swift └── _config.yml /Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment the next line to define a global platform for your project 2 | # platform :ios, '9.0' 3 | 4 | target 'RxSwiftMVVM' do 5 | # Comment the next line if you're not using Swift and don't want to use dynamic frameworks 6 | use_frameworks! 7 | #ReactiveX 8 | pod 'RxCocoa' 9 | pod 'RxSwiftExt' 10 | pod 'RxDataSources' 11 | pod 'NSObject+Rx' 12 | pod 'Action' 13 | #NetWithRxSwift 14 | pod 'Moya/RxSwift' 15 | #JsonModel 16 | pod 'HandyJSON', '4.0.0-beta.1' 17 | #ImageView 18 | pod 'Kingfisher' 19 | # Pods for RxSwiftMVVM 20 | 21 | target 'RxSwiftMVVMTests' do 22 | inherit! :search_paths 23 | # Pods for testing 24 | end 25 | 26 | target 'RxSwiftMVVMUITests' do 27 | inherit! :search_paths 28 | # Pods for testing 29 | end 30 | 31 | end 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RxSwiftMVVM 2 | 3 | RxSwift MVVM Moya HandyJSON, basic architecture With Swift, make developer code easy. 4 | 5 | 6 | Idea from http://blog.leichunfeng.com/blog/2016/02/27/mvvm-with-reactivecocoa/ , an exciting architecture depend on ReactiveCocoa With ObjC. 7 | 8 | 9 | Thanks to the author. 10 | -------------------------------------------------------------------------------- /RxSwiftMVVM.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 48; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 19100D3613713E9837924519 /* Pods_RxSwiftMVVMTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B2CB5C8F5E2A2B1C46C87D2 /* Pods_RxSwiftMVVMTests.framework */; }; 11 | 658F7752D181C320F3C8E12B /* Pods_RxSwiftMVVM.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1B63B15517C171CF29F7E626 /* Pods_RxSwiftMVVM.framework */; }; 12 | 7F09E6691FA814A800EDAA6D /* Model.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F09E6681FA814A800EDAA6D /* Model.swift */; }; 13 | 7F146B1C1FAAC636003652D3 /* API.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F146B1B1FAAC636003652D3 /* API.swift */; }; 14 | 7F146B1E1FAAF632003652D3 /* MoyaProvider+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F146B1D1FAAF631003652D3 /* MoyaProvider+Rx.swift */; }; 15 | 7F44FF811F80BA720053B8A6 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F44FF801F80BA720053B8A6 /* AppDelegate.swift */; }; 16 | 7F44FF861F80BA720053B8A6 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 7F44FF841F80BA720053B8A6 /* Main.storyboard */; }; 17 | 7F44FF881F80BA720053B8A6 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 7F44FF871F80BA720053B8A6 /* Assets.xcassets */; }; 18 | 7F44FF8B1F80BA720053B8A6 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 7F44FF891F80BA720053B8A6 /* LaunchScreen.storyboard */; }; 19 | 7F44FF961F80BA720053B8A6 /* RxSwiftMVVMTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F44FF951F80BA720053B8A6 /* RxSwiftMVVMTests.swift */; }; 20 | 7F44FFA11F80BA720053B8A6 /* RxSwiftMVVMUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F44FFA01F80BA720053B8A6 /* RxSwiftMVVMUITests.swift */; }; 21 | 7F5AD6CA1FA08C450056066A /* Observable+HandyJSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F5AD6C91FA08C450056066A /* Observable+HandyJSON.swift */; }; 22 | 7F875A351FA8B6B9008E5683 /* SecondViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F875A341FA8B6B9008E5683 /* SecondViewController.swift */; }; 23 | 7F875A371FA8B6C7008E5683 /* SecondModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F875A361FA8B6C7008E5683 /* SecondModel.swift */; }; 24 | 7F875A391FA8B6D2008E5683 /* SecondViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F875A381FA8B6D2008E5683 /* SecondViewModel.swift */; }; 25 | 7F875A3B1FA8B6E1008E5683 /* FirstViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F875A3A1FA8B6E1008E5683 /* FirstViewController.swift */; }; 26 | 7F875A3D1FA8B6EB008E5683 /* FirstModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F875A3C1FA8B6EB008E5683 /* FirstModel.swift */; }; 27 | 7F875A3F1FA8B6F5008E5683 /* FirstViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F875A3E1FA8B6F5008E5683 /* FirstViewModel.swift */; }; 28 | 7F8A08791FA6CDB90009750F /* View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F8A08781FA6CDB90009750F /* View.swift */; }; 29 | 7F8A087E1FA6CF0D0009750F /* ViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F8A087D1FA6CF0D0009750F /* ViewModelProtocol.swift */; }; 30 | 7F8A08801FA6CF1E0009750F /* ModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F8A087F1FA6CF1E0009750F /* ModelProtocol.swift */; }; 31 | 7F8A08821FA6D0580009750F /* ViewModelService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F8A08811FA6D0580009750F /* ViewModelService.swift */; }; 32 | 7F8A08861FA7070B0009750F /* Log.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F8A08851FA7070B0009750F /* Log.swift */; }; 33 | 7F8A08891FA71E9F0009750F /* Stack.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F8A08881FA71E9F0009750F /* Stack.swift */; }; 34 | 7F8A088B1FA731D60009750F /* Service.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F8A088A1FA731D60009750F /* Service.swift */; }; 35 | 7F8A088E1FA7609F0009750F /* Router.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F8A088D1FA7609F0009750F /* Router.swift */; }; 36 | 7F8A08911FA771DE0009750F /* BaseViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F8A08901FA771DE0009750F /* BaseViewModel.swift */; }; 37 | 7F8A08931FA7724A0009750F /* BaseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F8A08921FA7724A0009750F /* BaseViewController.swift */; }; 38 | 7FC7B5031FA870780094B274 /* BaseTabBarViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7FC7B5021FA870780094B274 /* BaseTabBarViewController.swift */; }; 39 | 7FC7B50C1FA8785E0094B274 /* DataModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7FC7B50B1FA8785E0094B274 /* DataModel.swift */; }; 40 | 7FC7B50F1FA878B00094B274 /* HomeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7FC7B50E1FA878B00094B274 /* HomeViewModel.swift */; }; 41 | 7FC7B51C1FA87CD60094B274 /* HomeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7FC7B51B1FA87CD60094B274 /* HomeViewController.swift */; }; 42 | 7FF97E031FAC125D0088745D /* ViewModelMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7FF97E021FAC125D0088745D /* ViewModelMapper.swift */; }; 43 | 7FF97E061FAC5B6D0088745D /* ZhihuTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7FF97E051FAC5B6D0088745D /* ZhihuTableViewCell.swift */; }; 44 | EA4ACF092E4322A140FA110D /* Pods_RxSwiftMVVMUITests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FDF60653077F647AAB1CCAE4 /* Pods_RxSwiftMVVMUITests.framework */; }; 45 | /* End PBXBuildFile section */ 46 | 47 | /* Begin PBXContainerItemProxy section */ 48 | 7F44FF921F80BA720053B8A6 /* PBXContainerItemProxy */ = { 49 | isa = PBXContainerItemProxy; 50 | containerPortal = 7F44FF751F80BA720053B8A6 /* Project object */; 51 | proxyType = 1; 52 | remoteGlobalIDString = 7F44FF7C1F80BA720053B8A6; 53 | remoteInfo = RxSwiftMVVM; 54 | }; 55 | 7F44FF9D1F80BA720053B8A6 /* PBXContainerItemProxy */ = { 56 | isa = PBXContainerItemProxy; 57 | containerPortal = 7F44FF751F80BA720053B8A6 /* Project object */; 58 | proxyType = 1; 59 | remoteGlobalIDString = 7F44FF7C1F80BA720053B8A6; 60 | remoteInfo = RxSwiftMVVM; 61 | }; 62 | /* End PBXContainerItemProxy section */ 63 | 64 | /* Begin PBXFileReference section */ 65 | 1B63B15517C171CF29F7E626 /* Pods_RxSwiftMVVM.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RxSwiftMVVM.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 66 | 255F084072E64017D216BE6A /* Pods-RxSwiftMVVMTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RxSwiftMVVMTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-RxSwiftMVVMTests/Pods-RxSwiftMVVMTests.release.xcconfig"; sourceTree = ""; }; 67 | 27A34DD4B9F2B804FFFE0786 /* Pods-RxSwiftMVVM.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RxSwiftMVVM.release.xcconfig"; path = "Pods/Target Support Files/Pods-RxSwiftMVVM/Pods-RxSwiftMVVM.release.xcconfig"; sourceTree = ""; }; 68 | 3A0BF2A9DA9268A488E8576D /* Pods-RxSwiftMVVMUITests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RxSwiftMVVMUITests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-RxSwiftMVVMUITests/Pods-RxSwiftMVVMUITests.debug.xcconfig"; sourceTree = ""; }; 69 | 5B2CB5C8F5E2A2B1C46C87D2 /* Pods_RxSwiftMVVMTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RxSwiftMVVMTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 70 | 7EBE4623AED6A1A917A6C636 /* Pods-RxSwiftMVVMUITests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RxSwiftMVVMUITests.release.xcconfig"; path = "Pods/Target Support Files/Pods-RxSwiftMVVMUITests/Pods-RxSwiftMVVMUITests.release.xcconfig"; sourceTree = ""; }; 71 | 7F09E6681FA814A800EDAA6D /* Model.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Model.swift; sourceTree = ""; }; 72 | 7F146B1B1FAAC636003652D3 /* API.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = API.swift; sourceTree = ""; }; 73 | 7F146B1D1FAAF631003652D3 /* MoyaProvider+Rx.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "MoyaProvider+Rx.swift"; sourceTree = ""; }; 74 | 7F44FF7D1F80BA720053B8A6 /* RxSwiftMVVM.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RxSwiftMVVM.app; sourceTree = BUILT_PRODUCTS_DIR; }; 75 | 7F44FF801F80BA720053B8A6 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 76 | 7F44FF851F80BA720053B8A6 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 77 | 7F44FF871F80BA720053B8A6 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 78 | 7F44FF8A1F80BA720053B8A6 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 79 | 7F44FF8C1F80BA720053B8A6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 80 | 7F44FF911F80BA720053B8A6 /* RxSwiftMVVMTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RxSwiftMVVMTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 81 | 7F44FF951F80BA720053B8A6 /* RxSwiftMVVMTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RxSwiftMVVMTests.swift; sourceTree = ""; }; 82 | 7F44FF971F80BA720053B8A6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 83 | 7F44FF9C1F80BA720053B8A6 /* RxSwiftMVVMUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RxSwiftMVVMUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 84 | 7F44FFA01F80BA720053B8A6 /* RxSwiftMVVMUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RxSwiftMVVMUITests.swift; sourceTree = ""; }; 85 | 7F44FFA21F80BA720053B8A6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 86 | 7F5AD6C91FA08C450056066A /* Observable+HandyJSON.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Observable+HandyJSON.swift"; sourceTree = ""; }; 87 | 7F875A341FA8B6B9008E5683 /* SecondViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecondViewController.swift; sourceTree = ""; }; 88 | 7F875A361FA8B6C7008E5683 /* SecondModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecondModel.swift; sourceTree = ""; }; 89 | 7F875A381FA8B6D2008E5683 /* SecondViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecondViewModel.swift; sourceTree = ""; }; 90 | 7F875A3A1FA8B6E1008E5683 /* FirstViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirstViewController.swift; sourceTree = ""; }; 91 | 7F875A3C1FA8B6EB008E5683 /* FirstModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirstModel.swift; sourceTree = ""; }; 92 | 7F875A3E1FA8B6F5008E5683 /* FirstViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirstViewModel.swift; sourceTree = ""; }; 93 | 7F8A08781FA6CDB90009750F /* View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = View.swift; sourceTree = ""; }; 94 | 7F8A087D1FA6CF0D0009750F /* ViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewModelProtocol.swift; sourceTree = ""; }; 95 | 7F8A087F1FA6CF1E0009750F /* ModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModelProtocol.swift; sourceTree = ""; }; 96 | 7F8A08811FA6D0580009750F /* ViewModelService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewModelService.swift; sourceTree = ""; }; 97 | 7F8A08851FA7070B0009750F /* Log.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Log.swift; sourceTree = ""; }; 98 | 7F8A08881FA71E9F0009750F /* Stack.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Stack.swift; sourceTree = ""; }; 99 | 7F8A088A1FA731D60009750F /* Service.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Service.swift; sourceTree = ""; }; 100 | 7F8A088D1FA7609F0009750F /* Router.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Router.swift; sourceTree = ""; }; 101 | 7F8A08901FA771DE0009750F /* BaseViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseViewModel.swift; sourceTree = ""; }; 102 | 7F8A08921FA7724A0009750F /* BaseViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseViewController.swift; sourceTree = ""; }; 103 | 7FC7B5021FA870780094B274 /* BaseTabBarViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseTabBarViewController.swift; sourceTree = ""; }; 104 | 7FC7B50B1FA8785E0094B274 /* DataModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataModel.swift; sourceTree = ""; }; 105 | 7FC7B50E1FA878B00094B274 /* HomeViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeViewModel.swift; sourceTree = ""; }; 106 | 7FC7B51B1FA87CD60094B274 /* HomeViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeViewController.swift; sourceTree = ""; }; 107 | 7FF97E021FAC125D0088745D /* ViewModelMapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewModelMapper.swift; sourceTree = ""; }; 108 | 7FF97E051FAC5B6D0088745D /* ZhihuTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZhihuTableViewCell.swift; sourceTree = ""; }; 109 | CA650F7B2926313E5C3ED3BC /* Pods-RxSwiftMVVMTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RxSwiftMVVMTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-RxSwiftMVVMTests/Pods-RxSwiftMVVMTests.debug.xcconfig"; sourceTree = ""; }; 110 | EC98160AF2A3FB09012F3C9A /* Pods-RxSwiftMVVM.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RxSwiftMVVM.debug.xcconfig"; path = "Pods/Target Support Files/Pods-RxSwiftMVVM/Pods-RxSwiftMVVM.debug.xcconfig"; sourceTree = ""; }; 111 | FDF60653077F647AAB1CCAE4 /* Pods_RxSwiftMVVMUITests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RxSwiftMVVMUITests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 112 | /* End PBXFileReference section */ 113 | 114 | /* Begin PBXFrameworksBuildPhase section */ 115 | 7F44FF7A1F80BA720053B8A6 /* Frameworks */ = { 116 | isa = PBXFrameworksBuildPhase; 117 | buildActionMask = 2147483647; 118 | files = ( 119 | 658F7752D181C320F3C8E12B /* Pods_RxSwiftMVVM.framework in Frameworks */, 120 | ); 121 | runOnlyForDeploymentPostprocessing = 0; 122 | }; 123 | 7F44FF8E1F80BA720053B8A6 /* Frameworks */ = { 124 | isa = PBXFrameworksBuildPhase; 125 | buildActionMask = 2147483647; 126 | files = ( 127 | 19100D3613713E9837924519 /* Pods_RxSwiftMVVMTests.framework in Frameworks */, 128 | ); 129 | runOnlyForDeploymentPostprocessing = 0; 130 | }; 131 | 7F44FF991F80BA720053B8A6 /* Frameworks */ = { 132 | isa = PBXFrameworksBuildPhase; 133 | buildActionMask = 2147483647; 134 | files = ( 135 | EA4ACF092E4322A140FA110D /* Pods_RxSwiftMVVMUITests.framework in Frameworks */, 136 | ); 137 | runOnlyForDeploymentPostprocessing = 0; 138 | }; 139 | /* End PBXFrameworksBuildPhase section */ 140 | 141 | /* Begin PBXGroup section */ 142 | 6D6276299B6C1BF0B6E404D9 /* Frameworks */ = { 143 | isa = PBXGroup; 144 | children = ( 145 | 1B63B15517C171CF29F7E626 /* Pods_RxSwiftMVVM.framework */, 146 | 5B2CB5C8F5E2A2B1C46C87D2 /* Pods_RxSwiftMVVMTests.framework */, 147 | FDF60653077F647AAB1CCAE4 /* Pods_RxSwiftMVVMUITests.framework */, 148 | ); 149 | name = Frameworks; 150 | sourceTree = ""; 151 | }; 152 | 7F146B1F1FAAF635003652D3 /* RxMoya */ = { 153 | isa = PBXGroup; 154 | children = ( 155 | 7F146B1D1FAAF631003652D3 /* MoyaProvider+Rx.swift */, 156 | ); 157 | path = RxMoya; 158 | sourceTree = ""; 159 | }; 160 | 7F44FF741F80BA720053B8A6 = { 161 | isa = PBXGroup; 162 | children = ( 163 | 7F44FF7F1F80BA720053B8A6 /* RxSwiftMVVM */, 164 | 7F44FF941F80BA720053B8A6 /* RxSwiftMVVMTests */, 165 | 7F44FF9F1F80BA720053B8A6 /* RxSwiftMVVMUITests */, 166 | 7F44FF7E1F80BA720053B8A6 /* Products */, 167 | D5CD4E78BC05A92672A6EDAF /* Pods */, 168 | 6D6276299B6C1BF0B6E404D9 /* Frameworks */, 169 | ); 170 | sourceTree = ""; 171 | }; 172 | 7F44FF7E1F80BA720053B8A6 /* Products */ = { 173 | isa = PBXGroup; 174 | children = ( 175 | 7F44FF7D1F80BA720053B8A6 /* RxSwiftMVVM.app */, 176 | 7F44FF911F80BA720053B8A6 /* RxSwiftMVVMTests.xctest */, 177 | 7F44FF9C1F80BA720053B8A6 /* RxSwiftMVVMUITests.xctest */, 178 | ); 179 | name = Products; 180 | sourceTree = ""; 181 | }; 182 | 7F44FF7F1F80BA720053B8A6 /* RxSwiftMVVM */ = { 183 | isa = PBXGroup; 184 | children = ( 185 | 7FC7B5041FA8779F0094B274 /* Project */, 186 | 7F8A087C1FA6CEA60009750F /* MVVM */, 187 | 7F44FF801F80BA720053B8A6 /* AppDelegate.swift */, 188 | 7F44FF841F80BA720053B8A6 /* Main.storyboard */, 189 | 7F44FF871F80BA720053B8A6 /* Assets.xcassets */, 190 | 7F44FF891F80BA720053B8A6 /* LaunchScreen.storyboard */, 191 | 7F44FF8C1F80BA720053B8A6 /* Info.plist */, 192 | ); 193 | path = RxSwiftMVVM; 194 | sourceTree = ""; 195 | }; 196 | 7F44FF941F80BA720053B8A6 /* RxSwiftMVVMTests */ = { 197 | isa = PBXGroup; 198 | children = ( 199 | 7F44FF951F80BA720053B8A6 /* RxSwiftMVVMTests.swift */, 200 | 7F44FF971F80BA720053B8A6 /* Info.plist */, 201 | ); 202 | path = RxSwiftMVVMTests; 203 | sourceTree = ""; 204 | }; 205 | 7F44FF9F1F80BA720053B8A6 /* RxSwiftMVVMUITests */ = { 206 | isa = PBXGroup; 207 | children = ( 208 | 7F44FFA01F80BA720053B8A6 /* RxSwiftMVVMUITests.swift */, 209 | 7F44FFA21F80BA720053B8A6 /* Info.plist */, 210 | ); 211 | path = RxSwiftMVVMUITests; 212 | sourceTree = ""; 213 | }; 214 | 7F875A2A1FA8B69F008E5683 /* DemoTwo */ = { 215 | isa = PBXGroup; 216 | children = ( 217 | 7F875A2B1FA8B69F008E5683 /* ViewModel */, 218 | 7F875A2C1FA8B69F008E5683 /* Model */, 219 | 7F875A2D1FA8B69F008E5683 /* View */, 220 | 7F875A2E1FA8B69F008E5683 /* ViewController */, 221 | ); 222 | path = DemoTwo; 223 | sourceTree = ""; 224 | }; 225 | 7F875A2B1FA8B69F008E5683 /* ViewModel */ = { 226 | isa = PBXGroup; 227 | children = ( 228 | 7F875A381FA8B6D2008E5683 /* SecondViewModel.swift */, 229 | ); 230 | path = ViewModel; 231 | sourceTree = ""; 232 | }; 233 | 7F875A2C1FA8B69F008E5683 /* Model */ = { 234 | isa = PBXGroup; 235 | children = ( 236 | 7F875A361FA8B6C7008E5683 /* SecondModel.swift */, 237 | ); 238 | path = Model; 239 | sourceTree = ""; 240 | }; 241 | 7F875A2D1FA8B69F008E5683 /* View */ = { 242 | isa = PBXGroup; 243 | children = ( 244 | ); 245 | path = View; 246 | sourceTree = ""; 247 | }; 248 | 7F875A2E1FA8B69F008E5683 /* ViewController */ = { 249 | isa = PBXGroup; 250 | children = ( 251 | 7F875A341FA8B6B9008E5683 /* SecondViewController.swift */, 252 | ); 253 | path = ViewController; 254 | sourceTree = ""; 255 | }; 256 | 7F875A2F1FA8B69F008E5683 /* DemoOne */ = { 257 | isa = PBXGroup; 258 | children = ( 259 | 7F875A301FA8B69F008E5683 /* ViewModel */, 260 | 7F875A311FA8B69F008E5683 /* Model */, 261 | 7F875A321FA8B69F008E5683 /* View */, 262 | 7F875A331FA8B69F008E5683 /* ViewController */, 263 | ); 264 | path = DemoOne; 265 | sourceTree = ""; 266 | }; 267 | 7F875A301FA8B69F008E5683 /* ViewModel */ = { 268 | isa = PBXGroup; 269 | children = ( 270 | 7F875A3E1FA8B6F5008E5683 /* FirstViewModel.swift */, 271 | ); 272 | path = ViewModel; 273 | sourceTree = ""; 274 | }; 275 | 7F875A311FA8B69F008E5683 /* Model */ = { 276 | isa = PBXGroup; 277 | children = ( 278 | 7F875A3C1FA8B6EB008E5683 /* FirstModel.swift */, 279 | ); 280 | path = Model; 281 | sourceTree = ""; 282 | }; 283 | 7F875A321FA8B69F008E5683 /* View */ = { 284 | isa = PBXGroup; 285 | children = ( 286 | 7FF97E051FAC5B6D0088745D /* ZhihuTableViewCell.swift */, 287 | ); 288 | path = View; 289 | sourceTree = ""; 290 | }; 291 | 7F875A331FA8B69F008E5683 /* ViewController */ = { 292 | isa = PBXGroup; 293 | children = ( 294 | 7F875A3A1FA8B6E1008E5683 /* FirstViewController.swift */, 295 | ); 296 | path = ViewController; 297 | sourceTree = ""; 298 | }; 299 | 7F8A08771FA6CD9B0009750F /* View */ = { 300 | isa = PBXGroup; 301 | children = ( 302 | 7F8A08781FA6CDB90009750F /* View.swift */, 303 | 7FF97E021FAC125D0088745D /* ViewModelMapper.swift */, 304 | ); 305 | path = View; 306 | sourceTree = ""; 307 | }; 308 | 7F8A087A1FA6CE1A0009750F /* Model */ = { 309 | isa = PBXGroup; 310 | children = ( 311 | 7F146B1F1FAAF635003652D3 /* RxMoya */, 312 | 7F8A08831FA700E10009750F /* JsonModel */, 313 | 7F8A087F1FA6CF1E0009750F /* ModelProtocol.swift */, 314 | 7F09E6681FA814A800EDAA6D /* Model.swift */, 315 | 7F146B1B1FAAC636003652D3 /* API.swift */, 316 | ); 317 | path = Model; 318 | sourceTree = ""; 319 | }; 320 | 7F8A087B1FA6CE8F0009750F /* ViewModel */ = { 321 | isa = PBXGroup; 322 | children = ( 323 | 7F8A087D1FA6CF0D0009750F /* ViewModelProtocol.swift */, 324 | 7F8A08811FA6D0580009750F /* ViewModelService.swift */, 325 | 7F8A088A1FA731D60009750F /* Service.swift */, 326 | ); 327 | path = ViewModel; 328 | sourceTree = ""; 329 | }; 330 | 7F8A087C1FA6CEA60009750F /* MVVM */ = { 331 | isa = PBXGroup; 332 | children = ( 333 | 7F8A088F1FA771D00009750F /* Base */, 334 | 7F8A088C1FA7608E0009750F /* Router */, 335 | 7F8A08871FA71E310009750F /* Stack */, 336 | 7F8A08841FA706FF0009750F /* Log */, 337 | 7F8A087B1FA6CE8F0009750F /* ViewModel */, 338 | 7F8A087A1FA6CE1A0009750F /* Model */, 339 | 7F8A08771FA6CD9B0009750F /* View */, 340 | ); 341 | path = MVVM; 342 | sourceTree = ""; 343 | }; 344 | 7F8A08831FA700E10009750F /* JsonModel */ = { 345 | isa = PBXGroup; 346 | children = ( 347 | 7F5AD6C91FA08C450056066A /* Observable+HandyJSON.swift */, 348 | ); 349 | path = JsonModel; 350 | sourceTree = ""; 351 | }; 352 | 7F8A08841FA706FF0009750F /* Log */ = { 353 | isa = PBXGroup; 354 | children = ( 355 | 7F8A08851FA7070B0009750F /* Log.swift */, 356 | ); 357 | path = Log; 358 | sourceTree = ""; 359 | }; 360 | 7F8A08871FA71E310009750F /* Stack */ = { 361 | isa = PBXGroup; 362 | children = ( 363 | 7F8A08881FA71E9F0009750F /* Stack.swift */, 364 | ); 365 | path = Stack; 366 | sourceTree = ""; 367 | }; 368 | 7F8A088C1FA7608E0009750F /* Router */ = { 369 | isa = PBXGroup; 370 | children = ( 371 | 7F8A088D1FA7609F0009750F /* Router.swift */, 372 | ); 373 | path = Router; 374 | sourceTree = ""; 375 | }; 376 | 7F8A088F1FA771D00009750F /* Base */ = { 377 | isa = PBXGroup; 378 | children = ( 379 | 7F8A08901FA771DE0009750F /* BaseViewModel.swift */, 380 | 7F8A08921FA7724A0009750F /* BaseViewController.swift */, 381 | 7FC7B5021FA870780094B274 /* BaseTabBarViewController.swift */, 382 | 7FC7B50B1FA8785E0094B274 /* DataModel.swift */, 383 | ); 384 | path = Base; 385 | sourceTree = ""; 386 | }; 387 | 7FC7B5041FA8779F0094B274 /* Project */ = { 388 | isa = PBXGroup; 389 | children = ( 390 | 7FC7B5051FA877CB0094B274 /* Business */, 391 | ); 392 | path = Project; 393 | sourceTree = ""; 394 | }; 395 | 7FC7B5051FA877CB0094B274 /* Business */ = { 396 | isa = PBXGroup; 397 | children = ( 398 | 7F875A2F1FA8B69F008E5683 /* DemoOne */, 399 | 7F875A2A1FA8B69F008E5683 /* DemoTwo */, 400 | 7FC7B5061FA877E00094B274 /* Home */, 401 | ); 402 | path = Business; 403 | sourceTree = ""; 404 | }; 405 | 7FC7B5061FA877E00094B274 /* Home */ = { 406 | isa = PBXGroup; 407 | children = ( 408 | 7FC7B5081FA877F70094B274 /* Model */, 409 | 7FC7B50A1FA8780C0094B274 /* View */, 410 | 7FC7B5091FA878000094B274 /* ViewModel */, 411 | 7FC7B5071FA877EA0094B274 /* ViewController */, 412 | ); 413 | path = Home; 414 | sourceTree = ""; 415 | }; 416 | 7FC7B5071FA877EA0094B274 /* ViewController */ = { 417 | isa = PBXGroup; 418 | children = ( 419 | 7FC7B51B1FA87CD60094B274 /* HomeViewController.swift */, 420 | ); 421 | path = ViewController; 422 | sourceTree = ""; 423 | }; 424 | 7FC7B5081FA877F70094B274 /* Model */ = { 425 | isa = PBXGroup; 426 | children = ( 427 | ); 428 | path = Model; 429 | sourceTree = ""; 430 | }; 431 | 7FC7B5091FA878000094B274 /* ViewModel */ = { 432 | isa = PBXGroup; 433 | children = ( 434 | 7FC7B50E1FA878B00094B274 /* HomeViewModel.swift */, 435 | ); 436 | path = ViewModel; 437 | sourceTree = ""; 438 | }; 439 | 7FC7B50A1FA8780C0094B274 /* View */ = { 440 | isa = PBXGroup; 441 | children = ( 442 | ); 443 | path = View; 444 | sourceTree = ""; 445 | }; 446 | D5CD4E78BC05A92672A6EDAF /* Pods */ = { 447 | isa = PBXGroup; 448 | children = ( 449 | EC98160AF2A3FB09012F3C9A /* Pods-RxSwiftMVVM.debug.xcconfig */, 450 | 27A34DD4B9F2B804FFFE0786 /* Pods-RxSwiftMVVM.release.xcconfig */, 451 | CA650F7B2926313E5C3ED3BC /* Pods-RxSwiftMVVMTests.debug.xcconfig */, 452 | 255F084072E64017D216BE6A /* Pods-RxSwiftMVVMTests.release.xcconfig */, 453 | 3A0BF2A9DA9268A488E8576D /* Pods-RxSwiftMVVMUITests.debug.xcconfig */, 454 | 7EBE4623AED6A1A917A6C636 /* Pods-RxSwiftMVVMUITests.release.xcconfig */, 455 | ); 456 | name = Pods; 457 | sourceTree = ""; 458 | }; 459 | /* End PBXGroup section */ 460 | 461 | /* Begin PBXNativeTarget section */ 462 | 7F44FF7C1F80BA720053B8A6 /* RxSwiftMVVM */ = { 463 | isa = PBXNativeTarget; 464 | buildConfigurationList = 7F44FFA51F80BA720053B8A6 /* Build configuration list for PBXNativeTarget "RxSwiftMVVM" */; 465 | buildPhases = ( 466 | A01B8B7716EED1A6AB5D3F70 /* [CP] Check Pods Manifest.lock */, 467 | 7F44FF791F80BA720053B8A6 /* Sources */, 468 | 7F44FF7A1F80BA720053B8A6 /* Frameworks */, 469 | 7F44FF7B1F80BA720053B8A6 /* Resources */, 470 | 99DE77A2D46DD8C54508BAF4 /* [CP] Embed Pods Frameworks */, 471 | 1EBFB92FD08521CA23B4EBBF /* [CP] Copy Pods Resources */, 472 | ); 473 | buildRules = ( 474 | ); 475 | dependencies = ( 476 | ); 477 | name = RxSwiftMVVM; 478 | productName = RxSwiftMVVM; 479 | productReference = 7F44FF7D1F80BA720053B8A6 /* RxSwiftMVVM.app */; 480 | productType = "com.apple.product-type.application"; 481 | }; 482 | 7F44FF901F80BA720053B8A6 /* RxSwiftMVVMTests */ = { 483 | isa = PBXNativeTarget; 484 | buildConfigurationList = 7F44FFA81F80BA720053B8A6 /* Build configuration list for PBXNativeTarget "RxSwiftMVVMTests" */; 485 | buildPhases = ( 486 | 90B43E99D6D45B66A30C17B6 /* [CP] Check Pods Manifest.lock */, 487 | 7F44FF8D1F80BA720053B8A6 /* Sources */, 488 | 7F44FF8E1F80BA720053B8A6 /* Frameworks */, 489 | 7F44FF8F1F80BA720053B8A6 /* Resources */, 490 | 981C40C43522A5CC566E7232 /* [CP] Embed Pods Frameworks */, 491 | 1EF2583E5ED6FCEF596B14B1 /* [CP] Copy Pods Resources */, 492 | ); 493 | buildRules = ( 494 | ); 495 | dependencies = ( 496 | 7F44FF931F80BA720053B8A6 /* PBXTargetDependency */, 497 | ); 498 | name = RxSwiftMVVMTests; 499 | productName = RxSwiftMVVMTests; 500 | productReference = 7F44FF911F80BA720053B8A6 /* RxSwiftMVVMTests.xctest */; 501 | productType = "com.apple.product-type.bundle.unit-test"; 502 | }; 503 | 7F44FF9B1F80BA720053B8A6 /* RxSwiftMVVMUITests */ = { 504 | isa = PBXNativeTarget; 505 | buildConfigurationList = 7F44FFAB1F80BA720053B8A6 /* Build configuration list for PBXNativeTarget "RxSwiftMVVMUITests" */; 506 | buildPhases = ( 507 | E93E2566E18467EF09EA233F /* [CP] Check Pods Manifest.lock */, 508 | 7F44FF981F80BA720053B8A6 /* Sources */, 509 | 7F44FF991F80BA720053B8A6 /* Frameworks */, 510 | 7F44FF9A1F80BA720053B8A6 /* Resources */, 511 | 86E6AB18775F6B66564B38ED /* [CP] Embed Pods Frameworks */, 512 | 8AB476E7627CD3A82AD7AE6B /* [CP] Copy Pods Resources */, 513 | ); 514 | buildRules = ( 515 | ); 516 | dependencies = ( 517 | 7F44FF9E1F80BA720053B8A6 /* PBXTargetDependency */, 518 | ); 519 | name = RxSwiftMVVMUITests; 520 | productName = RxSwiftMVVMUITests; 521 | productReference = 7F44FF9C1F80BA720053B8A6 /* RxSwiftMVVMUITests.xctest */; 522 | productType = "com.apple.product-type.bundle.ui-testing"; 523 | }; 524 | /* End PBXNativeTarget section */ 525 | 526 | /* Begin PBXProject section */ 527 | 7F44FF751F80BA720053B8A6 /* Project object */ = { 528 | isa = PBXProject; 529 | attributes = { 530 | LastSwiftUpdateCheck = 0900; 531 | LastUpgradeCheck = 0900; 532 | ORGANIZATIONNAME = JianweiWang; 533 | TargetAttributes = { 534 | 7F44FF7C1F80BA720053B8A6 = { 535 | CreatedOnToolsVersion = 9.0; 536 | ProvisioningStyle = Automatic; 537 | }; 538 | 7F44FF901F80BA720053B8A6 = { 539 | CreatedOnToolsVersion = 9.0; 540 | ProvisioningStyle = Automatic; 541 | TestTargetID = 7F44FF7C1F80BA720053B8A6; 542 | }; 543 | 7F44FF9B1F80BA720053B8A6 = { 544 | CreatedOnToolsVersion = 9.0; 545 | ProvisioningStyle = Automatic; 546 | TestTargetID = 7F44FF7C1F80BA720053B8A6; 547 | }; 548 | }; 549 | }; 550 | buildConfigurationList = 7F44FF781F80BA720053B8A6 /* Build configuration list for PBXProject "RxSwiftMVVM" */; 551 | compatibilityVersion = "Xcode 8.0"; 552 | developmentRegion = en; 553 | hasScannedForEncodings = 0; 554 | knownRegions = ( 555 | en, 556 | Base, 557 | ); 558 | mainGroup = 7F44FF741F80BA720053B8A6; 559 | productRefGroup = 7F44FF7E1F80BA720053B8A6 /* Products */; 560 | projectDirPath = ""; 561 | projectRoot = ""; 562 | targets = ( 563 | 7F44FF7C1F80BA720053B8A6 /* RxSwiftMVVM */, 564 | 7F44FF901F80BA720053B8A6 /* RxSwiftMVVMTests */, 565 | 7F44FF9B1F80BA720053B8A6 /* RxSwiftMVVMUITests */, 566 | ); 567 | }; 568 | /* End PBXProject section */ 569 | 570 | /* Begin PBXResourcesBuildPhase section */ 571 | 7F44FF7B1F80BA720053B8A6 /* Resources */ = { 572 | isa = PBXResourcesBuildPhase; 573 | buildActionMask = 2147483647; 574 | files = ( 575 | 7F44FF8B1F80BA720053B8A6 /* LaunchScreen.storyboard in Resources */, 576 | 7F44FF881F80BA720053B8A6 /* Assets.xcassets in Resources */, 577 | 7F44FF861F80BA720053B8A6 /* Main.storyboard in Resources */, 578 | ); 579 | runOnlyForDeploymentPostprocessing = 0; 580 | }; 581 | 7F44FF8F1F80BA720053B8A6 /* Resources */ = { 582 | isa = PBXResourcesBuildPhase; 583 | buildActionMask = 2147483647; 584 | files = ( 585 | ); 586 | runOnlyForDeploymentPostprocessing = 0; 587 | }; 588 | 7F44FF9A1F80BA720053B8A6 /* Resources */ = { 589 | isa = PBXResourcesBuildPhase; 590 | buildActionMask = 2147483647; 591 | files = ( 592 | ); 593 | runOnlyForDeploymentPostprocessing = 0; 594 | }; 595 | /* End PBXResourcesBuildPhase section */ 596 | 597 | /* Begin PBXShellScriptBuildPhase section */ 598 | 1EBFB92FD08521CA23B4EBBF /* [CP] Copy Pods Resources */ = { 599 | isa = PBXShellScriptBuildPhase; 600 | buildActionMask = 2147483647; 601 | files = ( 602 | ); 603 | inputPaths = ( 604 | ); 605 | name = "[CP] Copy Pods Resources"; 606 | outputPaths = ( 607 | ); 608 | runOnlyForDeploymentPostprocessing = 0; 609 | shellPath = /bin/sh; 610 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-RxSwiftMVVM/Pods-RxSwiftMVVM-resources.sh\"\n"; 611 | showEnvVarsInLog = 0; 612 | }; 613 | 1EF2583E5ED6FCEF596B14B1 /* [CP] Copy Pods Resources */ = { 614 | isa = PBXShellScriptBuildPhase; 615 | buildActionMask = 2147483647; 616 | files = ( 617 | ); 618 | inputPaths = ( 619 | ); 620 | name = "[CP] Copy Pods Resources"; 621 | outputPaths = ( 622 | ); 623 | runOnlyForDeploymentPostprocessing = 0; 624 | shellPath = /bin/sh; 625 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-RxSwiftMVVMTests/Pods-RxSwiftMVVMTests-resources.sh\"\n"; 626 | showEnvVarsInLog = 0; 627 | }; 628 | 86E6AB18775F6B66564B38ED /* [CP] Embed Pods Frameworks */ = { 629 | isa = PBXShellScriptBuildPhase; 630 | buildActionMask = 2147483647; 631 | files = ( 632 | ); 633 | inputPaths = ( 634 | ); 635 | name = "[CP] Embed Pods Frameworks"; 636 | outputPaths = ( 637 | ); 638 | runOnlyForDeploymentPostprocessing = 0; 639 | shellPath = /bin/sh; 640 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-RxSwiftMVVMUITests/Pods-RxSwiftMVVMUITests-frameworks.sh\"\n"; 641 | showEnvVarsInLog = 0; 642 | }; 643 | 8AB476E7627CD3A82AD7AE6B /* [CP] Copy Pods Resources */ = { 644 | isa = PBXShellScriptBuildPhase; 645 | buildActionMask = 2147483647; 646 | files = ( 647 | ); 648 | inputPaths = ( 649 | ); 650 | name = "[CP] Copy Pods Resources"; 651 | outputPaths = ( 652 | ); 653 | runOnlyForDeploymentPostprocessing = 0; 654 | shellPath = /bin/sh; 655 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-RxSwiftMVVMUITests/Pods-RxSwiftMVVMUITests-resources.sh\"\n"; 656 | showEnvVarsInLog = 0; 657 | }; 658 | 90B43E99D6D45B66A30C17B6 /* [CP] Check Pods Manifest.lock */ = { 659 | isa = PBXShellScriptBuildPhase; 660 | buildActionMask = 2147483647; 661 | files = ( 662 | ); 663 | inputPaths = ( 664 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 665 | "${PODS_ROOT}/Manifest.lock", 666 | ); 667 | name = "[CP] Check Pods Manifest.lock"; 668 | outputPaths = ( 669 | "$(DERIVED_FILE_DIR)/Pods-RxSwiftMVVMTests-checkManifestLockResult.txt", 670 | ); 671 | runOnlyForDeploymentPostprocessing = 0; 672 | shellPath = /bin/sh; 673 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 674 | showEnvVarsInLog = 0; 675 | }; 676 | 981C40C43522A5CC566E7232 /* [CP] Embed Pods Frameworks */ = { 677 | isa = PBXShellScriptBuildPhase; 678 | buildActionMask = 2147483647; 679 | files = ( 680 | ); 681 | inputPaths = ( 682 | ); 683 | name = "[CP] Embed Pods Frameworks"; 684 | outputPaths = ( 685 | ); 686 | runOnlyForDeploymentPostprocessing = 0; 687 | shellPath = /bin/sh; 688 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-RxSwiftMVVMTests/Pods-RxSwiftMVVMTests-frameworks.sh\"\n"; 689 | showEnvVarsInLog = 0; 690 | }; 691 | 99DE77A2D46DD8C54508BAF4 /* [CP] Embed Pods Frameworks */ = { 692 | isa = PBXShellScriptBuildPhase; 693 | buildActionMask = 2147483647; 694 | files = ( 695 | ); 696 | inputPaths = ( 697 | "${SRCROOT}/Pods/Target Support Files/Pods-RxSwiftMVVM/Pods-RxSwiftMVVM-frameworks.sh", 698 | "${BUILT_PRODUCTS_DIR}/Action/Action.framework", 699 | "${BUILT_PRODUCTS_DIR}/Alamofire/Alamofire.framework", 700 | "${BUILT_PRODUCTS_DIR}/Differentiator/Differentiator.framework", 701 | "${BUILT_PRODUCTS_DIR}/HandyJSON/HandyJSON.framework", 702 | "${BUILT_PRODUCTS_DIR}/Kingfisher/Kingfisher.framework", 703 | "${BUILT_PRODUCTS_DIR}/Moya/Moya.framework", 704 | "${BUILT_PRODUCTS_DIR}/NSObject+Rx/NSObject_Rx.framework", 705 | "${BUILT_PRODUCTS_DIR}/Result/Result.framework", 706 | "${BUILT_PRODUCTS_DIR}/RxCocoa/RxCocoa.framework", 707 | "${BUILT_PRODUCTS_DIR}/RxDataSources/RxDataSources.framework", 708 | "${BUILT_PRODUCTS_DIR}/RxSwift/RxSwift.framework", 709 | "${BUILT_PRODUCTS_DIR}/RxSwiftExt/RxSwiftExt.framework", 710 | ); 711 | name = "[CP] Embed Pods Frameworks"; 712 | outputPaths = ( 713 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Action.framework", 714 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Alamofire.framework", 715 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Differentiator.framework", 716 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/HandyJSON.framework", 717 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Kingfisher.framework", 718 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Moya.framework", 719 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/NSObject_Rx.framework", 720 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Result.framework", 721 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxCocoa.framework", 722 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxDataSources.framework", 723 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxSwift.framework", 724 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxSwiftExt.framework", 725 | ); 726 | runOnlyForDeploymentPostprocessing = 0; 727 | shellPath = /bin/sh; 728 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-RxSwiftMVVM/Pods-RxSwiftMVVM-frameworks.sh\"\n"; 729 | showEnvVarsInLog = 0; 730 | }; 731 | A01B8B7716EED1A6AB5D3F70 /* [CP] Check Pods Manifest.lock */ = { 732 | isa = PBXShellScriptBuildPhase; 733 | buildActionMask = 2147483647; 734 | files = ( 735 | ); 736 | inputPaths = ( 737 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 738 | "${PODS_ROOT}/Manifest.lock", 739 | ); 740 | name = "[CP] Check Pods Manifest.lock"; 741 | outputPaths = ( 742 | "$(DERIVED_FILE_DIR)/Pods-RxSwiftMVVM-checkManifestLockResult.txt", 743 | ); 744 | runOnlyForDeploymentPostprocessing = 0; 745 | shellPath = /bin/sh; 746 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 747 | showEnvVarsInLog = 0; 748 | }; 749 | E93E2566E18467EF09EA233F /* [CP] Check Pods Manifest.lock */ = { 750 | isa = PBXShellScriptBuildPhase; 751 | buildActionMask = 2147483647; 752 | files = ( 753 | ); 754 | inputPaths = ( 755 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 756 | "${PODS_ROOT}/Manifest.lock", 757 | ); 758 | name = "[CP] Check Pods Manifest.lock"; 759 | outputPaths = ( 760 | "$(DERIVED_FILE_DIR)/Pods-RxSwiftMVVMUITests-checkManifestLockResult.txt", 761 | ); 762 | runOnlyForDeploymentPostprocessing = 0; 763 | shellPath = /bin/sh; 764 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 765 | showEnvVarsInLog = 0; 766 | }; 767 | /* End PBXShellScriptBuildPhase section */ 768 | 769 | /* Begin PBXSourcesBuildPhase section */ 770 | 7F44FF791F80BA720053B8A6 /* Sources */ = { 771 | isa = PBXSourcesBuildPhase; 772 | buildActionMask = 2147483647; 773 | files = ( 774 | 7FC7B50F1FA878B00094B274 /* HomeViewModel.swift in Sources */, 775 | 7F875A371FA8B6C7008E5683 /* SecondModel.swift in Sources */, 776 | 7F8A088E1FA7609F0009750F /* Router.swift in Sources */, 777 | 7F8A08911FA771DE0009750F /* BaseViewModel.swift in Sources */, 778 | 7F875A351FA8B6B9008E5683 /* SecondViewController.swift in Sources */, 779 | 7F5AD6CA1FA08C450056066A /* Observable+HandyJSON.swift in Sources */, 780 | 7F875A391FA8B6D2008E5683 /* SecondViewModel.swift in Sources */, 781 | 7FC7B51C1FA87CD60094B274 /* HomeViewController.swift in Sources */, 782 | 7F44FF811F80BA720053B8A6 /* AppDelegate.swift in Sources */, 783 | 7FC7B50C1FA8785E0094B274 /* DataModel.swift in Sources */, 784 | 7F8A08891FA71E9F0009750F /* Stack.swift in Sources */, 785 | 7FF97E031FAC125D0088745D /* ViewModelMapper.swift in Sources */, 786 | 7F8A08791FA6CDB90009750F /* View.swift in Sources */, 787 | 7F09E6691FA814A800EDAA6D /* Model.swift in Sources */, 788 | 7F146B1E1FAAF632003652D3 /* MoyaProvider+Rx.swift in Sources */, 789 | 7F8A087E1FA6CF0D0009750F /* ViewModelProtocol.swift in Sources */, 790 | 7F8A08931FA7724A0009750F /* BaseViewController.swift in Sources */, 791 | 7F8A08821FA6D0580009750F /* ViewModelService.swift in Sources */, 792 | 7F8A088B1FA731D60009750F /* Service.swift in Sources */, 793 | 7FF97E061FAC5B6D0088745D /* ZhihuTableViewCell.swift in Sources */, 794 | 7F8A08861FA7070B0009750F /* Log.swift in Sources */, 795 | 7F875A3F1FA8B6F5008E5683 /* FirstViewModel.swift in Sources */, 796 | 7FC7B5031FA870780094B274 /* BaseTabBarViewController.swift in Sources */, 797 | 7F875A3D1FA8B6EB008E5683 /* FirstModel.swift in Sources */, 798 | 7F8A08801FA6CF1E0009750F /* ModelProtocol.swift in Sources */, 799 | 7F146B1C1FAAC636003652D3 /* API.swift in Sources */, 800 | 7F875A3B1FA8B6E1008E5683 /* FirstViewController.swift in Sources */, 801 | ); 802 | runOnlyForDeploymentPostprocessing = 0; 803 | }; 804 | 7F44FF8D1F80BA720053B8A6 /* Sources */ = { 805 | isa = PBXSourcesBuildPhase; 806 | buildActionMask = 2147483647; 807 | files = ( 808 | 7F44FF961F80BA720053B8A6 /* RxSwiftMVVMTests.swift in Sources */, 809 | ); 810 | runOnlyForDeploymentPostprocessing = 0; 811 | }; 812 | 7F44FF981F80BA720053B8A6 /* Sources */ = { 813 | isa = PBXSourcesBuildPhase; 814 | buildActionMask = 2147483647; 815 | files = ( 816 | 7F44FFA11F80BA720053B8A6 /* RxSwiftMVVMUITests.swift in Sources */, 817 | ); 818 | runOnlyForDeploymentPostprocessing = 0; 819 | }; 820 | /* End PBXSourcesBuildPhase section */ 821 | 822 | /* Begin PBXTargetDependency section */ 823 | 7F44FF931F80BA720053B8A6 /* PBXTargetDependency */ = { 824 | isa = PBXTargetDependency; 825 | target = 7F44FF7C1F80BA720053B8A6 /* RxSwiftMVVM */; 826 | targetProxy = 7F44FF921F80BA720053B8A6 /* PBXContainerItemProxy */; 827 | }; 828 | 7F44FF9E1F80BA720053B8A6 /* PBXTargetDependency */ = { 829 | isa = PBXTargetDependency; 830 | target = 7F44FF7C1F80BA720053B8A6 /* RxSwiftMVVM */; 831 | targetProxy = 7F44FF9D1F80BA720053B8A6 /* PBXContainerItemProxy */; 832 | }; 833 | /* End PBXTargetDependency section */ 834 | 835 | /* Begin PBXVariantGroup section */ 836 | 7F44FF841F80BA720053B8A6 /* Main.storyboard */ = { 837 | isa = PBXVariantGroup; 838 | children = ( 839 | 7F44FF851F80BA720053B8A6 /* Base */, 840 | ); 841 | name = Main.storyboard; 842 | sourceTree = ""; 843 | }; 844 | 7F44FF891F80BA720053B8A6 /* LaunchScreen.storyboard */ = { 845 | isa = PBXVariantGroup; 846 | children = ( 847 | 7F44FF8A1F80BA720053B8A6 /* Base */, 848 | ); 849 | name = LaunchScreen.storyboard; 850 | sourceTree = ""; 851 | }; 852 | /* End PBXVariantGroup section */ 853 | 854 | /* Begin XCBuildConfiguration section */ 855 | 7F44FFA31F80BA720053B8A6 /* Debug */ = { 856 | isa = XCBuildConfiguration; 857 | buildSettings = { 858 | ALWAYS_SEARCH_USER_PATHS = NO; 859 | CLANG_ANALYZER_NONNULL = YES; 860 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 861 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 862 | CLANG_CXX_LIBRARY = "libc++"; 863 | CLANG_ENABLE_MODULES = YES; 864 | CLANG_ENABLE_OBJC_ARC = YES; 865 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 866 | CLANG_WARN_BOOL_CONVERSION = YES; 867 | CLANG_WARN_COMMA = YES; 868 | CLANG_WARN_CONSTANT_CONVERSION = YES; 869 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 870 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 871 | CLANG_WARN_EMPTY_BODY = YES; 872 | CLANG_WARN_ENUM_CONVERSION = YES; 873 | CLANG_WARN_INFINITE_RECURSION = YES; 874 | CLANG_WARN_INT_CONVERSION = YES; 875 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 876 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 877 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 878 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 879 | CLANG_WARN_STRICT_PROTOTYPES = YES; 880 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 881 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 882 | CLANG_WARN_UNREACHABLE_CODE = YES; 883 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 884 | CODE_SIGN_IDENTITY = "iPhone Developer"; 885 | COPY_PHASE_STRIP = NO; 886 | DEBUG_INFORMATION_FORMAT = dwarf; 887 | ENABLE_STRICT_OBJC_MSGSEND = YES; 888 | ENABLE_TESTABILITY = YES; 889 | GCC_C_LANGUAGE_STANDARD = gnu11; 890 | GCC_DYNAMIC_NO_PIC = NO; 891 | GCC_NO_COMMON_BLOCKS = YES; 892 | GCC_OPTIMIZATION_LEVEL = 0; 893 | GCC_PREPROCESSOR_DEFINITIONS = ( 894 | "DEBUG=1", 895 | "$(inherited)", 896 | ); 897 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 898 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 899 | GCC_WARN_UNDECLARED_SELECTOR = YES; 900 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 901 | GCC_WARN_UNUSED_FUNCTION = YES; 902 | GCC_WARN_UNUSED_VARIABLE = YES; 903 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 904 | MTL_ENABLE_DEBUG_INFO = YES; 905 | ONLY_ACTIVE_ARCH = YES; 906 | SDKROOT = iphoneos; 907 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 908 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 909 | }; 910 | name = Debug; 911 | }; 912 | 7F44FFA41F80BA720053B8A6 /* Release */ = { 913 | isa = XCBuildConfiguration; 914 | buildSettings = { 915 | ALWAYS_SEARCH_USER_PATHS = NO; 916 | CLANG_ANALYZER_NONNULL = YES; 917 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 918 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 919 | CLANG_CXX_LIBRARY = "libc++"; 920 | CLANG_ENABLE_MODULES = YES; 921 | CLANG_ENABLE_OBJC_ARC = YES; 922 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 923 | CLANG_WARN_BOOL_CONVERSION = YES; 924 | CLANG_WARN_COMMA = YES; 925 | CLANG_WARN_CONSTANT_CONVERSION = YES; 926 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 927 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 928 | CLANG_WARN_EMPTY_BODY = YES; 929 | CLANG_WARN_ENUM_CONVERSION = YES; 930 | CLANG_WARN_INFINITE_RECURSION = YES; 931 | CLANG_WARN_INT_CONVERSION = YES; 932 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 933 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 934 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 935 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 936 | CLANG_WARN_STRICT_PROTOTYPES = YES; 937 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 938 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 939 | CLANG_WARN_UNREACHABLE_CODE = YES; 940 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 941 | CODE_SIGN_IDENTITY = "iPhone Developer"; 942 | COPY_PHASE_STRIP = NO; 943 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 944 | ENABLE_NS_ASSERTIONS = NO; 945 | ENABLE_STRICT_OBJC_MSGSEND = YES; 946 | GCC_C_LANGUAGE_STANDARD = gnu11; 947 | GCC_NO_COMMON_BLOCKS = YES; 948 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 949 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 950 | GCC_WARN_UNDECLARED_SELECTOR = YES; 951 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 952 | GCC_WARN_UNUSED_FUNCTION = YES; 953 | GCC_WARN_UNUSED_VARIABLE = YES; 954 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 955 | MTL_ENABLE_DEBUG_INFO = NO; 956 | SDKROOT = iphoneos; 957 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 958 | VALIDATE_PRODUCT = YES; 959 | }; 960 | name = Release; 961 | }; 962 | 7F44FFA61F80BA720053B8A6 /* Debug */ = { 963 | isa = XCBuildConfiguration; 964 | baseConfigurationReference = EC98160AF2A3FB09012F3C9A /* Pods-RxSwiftMVVM.debug.xcconfig */; 965 | buildSettings = { 966 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 967 | CODE_SIGN_STYLE = Automatic; 968 | DEVELOPMENT_TEAM = WH57G3K232; 969 | INFOPLIST_FILE = RxSwiftMVVM/Info.plist; 970 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 971 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 972 | OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-D\" \"STORYBOARD\""; 973 | PRODUCT_BUNDLE_IDENTIFIER = JianweiWang.RxSwiftMVVM; 974 | PRODUCT_NAME = "$(TARGET_NAME)"; 975 | SWIFT_VERSION = 4.0; 976 | TARGETED_DEVICE_FAMILY = "1,2"; 977 | }; 978 | name = Debug; 979 | }; 980 | 7F44FFA71F80BA720053B8A6 /* Release */ = { 981 | isa = XCBuildConfiguration; 982 | baseConfigurationReference = 27A34DD4B9F2B804FFFE0786 /* Pods-RxSwiftMVVM.release.xcconfig */; 983 | buildSettings = { 984 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 985 | CODE_SIGN_STYLE = Automatic; 986 | DEVELOPMENT_TEAM = WH57G3K232; 987 | INFOPLIST_FILE = RxSwiftMVVM/Info.plist; 988 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 989 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 990 | OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-D\" \"STORYBOARD\""; 991 | PRODUCT_BUNDLE_IDENTIFIER = JianweiWang.RxSwiftMVVM; 992 | PRODUCT_NAME = "$(TARGET_NAME)"; 993 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = ""; 994 | SWIFT_VERSION = 4.0; 995 | TARGETED_DEVICE_FAMILY = "1,2"; 996 | }; 997 | name = Release; 998 | }; 999 | 7F44FFA91F80BA720053B8A6 /* Debug */ = { 1000 | isa = XCBuildConfiguration; 1001 | baseConfigurationReference = CA650F7B2926313E5C3ED3BC /* Pods-RxSwiftMVVMTests.debug.xcconfig */; 1002 | buildSettings = { 1003 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 1004 | BUNDLE_LOADER = "$(TEST_HOST)"; 1005 | CODE_SIGN_STYLE = Automatic; 1006 | DEVELOPMENT_TEAM = XS6LB4248G; 1007 | INFOPLIST_FILE = RxSwiftMVVMTests/Info.plist; 1008 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 1009 | PRODUCT_BUNDLE_IDENTIFIER = JianweiWang.RxSwiftMVVMTests; 1010 | PRODUCT_NAME = "$(TARGET_NAME)"; 1011 | SWIFT_VERSION = 4.0; 1012 | TARGETED_DEVICE_FAMILY = "1,2"; 1013 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/RxSwiftMVVM.app/RxSwiftMVVM"; 1014 | }; 1015 | name = Debug; 1016 | }; 1017 | 7F44FFAA1F80BA720053B8A6 /* Release */ = { 1018 | isa = XCBuildConfiguration; 1019 | baseConfigurationReference = 255F084072E64017D216BE6A /* Pods-RxSwiftMVVMTests.release.xcconfig */; 1020 | buildSettings = { 1021 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 1022 | BUNDLE_LOADER = "$(TEST_HOST)"; 1023 | CODE_SIGN_STYLE = Automatic; 1024 | DEVELOPMENT_TEAM = XS6LB4248G; 1025 | INFOPLIST_FILE = RxSwiftMVVMTests/Info.plist; 1026 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 1027 | PRODUCT_BUNDLE_IDENTIFIER = JianweiWang.RxSwiftMVVMTests; 1028 | PRODUCT_NAME = "$(TARGET_NAME)"; 1029 | SWIFT_VERSION = 4.0; 1030 | TARGETED_DEVICE_FAMILY = "1,2"; 1031 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/RxSwiftMVVM.app/RxSwiftMVVM"; 1032 | }; 1033 | name = Release; 1034 | }; 1035 | 7F44FFAC1F80BA720053B8A6 /* Debug */ = { 1036 | isa = XCBuildConfiguration; 1037 | baseConfigurationReference = 3A0BF2A9DA9268A488E8576D /* Pods-RxSwiftMVVMUITests.debug.xcconfig */; 1038 | buildSettings = { 1039 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 1040 | CODE_SIGN_STYLE = Automatic; 1041 | DEVELOPMENT_TEAM = XS6LB4248G; 1042 | INFOPLIST_FILE = RxSwiftMVVMUITests/Info.plist; 1043 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 1044 | PRODUCT_BUNDLE_IDENTIFIER = JianweiWang.RxSwiftMVVMUITests; 1045 | PRODUCT_NAME = "$(TARGET_NAME)"; 1046 | SWIFT_VERSION = 4.0; 1047 | TARGETED_DEVICE_FAMILY = "1,2"; 1048 | TEST_TARGET_NAME = RxSwiftMVVM; 1049 | }; 1050 | name = Debug; 1051 | }; 1052 | 7F44FFAD1F80BA720053B8A6 /* Release */ = { 1053 | isa = XCBuildConfiguration; 1054 | baseConfigurationReference = 7EBE4623AED6A1A917A6C636 /* Pods-RxSwiftMVVMUITests.release.xcconfig */; 1055 | buildSettings = { 1056 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 1057 | CODE_SIGN_STYLE = Automatic; 1058 | DEVELOPMENT_TEAM = XS6LB4248G; 1059 | INFOPLIST_FILE = RxSwiftMVVMUITests/Info.plist; 1060 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 1061 | PRODUCT_BUNDLE_IDENTIFIER = JianweiWang.RxSwiftMVVMUITests; 1062 | PRODUCT_NAME = "$(TARGET_NAME)"; 1063 | SWIFT_VERSION = 4.0; 1064 | TARGETED_DEVICE_FAMILY = "1,2"; 1065 | TEST_TARGET_NAME = RxSwiftMVVM; 1066 | }; 1067 | name = Release; 1068 | }; 1069 | /* End XCBuildConfiguration section */ 1070 | 1071 | /* Begin XCConfigurationList section */ 1072 | 7F44FF781F80BA720053B8A6 /* Build configuration list for PBXProject "RxSwiftMVVM" */ = { 1073 | isa = XCConfigurationList; 1074 | buildConfigurations = ( 1075 | 7F44FFA31F80BA720053B8A6 /* Debug */, 1076 | 7F44FFA41F80BA720053B8A6 /* Release */, 1077 | ); 1078 | defaultConfigurationIsVisible = 0; 1079 | defaultConfigurationName = Release; 1080 | }; 1081 | 7F44FFA51F80BA720053B8A6 /* Build configuration list for PBXNativeTarget "RxSwiftMVVM" */ = { 1082 | isa = XCConfigurationList; 1083 | buildConfigurations = ( 1084 | 7F44FFA61F80BA720053B8A6 /* Debug */, 1085 | 7F44FFA71F80BA720053B8A6 /* Release */, 1086 | ); 1087 | defaultConfigurationIsVisible = 0; 1088 | defaultConfigurationName = Release; 1089 | }; 1090 | 7F44FFA81F80BA720053B8A6 /* Build configuration list for PBXNativeTarget "RxSwiftMVVMTests" */ = { 1091 | isa = XCConfigurationList; 1092 | buildConfigurations = ( 1093 | 7F44FFA91F80BA720053B8A6 /* Debug */, 1094 | 7F44FFAA1F80BA720053B8A6 /* Release */, 1095 | ); 1096 | defaultConfigurationIsVisible = 0; 1097 | defaultConfigurationName = Release; 1098 | }; 1099 | 7F44FFAB1F80BA720053B8A6 /* Build configuration list for PBXNativeTarget "RxSwiftMVVMUITests" */ = { 1100 | isa = XCConfigurationList; 1101 | buildConfigurations = ( 1102 | 7F44FFAC1F80BA720053B8A6 /* Debug */, 1103 | 7F44FFAD1F80BA720053B8A6 /* Release */, 1104 | ); 1105 | defaultConfigurationIsVisible = 0; 1106 | defaultConfigurationName = Release; 1107 | }; 1108 | /* End XCConfigurationList section */ 1109 | }; 1110 | rootObject = 7F44FF751F80BA720053B8A6 /* Project object */; 1111 | } 1112 | -------------------------------------------------------------------------------- /RxSwiftMVVM.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /RxSwiftMVVM.xcodeproj/project.xcworkspace/xcuserdata/wangjianwei.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JianweiWangs/RxSwiftMVVM/218c1af907a2c7e5e43a36aaa09b64e9024df3c5/RxSwiftMVVM.xcodeproj/project.xcworkspace/xcuserdata/wangjianwei.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /RxSwiftMVVM.xcodeproj/xcuserdata/wangjianwei.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | RxSwiftMVVM.xcscheme 8 | 9 | orderHint 10 | 15 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /RxSwiftMVVM/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // RxSwiftMVVM 4 | // 5 | // Created by 王健伟 on 2017/10/1. 6 | // Copyright © 2017年 JianweiWang. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | window = UIWindow(frame: UIScreen.main.bounds) 20 | window?.backgroundColor = UIColor.white 21 | NavigationControllerStack.initialize() 22 | Service.instance.resetRootViewModel(HomeViewModel()) 23 | 24 | return true 25 | } 26 | 27 | func applicationWillResignActive(_ application: UIApplication) { 28 | // 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. 29 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 30 | } 31 | 32 | func applicationDidEnterBackground(_ application: UIApplication) { 33 | // 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. 34 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 35 | } 36 | 37 | func applicationWillEnterForeground(_ application: UIApplication) { 38 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 39 | } 40 | 41 | func applicationDidBecomeActive(_ application: UIApplication) { 42 | // 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. 43 | } 44 | 45 | func applicationWillTerminate(_ application: UIApplication) { 46 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 47 | } 48 | 49 | 50 | } 51 | 52 | -------------------------------------------------------------------------------- /RxSwiftMVVM/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /RxSwiftMVVM/Base.lproj/LaunchScreen.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 | -------------------------------------------------------------------------------- /RxSwiftMVVM/Base.lproj/Main.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 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | -------------------------------------------------------------------------------- /RxSwiftMVVM/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSAppTransportSecurity 6 | 7 | NSAllowsArbitraryLoads 8 | 9 | 10 | CFBundleDevelopmentRegion 11 | $(DEVELOPMENT_LANGUAGE) 12 | CFBundleExecutable 13 | $(EXECUTABLE_NAME) 14 | CFBundleIdentifier 15 | $(PRODUCT_BUNDLE_IDENTIFIER) 16 | CFBundleInfoDictionaryVersion 17 | 6.0 18 | CFBundleName 19 | $(PRODUCT_NAME) 20 | CFBundlePackageType 21 | APPL 22 | CFBundleShortVersionString 23 | 1.0 24 | CFBundleVersion 25 | 1 26 | LSRequiresIPhoneOS 27 | 28 | UILaunchStoryboardName 29 | LaunchScreen 30 | UIMainStoryboardFile 31 | Main 32 | UIRequiredDeviceCapabilities 33 | 34 | armv7 35 | 36 | UISupportedInterfaceOrientations 37 | 38 | UIInterfaceOrientationPortrait 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UISupportedInterfaceOrientations~ipad 43 | 44 | UIInterfaceOrientationPortrait 45 | UIInterfaceOrientationPortraitUpsideDown 46 | UIInterfaceOrientationLandscapeLeft 47 | UIInterfaceOrientationLandscapeRight 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /RxSwiftMVVM/MVVM/Base/BaseTabBarViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TabBarViewController.swift 3 | // RxSwiftMVVM 4 | // 5 | // Created by 王健伟 on 2017/10/31. 6 | // Copyright © 2017年 JianweiWang. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class BaseTabBarViewController: BaseViewController { 12 | 13 | let vmTabBarController: UITabBarController = UITabBarController() 14 | 15 | override func viewDidLoad() { 16 | super.viewDidLoad() 17 | vmTabBarController.view.frame = view.bounds 18 | addChildViewController(vmTabBarController) 19 | view.addSubview(vmTabBarController.view) 20 | // Do any additional setup after loading the view. 21 | } 22 | 23 | override func didReceiveMemoryWarning() { 24 | super.didReceiveMemoryWarning() 25 | // Dispose of any resources that can be recreated. 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /RxSwiftMVVM/MVVM/Base/BaseViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // RxSwiftMVVM 4 | // 5 | // Created by 王健伟 on 2017/10/30. 6 | // Copyright © 2017年 JianweiWang. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | // There is not Generic modify at instance of StoryBoard, so ViewController havn't Generic 11 | // Consider use associatedtype instead in future, then remove Router Module, Remove ObjC Runtime and Reflecte, turn Swift back Static 12 | class BaseViewController: UIViewController, ViewProtocol, ViewModelCast { 13 | 14 | typealias ViewModel = BaseViewModel 15 | 16 | var _viewModel: ViewModel? 17 | 18 | var viewModel: ViewModel? { 19 | get { 20 | return self._viewModel 21 | } 22 | set { 23 | assert(self.viewModel == nil, "only call once in Router With installViewModel, reset viewModel is NOT ALLLOWED, the viewModel MUST to be READONLY") 24 | self._viewModel = newValue 25 | } 26 | } 27 | 28 | 29 | 30 | func bindViewModel() { 31 | 32 | } 33 | 34 | func installViewModel(_ viewModel: ViewModelProtocol) { 35 | self.viewModel = (viewModel as! BaseViewModel) 36 | } 37 | 38 | override func viewDidLoad() { 39 | super.viewDidLoad() 40 | self.bindViewModel() 41 | } 42 | } 43 | 44 | 45 | -------------------------------------------------------------------------------- /RxSwiftMVVM/MVVM/Base/BaseViewModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // File.swift 3 | // RxSwiftMVVM 4 | // 5 | // Created by 王健伟 on 2017/10/30. 6 | // Copyright © 2017年 JianweiWang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import NSObject_Rx 11 | import Moya 12 | class BaseViewModel { 13 | 14 | let model: Model 15 | var params: [Any?] = [] 16 | private let _storyBoard: StoryBoard 17 | private let _service: ViewModelService 18 | 19 | var storyBoard: StoryBoard { 20 | return self._storyBoard 21 | } 22 | 23 | init(_ storyBoard: StoryBoard) { 24 | _storyBoard = storyBoard 25 | _service = Service.instance 26 | model = _service.model 27 | self.initialize() 28 | } 29 | 30 | func initialize() { 31 | 32 | } 33 | func param(_ param: Any) -> BaseViewModel { 34 | self.params.append(param) 35 | return self 36 | } 37 | } 38 | 39 | extension BaseViewModel: ViewModelProtocol { 40 | var service: ViewModelService { 41 | return _service 42 | } 43 | func push(_ animated: Bool = true) { 44 | self.service.pushViewModel(self, animated) 45 | } 46 | func pop(_ animated: Bool = true) { 47 | self.service.popViewModel(animated) 48 | } 49 | func present(_ animated: Bool = true, _ completion: (() -> Void)? = nil) { 50 | self.service.presentViewModel(self, animated, completion) 51 | } 52 | func dismiss(_ animated: Bool = true, _ completion: (() -> Void)? = nil) { 53 | self.service.dismissViewModel(animated, completion) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /RxSwiftMVVM/MVVM/Base/DataModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DataModel.swift 3 | // RxSwiftMVVM 4 | // 5 | // Created by 王健伟 on 2017/10/31. 6 | // Copyright © 2017年 JianweiWang. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import HandyJSON 11 | class DataModel : HandyJSON { 12 | var code: String? 13 | var message: String? 14 | var data: T? 15 | func isSuccess() -> Bool { 16 | guard let _code = code else { 17 | return false 18 | } 19 | return Int.init(_code)! == 0 20 | } 21 | required init() {} 22 | } 23 | -------------------------------------------------------------------------------- /RxSwiftMVVM/MVVM/Log/Log.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Log.swift 3 | // RxSwiftMVVM 4 | // 5 | // Created by 王健伟 on 2017/10/30. 6 | // Copyright © 2017年 JianweiWang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | func Log(_ message:T, file: String = #file, function: String = #function, line: Int = #line) { 12 | #if DEBUG 13 | let fileName = (file as NSString).lastPathComponent 14 | let dateFormatter = DateFormatter() 15 | dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss.SSS" 16 | let date = Date() 17 | let dateString = dateFormatter.string(from: date) 18 | print("") 19 | print("----LOGBEGAN--- \(fileName): \(line) \(function)--------") 20 | print("\(dateString) \(message)") 21 | print("----LOGEND-----") 22 | 23 | #endif 24 | } 25 | -------------------------------------------------------------------------------- /RxSwiftMVVM/MVVM/Model/API.swift: -------------------------------------------------------------------------------- 1 | // 2 | // API.swift 3 | // RxSwiftMVVM 4 | // 5 | // Created by 王健伟 on 2017/11/2. 6 | // Copyright © 2017年 JianweiWang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Moya 11 | enum API { 12 | case Main 13 | } 14 | 15 | extension API: TargetType { 16 | 17 | var baseURL: URL { 18 | return URL(string: "http://news-at.zhihu.com")! 19 | } 20 | 21 | var path: String { 22 | switch self { 23 | case .Main: 24 | return "/api/4/stories/latest" 25 | } 26 | } 27 | 28 | var method: Moya.Method { 29 | switch self { 30 | case .Main: 31 | return .get 32 | } 33 | } 34 | 35 | var sampleData: Moya.Data { 36 | switch self { 37 | case .Main: 38 | return "".data(using: String.Encoding.utf8)! 39 | } 40 | } 41 | 42 | var task: Task { 43 | return .requestPlain 44 | } 45 | 46 | var headers: [String : String]? { 47 | return ["Content-type": "application/json"]; 48 | } 49 | 50 | 51 | } 52 | 53 | -------------------------------------------------------------------------------- /RxSwiftMVVM/MVVM/Model/JsonModel/Observable+HandyJSON.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Observable+HandyJSON.swift 3 | // RxSwiftMVVM 4 | // 5 | // Created by 王健伟 on 2017/10/25. 6 | // Copyright © 2017年 JianweiWang. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Moya 11 | import RxSwift 12 | import HandyJSON 13 | 14 | 15 | extension Observable { 16 | func map(_ type: T.Type) -> Observable { 17 | return map { response in 18 | guard let response = response as? Moya.Response else { 19 | throw RxSwiftMoyaError.ResponseError 20 | } 21 | 22 | guard (200...209) ~= response.statusCode else { 23 | throw RxSwiftMoyaError.RequestFailedError 24 | } 25 | 26 | guard let json = try? JSONSerialization.jsonObject(with: response.data, options: JSONSerialization.ReadingOptions.init(rawValue: 0)) as! [String: Any] else { 27 | throw RxSwiftMoyaError.ResponseError 28 | } 29 | 30 | let object = JSONDeserializer.deserializeFrom(dict: json) 31 | guard let model = object else { 32 | throw RxSwiftMoyaError.ParseJSONError 33 | } 34 | return model 35 | } 36 | } 37 | } 38 | 39 | 40 | enum RxSwiftMoyaError: String { 41 | case ParseJSONError 42 | case OtherError 43 | case ResponseError 44 | case RequestFailedError 45 | } 46 | 47 | extension RxSwiftMoyaError: Swift.Error { } 48 | -------------------------------------------------------------------------------- /RxSwiftMVVM/MVVM/Model/Model.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Model.swift 3 | // RxSwiftMVVM 4 | // 5 | // Created by 王健伟 on 2017/10/31. 6 | // Copyright © 2017年 JianweiWang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Moya 11 | import HandyJSON 12 | import RxSwift 13 | final class Model { 14 | func request(_ type: T, _ model: H.Type) -> Observable { 15 | let mp = MoyaProvider() 16 | let ob = mp 17 | .rx.request(type) 18 | .asObservable() 19 | .map(model) 20 | return ob 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /RxSwiftMVVM/MVVM/Model/ModelProtocol.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ModelProtocol.swift 3 | // RxSwiftMVVM 4 | // 5 | // Created by 王健伟 on 2017/10/30. 6 | // Copyright © 2017年 JianweiWang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import HandyJSON 11 | import Moya 12 | import RxSwift 13 | protocol ModelAbstract { 14 | associatedtype JsonFormat: HandyJSON 15 | associatedtype APIFormat: TargetType 16 | func request(_ type: APIFormat, _ model: JsonFormat) -> Observable 17 | } 18 | 19 | 20 | -------------------------------------------------------------------------------- /RxSwiftMVVM/MVVM/Model/RxMoya/MoyaProvider+Rx.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import RxSwift 3 | import Moya 4 | 5 | 6 | public extension Reactive where Base: MoyaProviderType { 7 | 8 | /// Designated request-making method. 9 | /// 10 | /// - Parameters: 11 | /// - token: Entity, which provides specifications necessary for a `MoyaProvider`. 12 | /// - callbackQueue: Callback queue. If nil - queue from provider initializer will be used. 13 | /// - Returns: Single response object. 14 | public func request(_ token: Base.Target, callbackQueue: DispatchQueue? = nil) -> Single { 15 | return base.rxRequest(token, callbackQueue: callbackQueue) 16 | } 17 | 18 | /// Designated request-making method with progress. 19 | public func requestWithProgress(_ token: Base.Target, callbackQueue: DispatchQueue? = nil) -> Observable { 20 | return base.rxRequestWithProgress(token, callbackQueue: callbackQueue) 21 | } 22 | } 23 | 24 | internal extension MoyaProviderType { 25 | 26 | internal func rxRequest(_ token: Target, callbackQueue: DispatchQueue? = nil) -> Single { 27 | return Single.create { single in 28 | let cancellableToken = self.request(token, callbackQueue: callbackQueue, progress: nil) { result in 29 | switch result { 30 | case let .success(response): 31 | single(.success(response)) 32 | case let .failure(error): 33 | single(.error(error)) 34 | } 35 | } 36 | 37 | return Disposables.create { 38 | cancellableToken.cancel() 39 | } 40 | } 41 | } 42 | 43 | internal func rxRequestWithProgress(_ token: Target, callbackQueue: DispatchQueue? = nil) -> Observable { 44 | let progressBlock: (AnyObserver) -> (ProgressResponse) -> Void = { observer in 45 | return { progress in 46 | observer.onNext(progress) 47 | } 48 | } 49 | 50 | let response: Observable = Observable.create { [weak self] observer in 51 | let cancellableToken = self?.request(token, callbackQueue: callbackQueue, progress: progressBlock(observer)) { result in 52 | switch result { 53 | case .success: 54 | observer.onCompleted() 55 | case let .failure(error): 56 | observer.onError(error) 57 | } 58 | } 59 | 60 | return Disposables.create { 61 | cancellableToken?.cancel() 62 | } 63 | } 64 | 65 | // Accumulate all progress and combine them when the result comes 66 | return response.scan(ProgressResponse()) { last, progress in 67 | let progressObject = progress.progressObject ?? last.progressObject 68 | let response = progress.response ?? last.response 69 | return ProgressResponse(progress: progressObject, response: response) 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /RxSwiftMVVM/MVVM/Router/Router.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Router.swift 3 | // RxSwiftMVVM 4 | // 5 | // Created by 王健伟 on 2017/10/30. 6 | // Copyright © 2017年 JianweiWang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | enum RouteError: Error { 13 | case NameSpaceGetError(String) 14 | case CastClassError 15 | } 16 | 17 | struct StoryBoard { 18 | let name: String 19 | let id: String 20 | init(_ name: String, _ id: String) { 21 | self.name = name 22 | self.id = id 23 | } 24 | } 25 | 26 | struct Router { 27 | private init() {} 28 | static let instance = Router.init() 29 | 30 | /// the map func that transform ViewModel to ViewController 31 | /// apply to code layout 32 | /// - Parameter viewModel: an obj what ViewModelProtocol constraint 33 | /// - Returns: viewController: an obj what ViewProtocol constraint 34 | 35 | static func viewController(_ viewModel: ViewModelProtocol) -> ViewProtocol { 36 | let router = Router.instance 37 | let storyboard = viewModel.storyBoard 38 | let viewController = router.viewControllerFromStoryBoard(storyBoardModel: storyboard) 39 | viewController.installViewModel(viewModel) 40 | return viewController 41 | } 42 | } 43 | 44 | extension Router { 45 | private func classNameOf(_ obj: Any) -> String { 46 | let type = Mirror.init(reflecting: obj) 47 | let keys = NSStringFromClass(type.subjectType as! AnyClass) 48 | let key = keys.components(separatedBy: ".").last! 49 | return key 50 | } 51 | 52 | private func instanceOf(_ cls: AnyClass?) throws -> ViewProtocol { 53 | guard let clsT = cls as? NSObject.Type else { 54 | throw RouteError.CastClassError 55 | } 56 | return clsT.init() as! ViewProtocol 57 | } 58 | 59 | private func viewControllerFromStoryBoard(storyBoardModel: StoryBoard) -> ViewProtocol { 60 | let storyBoard = UIStoryboard(name: storyBoardModel.name, bundle: Bundle.main) 61 | let controller = storyBoard.instantiateViewController(withIdentifier: storyBoardModel.id) as! ViewProtocol 62 | return controller 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /RxSwiftMVVM/MVVM/Stack/Stack.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NavigationControllerStack.swift 3 | // RxSwiftMVVM 4 | // 5 | // Created by 王健伟 on 2017/10/30. 6 | // Copyright © 2017年 JianweiWang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | import RxSwift 12 | final class NavigationControllerStack { 13 | 14 | static let instance = NavigationControllerStack.init() 15 | 16 | private let _service: ViewModelService 17 | 18 | private let tag = DisposeBag() 19 | 20 | var navigationStack: Array 21 | 22 | private init() { 23 | _service = Service.instance 24 | navigationStack = Array() 25 | registerNavigationHooks() 26 | } 27 | static func initialize() { 28 | _ = NavigationControllerStack.instance 29 | } 30 | } 31 | 32 | 33 | // MARK: - stack operate 34 | extension NavigationControllerStack { 35 | 36 | private func registerNavigationHooks() { 37 | 38 | _service.pushSubject 39 | .bind { (tuple) in 40 | let (viewModel, animated) = tuple as! (ViewModelProtocol, Bool) 41 | let viewController = Router.viewController(viewModel ) as! UIViewController 42 | self.navigationStack.last?.pushViewController(viewController, animated: animated) 43 | }.disposed(by: tag) 44 | 45 | _service.popSubject 46 | .bind { (tuple) in 47 | let (animated) = tuple as! (Bool) 48 | self.navigationStack.last?.popViewController(animated: animated) 49 | }.disposed(by: tag) 50 | 51 | _service.popRootSubject 52 | .bind { (tuple) in 53 | let (animated) = tuple as! (Bool) 54 | self.navigationStack.last?.popToRootViewController(animated: animated) 55 | }.disposed(by: tag) 56 | 57 | _service.presentSubject 58 | .bind { (tuple) in 59 | let (viewModel, animated, completion) = tuple as! (ViewModelProtocol, Bool, (() -> Void)?) 60 | var viewController = Router.viewController(viewModel) as! UIViewController 61 | if !viewController.isKind(of: UINavigationController.self) { 62 | viewController = UINavigationController(rootViewController: viewController) 63 | } 64 | self.navigationStack.last?.present(viewController, animated: animated, completion: completion) 65 | NavigationControllerStack.push(viewController as! UINavigationController) 66 | }.disposed(by: tag) 67 | 68 | _service.dismissSubject 69 | .bind { (tuple) in 70 | let (animated, completion) = tuple as! (Bool, (() -> Void)?) 71 | self.navigationStack.last?.dismiss(animated: animated, completion: completion) 72 | NavigationControllerStack.pop() 73 | }.disposed(by: tag) 74 | 75 | _service.resetSubject 76 | .bind { (tuple) in 77 | self.navigationStack.removeAll() 78 | let (viewModel) = tuple as! (ViewModelProtocol) 79 | let viewController = Router.viewController(viewModel) 80 | let window = (UIApplication.shared.delegate as! AppDelegate).window 81 | window?.rootViewController = (viewController as! UIViewController) 82 | }.disposed(by: tag) 83 | 84 | } 85 | 86 | public static func push(_ navigationController: UINavigationController) { 87 | let stack = NavigationControllerStack.instance 88 | if stack.navigationStack.contains(navigationController) { 89 | return 90 | } 91 | stack.navigationStack.append(navigationController) 92 | } 93 | @discardableResult public static func pop() -> UINavigationController { 94 | let stack = NavigationControllerStack.instance 95 | return stack.navigationStack.removeLast() 96 | } 97 | } 98 | 99 | // MARK: - some unpack method 100 | extension NavigationControllerStack { 101 | static func currentViewController() -> UIViewController { 102 | let stack = NavigationControllerStack.instance 103 | assert(stack.navigationStack.count > 0, "there was not any viewcontroller") 104 | return (stack.navigationStack.last?.viewControllers.last)! 105 | } 106 | static func currentNavigationViewController() -> UINavigationController { 107 | let stack = NavigationControllerStack.instance 108 | assert(stack.navigationStack.count > 0, "there was not any viewcontroller") 109 | return stack.navigationStack.last! 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /RxSwiftMVVM/MVVM/View/View.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewProtocol.swift 3 | // RxSwiftMVVM 4 | // 5 | // Created by 王健伟 on 2017/10/30. 6 | // Copyright © 2017年 JianweiWang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | protocol ViewProtocol { 12 | // associatedtype ViewModel: ViewModelProtocol 13 | 14 | func installViewModel(_ viewModel: ViewModelProtocol) 15 | } 16 | 17 | -------------------------------------------------------------------------------- /RxSwiftMVVM/MVVM/View/ViewModelMapper.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewModelMapper.swift 3 | // RxSwiftMVVM 4 | // 5 | // Created by 王健伟 on 2017/11/3. 6 | // Copyright © 2017年 JianweiWang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | protocol ViewModelCast { 12 | associatedtype ViewModel 13 | var viewModel: ViewModel? {get} 14 | 15 | } 16 | -------------------------------------------------------------------------------- /RxSwiftMVVM/MVVM/View/j.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /RxSwiftMVVM/MVVM/View/j.xcworkspace/xcuserdata/wangjianwei.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JianweiWangs/RxSwiftMVVM/218c1af907a2c7e5e43a36aaa09b64e9024df3c5/RxSwiftMVVM/MVVM/View/j.xcworkspace/xcuserdata/wangjianwei.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /RxSwiftMVVM/MVVM/ViewModel/Service.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Service.swift 3 | // RxSwiftMVVM 4 | // 5 | // Created by 王健伟 on 2017/10/30. 6 | // Copyright © 2017年 JianweiWang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import RxSwift 11 | struct Service { 12 | static let instance = Service.init() 13 | let model: Model 14 | private let _pushSubject: PublishSubject<(Any)> 15 | private let _popSubject: PublishSubject<(Any)> 16 | private let _popRootSubject: PublishSubject<(Any)> 17 | private let _presentSubject: PublishSubject<(Any)> 18 | private let _dismissSubject: PublishSubject<(Any)> 19 | private let _resetSubject: PublishSubject<(Any)> 20 | 21 | private init() { 22 | _pushSubject = PublishSubject<(Any)>() 23 | _popSubject = PublishSubject<(Any)>() 24 | _popRootSubject = PublishSubject<(Any)>() 25 | _presentSubject = PublishSubject<(Any)>() 26 | _dismissSubject = PublishSubject<(Any)>() 27 | _resetSubject = PublishSubject<(Any)>() 28 | model = Model() 29 | } 30 | } 31 | 32 | extension Service: ViewModelService { 33 | var pushSubject: PublishSubject<(Any)> { 34 | return _pushSubject 35 | } 36 | 37 | var popSubject: PublishSubject<(Any)> { 38 | return _popSubject 39 | } 40 | 41 | var popRootSubject: PublishSubject<(Any)> { 42 | return _popRootSubject 43 | } 44 | 45 | var presentSubject: PublishSubject<(Any)> { 46 | return _presentSubject 47 | } 48 | 49 | var dismissSubject: PublishSubject<(Any)> { 50 | return _dismissSubject 51 | } 52 | 53 | var resetSubject: PublishSubject<(Any)> { 54 | return _resetSubject 55 | } 56 | 57 | 58 | func pushViewModel(_ viewModel: ViewModelProtocol, _ animated: Bool) { 59 | _pushSubject.onNext((viewModel, animated)) 60 | } 61 | 62 | func popViewModel(_ animated: Bool) { 63 | _popSubject.onNext((animated)) 64 | } 65 | 66 | func popToRootViewModel(_ animated: Bool) { 67 | _popRootSubject.onNext((animated)) 68 | } 69 | 70 | func presentViewModel(_ viewModel: ViewModelProtocol, _ animated: Bool, _ completion: (() -> Void)? = nil) { 71 | _presentSubject.onNext((viewModel, animated, completion)) 72 | } 73 | 74 | func dismissViewModel(_ animated: Bool, _ completion: (() -> Void)? = nil) { 75 | dismissSubject.onNext((animated, completion)) 76 | } 77 | 78 | func resetRootViewModel(_ viewModel: ViewModelProtocol) { 79 | resetSubject.onNext((viewModel)) 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /RxSwiftMVVM/MVVM/ViewModel/ViewModelProtocol.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewModelProtocol.swift 3 | // RxSwiftMVVM 4 | // 5 | // Created by 王健伟 on 2017/10/30. 6 | // Copyright © 2017年 JianweiWang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | protocol ViewModelProtocol { 12 | var service: ViewModelService {get} 13 | var params: [Any?] {get} 14 | var storyBoard: StoryBoard {get} 15 | func push(_ animated: Bool) 16 | func pop(_ animated: Bool) 17 | func present(_ animated: Bool, _ completion: (() -> Void)?) 18 | func dismiss(_ animated: Bool, _ completion: (() -> Void)?) 19 | func initialize() 20 | } 21 | 22 | -------------------------------------------------------------------------------- /RxSwiftMVVM/MVVM/ViewModel/ViewModelService.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewModelService.swift 3 | // RxSwiftMVVM 4 | // 5 | // Created by 王健伟 on 2017/10/30. 6 | // Copyright © 2017年 JianweiWang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import RxSwift 11 | protocol ViewModelService { 12 | var pushSubject: PublishSubject<(Any)> {get} 13 | var popSubject: PublishSubject<(Any)> {get} 14 | var popRootSubject: PublishSubject<(Any)> {get} 15 | var presentSubject: PublishSubject<(Any)> {get} 16 | var dismissSubject: PublishSubject<(Any)> {get} 17 | var resetSubject: PublishSubject<(Any)> {get} 18 | var model: Model {get} 19 | func pushViewModel(_ : ViewModelProtocol, _ : Bool) 20 | func popViewModel(_ : Bool) 21 | func popToRootViewModel(_ : Bool) 22 | func presentViewModel(_ : ViewModelProtocol, _ : Bool, _ : (() -> Void)?) 23 | func dismissViewModel(_ : Bool, _ : (() -> Void)?) 24 | func resetRootViewModel(_ : ViewModelProtocol) 25 | } 26 | 27 | 28 | -------------------------------------------------------------------------------- /RxSwiftMVVM/Project/Business/DemoOne/Model/FirstModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FirstModel.swift 3 | // RxSwiftMVVM 4 | // 5 | // Created by 王健伟 on 2017/10/31. 6 | // Copyright © 2017年 JianweiWang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import HandyJSON 11 | struct FirstModel: HandyJSON { 12 | init() { 13 | 14 | } 15 | var date: String? 16 | var stories: [Storie]? 17 | var top_stories: [Top]? 18 | 19 | } 20 | struct Storie: HandyJSON { 21 | 22 | var ga_prefix: String? 23 | var id: Int? 24 | var images: [String]? 25 | var title: String? 26 | var type: String? 27 | } 28 | struct Top: HandyJSON { 29 | 30 | var ga_prefix: String? 31 | var id: String? 32 | var image: String? 33 | var title: String? 34 | var type: String? 35 | } 36 | -------------------------------------------------------------------------------- /RxSwiftMVVM/Project/Business/DemoOne/View/ZhihuTableViewCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ZhihuTableViewCell.swift 3 | // RxSwiftMVVM 4 | // 5 | // Created by 王健伟 on 2017/11/3. 6 | // Copyright © 2017年 JianweiWang. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Kingfisher 11 | class ZhihuTableViewCell: UITableViewCell { 12 | private var _model: Storie? 13 | var model: Storie? { 14 | set { 15 | self._model = newValue 16 | titleLabel.text = self._model?.title 17 | contentImageView.kf.setImage(with: URL(string: (self._model?.images![0])!)) 18 | 19 | } 20 | get { 21 | return self._model 22 | } 23 | } 24 | @IBOutlet weak var titleLabel: UILabel! 25 | @IBOutlet weak var contentImageView: UIImageView! 26 | } 27 | -------------------------------------------------------------------------------- /RxSwiftMVVM/Project/Business/DemoOne/ViewController/FirstViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FirstViewController.swift 3 | // RxSwiftMVVM 4 | // 5 | // Created by 王健伟 on 2017/10/31. 6 | // Copyright © 2017年 JianweiWang. All rights reserved. 7 | // 8 | 9 | 10 | import UIKit 11 | import Moya 12 | import RxSwift 13 | import RxCocoa 14 | import RxDataSources 15 | class FirstViewController: UIViewController, ViewProtocol, ViewModelCast { 16 | typealias ViewModel = FirstViewModel 17 | var viewModel: FirstViewModel? 18 | @IBOutlet weak var tableView: UITableView! 19 | 20 | override func viewDidLoad() { 21 | super.viewDidLoad() 22 | self.navigationItem.title = "知乎日报" 23 | 24 | var rightBarItem = UIBarButtonItem(title: "跳转", style: .plain, target: nil, action: nil) 25 | rightBarItem.rx.action = self.viewModel?.rightAction 26 | self.navigationItem.rightBarButtonItem = rightBarItem 27 | 28 | var leftBarItem = UIBarButtonItem(title: "刷新", style: .plain, target: nil, action: nil) 29 | leftBarItem.rx.action = self.viewModel?.leftAction 30 | self.navigationItem.leftBarButtonItem = leftBarItem 31 | 32 | self.viewModel? 33 | .homeAction? 34 | .executionObservables 35 | .switchLatest() 36 | .bind(to: tableView.rx.items(cellIdentifier: "zhihu", cellType: ZhihuTableViewCell.self)) { 37 | (row, element, cell) in 38 | cell.model = element 39 | } 40 | .disposed(by: self.rx.disposeBag) 41 | 42 | self.viewModel? 43 | .homeAction? 44 | .execute(true) 45 | 46 | tableView.rx 47 | .itemSelected 48 | .asObservable() 49 | .bind {[unowned self] (indexPath) in 50 | SecondViewModel() 51 | .param((self.viewModel?.data![indexPath.row].title)!) 52 | .push() 53 | }.disposed(by: self.rx.disposeBag) 54 | 55 | 56 | } 57 | func installViewModel(_ viewModel: ViewModelProtocol) { 58 | self.viewModel = viewModel as? FirstViewModel 59 | } 60 | } 61 | 62 | -------------------------------------------------------------------------------- /RxSwiftMVVM/Project/Business/DemoOne/ViewModel/FirstViewModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FirstViewModel.swift 3 | // RxSwiftMVVM 4 | // 5 | // Created by 王健伟 on 2017/10/31. 6 | // Copyright © 2017年 JianweiWang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import RxSwift 11 | import RxDataSources 12 | import RxSwiftExt 13 | import RxCocoa 14 | import Action 15 | 16 | class FirstViewModel: BaseViewModel { 17 | 18 | var homeAction: Action? 19 | var rightAction: Action? 20 | var leftAction: Action? 21 | var bool = false 22 | 23 | var data: [Storie]? 24 | 25 | init() { 26 | super.init(StoryBoard("Main", "FirstViewController")) 27 | } 28 | 29 | override func initialize() { 30 | 31 | homeAction = Action.init(workFactory: {[unowned self] (value) in 32 | self.model.request(API.Main, FirstModel.self) 33 | .map{ value ? $0.stories ?? [] : $0.stories!.dropLast(5).sorted { $0.id! > $1.id! } } 34 | .do(onNext: { 35 | self.data = $0 36 | }) 37 | }) 38 | 39 | leftAction = Action.init(workFactory: { 40 | Observable.create({[unowned self] (e) -> Disposable in 41 | self.homeAction?.execute(self.bool) 42 | self.bool = !self.bool 43 | e.onCompleted() 44 | return Disposables.create() 45 | }) 46 | }) 47 | 48 | rightAction = Action.init(workFactory: { 49 | Observable.create({ (e) -> Disposable in 50 | SecondViewModel() 51 | .param("param1") 52 | .param(["param2"]) 53 | .push() 54 | e.onCompleted() 55 | return Disposables.create() 56 | }) 57 | }) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /RxSwiftMVVM/Project/Business/DemoTwo/Model/SecondModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SecondModel.swift 3 | // RxSwiftMVVM 4 | // 5 | // Created by 王健伟 on 2017/10/31. 6 | // Copyright © 2017年 JianweiWang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | -------------------------------------------------------------------------------- /RxSwiftMVVM/Project/Business/DemoTwo/ViewController/SecondViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SecondViewController.swift 3 | // RxSwiftMVVM 4 | // 5 | // Created by 王健伟 on 2017/10/31. 6 | // Copyright © 2017年 JianweiWang. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class SecondViewController: UIViewController, ViewProtocol, ViewModelCast { 12 | var viewModel: SecondViewModel? 13 | 14 | func installViewModel(_ viewModel: ViewModelProtocol) { 15 | self.viewModel = viewModel as? SecondViewModel 16 | } 17 | 18 | typealias ViewModel = SecondViewModel 19 | 20 | override func viewDidLoad() { 21 | super.viewDidLoad() 22 | if self.viewModel!.params.count > 0 { 23 | self.navigationItem.title = (self.viewModel?.params[0] as? String) 24 | } else { 25 | self.navigationItem.title = "normal" 26 | } 27 | // MARK: check method work as normal 28 | Log(self.navigationController) 29 | Log(NavigationControllerStack.currentNavigationViewController()) 30 | Log(NavigationControllerStack.currentViewController()) 31 | Log(self) 32 | } 33 | deinit { 34 | Log("dealloc") 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /RxSwiftMVVM/Project/Business/DemoTwo/ViewModel/SecondViewModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SecondViewModel.swift 3 | // RxSwiftMVVM 4 | // 5 | // Created by 王健伟 on 2017/10/31. 6 | // Copyright © 2017年 JianweiWang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import RxSwift 11 | class SecondViewModel: BaseViewModel { 12 | 13 | 14 | init() { 15 | super.init(StoryBoard("Main", "SecondViewController")) 16 | } 17 | override func initialize() { 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /RxSwiftMVVM/Project/Business/Home/ViewController/HomeViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HomeViewController.swift 3 | // RxSwiftMVVM 4 | // 5 | // Created by 王健伟 on 2017/10/31. 6 | // Copyright © 2017年 JianweiWang. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import NSObject_Rx 11 | import RxCocoa 12 | 13 | class HomeViewController: BaseTabBarViewController, UITabBarControllerDelegate { 14 | 15 | override func viewDidLoad() { 16 | super.viewDidLoad() 17 | 18 | let viewModel = (self.viewModel as! HomeViewModel) 19 | 20 | let firstViewController: FirstViewController = Router.viewController((viewModel.firstViewModel)) as! FirstViewController 21 | 22 | let firstItem = UITabBarItem(tabBarSystemItem:.bookmarks, tag: 0) 23 | 24 | let firstNav = UINavigationController(rootViewController: firstViewController) 25 | 26 | firstNav.tabBarItem = firstItem 27 | 28 | let secondViewController: SecondViewController = Router.viewController((viewModel.secondViewModel)) as! SecondViewController 29 | 30 | let secondItem = UITabBarItem(tabBarSystemItem:.favorites, tag: 0) 31 | 32 | let secondNav = UINavigationController(rootViewController: secondViewController) 33 | 34 | secondNav.tabBarItem = secondItem 35 | 36 | self.vmTabBarController.viewControllers = [firstNav, secondNav] 37 | 38 | NavigationControllerStack.push(firstNav) 39 | 40 | self.vmTabBarController.delegate = self 41 | 42 | self.vmTabBarController 43 | .rx.didSelect 44 | .asObservable() 45 | .bind { (viewController) in 46 | NavigationControllerStack.pop() 47 | NavigationControllerStack.push(viewController as! UINavigationController) 48 | }.disposed(by: self.vmTabBarController.rx.disposeBag) 49 | 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /RxSwiftMVVM/Project/Business/Home/ViewModel/HomeViewModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HomeViewModel.swift 3 | // RxSwiftMVVM 4 | // 5 | // Created by 王健伟 on 2017/10/31. 6 | // Copyright © 2017年 JianweiWang. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class HomeViewModel: BaseViewModel { 12 | let firstViewModel = FirstViewModel() 13 | let secondViewModel = SecondViewModel() 14 | init() { 15 | super.init(StoryBoard("Main", "HomeViewController")) 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /RxSwiftMVVMTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /RxSwiftMVVMTests/RxSwiftMVVMTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RxSwiftMVVMTests.swift 3 | // RxSwiftMVVMTests 4 | // 5 | // Created by 王健伟 on 2017/10/1. 6 | // Copyright © 2017年 JianweiWang. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import RxSwiftMVVM 11 | 12 | class RxSwiftMVVMTests: XCTestCase { 13 | 14 | override func setUp() { 15 | super.setUp() 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | } 18 | 19 | override func tearDown() { 20 | // Put teardown code here. This method is called after the invocation of each test method in the class. 21 | super.tearDown() 22 | } 23 | 24 | func testExample() { 25 | // This is an example of a functional test case. 26 | // Use XCTAssert and related functions to verify your tests produce the correct results. 27 | } 28 | 29 | func testPerformanceExample() { 30 | // This is an example of a performance test case. 31 | self.measure { 32 | // Put the code you want to measure the time of here. 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /RxSwiftMVVMUITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /RxSwiftMVVMUITests/RxSwiftMVVMUITests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RxSwiftMVVMUITests.swift 3 | // RxSwiftMVVMUITests 4 | // 5 | // Created by 王健伟 on 2017/10/1. 6 | // Copyright © 2017年 JianweiWang. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | class RxSwiftMVVMUITests: XCTestCase { 12 | 13 | override func setUp() { 14 | super.setUp() 15 | 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | 18 | // In UI tests it is usually best to stop immediately when a failure occurs. 19 | continueAfterFailure = false 20 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. 21 | XCUIApplication().launch() 22 | 23 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 24 | } 25 | 26 | override func tearDown() { 27 | // Put teardown code here. This method is called after the invocation of each test method in the class. 28 | super.tearDown() 29 | } 30 | 31 | func testExample() { 32 | // Use recording to get started writing UI tests. 33 | // Use XCTAssert and related functions to verify your tests produce the correct results. 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman --------------------------------------------------------------------------------