├── .DS_Store ├── MutableCellTableView.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ └── IDEWorkspaceChecks.plist │ └── xcuserdata │ │ └── liyiping.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ └── liyiping.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ └── xcschememanagement.plist ├── MutableCellTableView ├── .DS_Store ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ └── Contents.json ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── Category │ ├── UIResponder+QFEventHandle.h │ └── UIResponder+QFEventHandle.m ├── Controller │ ├── .DS_Store │ ├── QFDetailViewController.h │ ├── QFDetailViewController.m │ ├── QFDetailViewController.xib │ ├── ViewController.h │ └── ViewController.m ├── Info.plist ├── Model │ ├── QFModeTwo.h │ ├── QFModeTwo.m │ ├── QFModelOne.h │ └── QFModelOne.m ├── Protocol │ ├── .DS_Store │ ├── QFModelProtocol.h │ └── QFViewProtocol.h ├── View │ ├── QFCellOne.h │ ├── QFCellOne.m │ ├── QFCellTwo.h │ └── QFCellTwo.m ├── ViewModel │ ├── QFViewModel.h │ └── QFViewModel.m └── main.m ├── MutableCellTableViewTests ├── Info.plist └── MutableCellTableViewTests.m ├── MutableCellTableViewUITests ├── Info.plist └── MutableCellTableViewUITests.m ├── README └── README.md /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qingfengiOS/MutableCellTableView/386ae4c13f213c3ecb528e350b2607900bbde4c5/.DS_Store -------------------------------------------------------------------------------- /MutableCellTableView.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | FD29E5DC2151DB7300D91931 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = FD29E5DB2151DB7300D91931 /* AppDelegate.m */; }; 11 | FD29E5E22151DB7300D91931 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = FD29E5E02151DB7300D91931 /* Main.storyboard */; }; 12 | FD29E5E42151DB7400D91931 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = FD29E5E32151DB7400D91931 /* Assets.xcassets */; }; 13 | FD29E5E72151DB7400D91931 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = FD29E5E52151DB7400D91931 /* LaunchScreen.storyboard */; }; 14 | FD29E5EA2151DB7400D91931 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = FD29E5E92151DB7400D91931 /* main.m */; }; 15 | FD29E5F42151DB7400D91931 /* MutableCellTableViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = FD29E5F32151DB7400D91931 /* MutableCellTableViewTests.m */; }; 16 | FD29E5FF2151DB7400D91931 /* MutableCellTableViewUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = FD29E5FE2151DB7400D91931 /* MutableCellTableViewUITests.m */; }; 17 | FD29E6132151DC3C00D91931 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FD29E60F2151DC3C00D91931 /* ViewController.m */; }; 18 | FD29E6162151DC5A00D91931 /* QFViewModel.m in Sources */ = {isa = PBXBuildFile; fileRef = FD29E6152151DC5A00D91931 /* QFViewModel.m */; }; 19 | FD29E6192151DC8600D91931 /* QFModelOne.m in Sources */ = {isa = PBXBuildFile; fileRef = FD29E6182151DC8600D91931 /* QFModelOne.m */; }; 20 | FD29E61C2151DC8F00D91931 /* QFModeTwo.m in Sources */ = {isa = PBXBuildFile; fileRef = FD29E61B2151DC8F00D91931 /* QFModeTwo.m */; }; 21 | FD29E6252151DE5A00D91931 /* UIResponder+QFEventHandle.m in Sources */ = {isa = PBXBuildFile; fileRef = FD29E6242151DE5A00D91931 /* UIResponder+QFEventHandle.m */; }; 22 | FD29E62D2151E0A300D91931 /* QFCellOne.m in Sources */ = {isa = PBXBuildFile; fileRef = FD29E62C2151E0A300D91931 /* QFCellOne.m */; }; 23 | FD29E6302151E0B000D91931 /* QFCellTwo.m in Sources */ = {isa = PBXBuildFile; fileRef = FD29E62F2151E0B000D91931 /* QFCellTwo.m */; }; 24 | FD38C8AD216C88060015A18F /* QFDetailViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FD38C8AB216C88060015A18F /* QFDetailViewController.m */; }; 25 | FD38C8AE216C88060015A18F /* QFDetailViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = FD38C8AC216C88060015A18F /* QFDetailViewController.xib */; }; 26 | /* End PBXBuildFile section */ 27 | 28 | /* Begin PBXContainerItemProxy section */ 29 | FD29E5F02151DB7400D91931 /* PBXContainerItemProxy */ = { 30 | isa = PBXContainerItemProxy; 31 | containerPortal = FD29E5CF2151DB7300D91931 /* Project object */; 32 | proxyType = 1; 33 | remoteGlobalIDString = FD29E5D62151DB7300D91931; 34 | remoteInfo = MutableCellTableView; 35 | }; 36 | FD29E5FB2151DB7400D91931 /* PBXContainerItemProxy */ = { 37 | isa = PBXContainerItemProxy; 38 | containerPortal = FD29E5CF2151DB7300D91931 /* Project object */; 39 | proxyType = 1; 40 | remoteGlobalIDString = FD29E5D62151DB7300D91931; 41 | remoteInfo = MutableCellTableView; 42 | }; 43 | /* End PBXContainerItemProxy section */ 44 | 45 | /* Begin PBXFileReference section */ 46 | FD29E5D72151DB7300D91931 /* MutableCellTableView.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MutableCellTableView.app; sourceTree = BUILT_PRODUCTS_DIR; }; 47 | FD29E5DA2151DB7300D91931 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 48 | FD29E5DB2151DB7300D91931 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 49 | FD29E5E12151DB7300D91931 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 50 | FD29E5E32151DB7400D91931 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 51 | FD29E5E62151DB7400D91931 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 52 | FD29E5E82151DB7400D91931 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 53 | FD29E5E92151DB7400D91931 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 54 | FD29E5EF2151DB7400D91931 /* MutableCellTableViewTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MutableCellTableViewTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 55 | FD29E5F32151DB7400D91931 /* MutableCellTableViewTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MutableCellTableViewTests.m; sourceTree = ""; }; 56 | FD29E5F52151DB7400D91931 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 57 | FD29E5FA2151DB7400D91931 /* MutableCellTableViewUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MutableCellTableViewUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 58 | FD29E5FE2151DB7400D91931 /* MutableCellTableViewUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MutableCellTableViewUITests.m; sourceTree = ""; }; 59 | FD29E6002151DB7400D91931 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 60 | FD29E60F2151DC3C00D91931 /* ViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 61 | FD29E6102151DC3C00D91931 /* ViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 62 | FD29E6142151DC5A00D91931 /* QFViewModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = QFViewModel.h; sourceTree = ""; }; 63 | FD29E6152151DC5A00D91931 /* QFViewModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = QFViewModel.m; sourceTree = ""; }; 64 | FD29E6172151DC8600D91931 /* QFModelOne.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = QFModelOne.h; sourceTree = ""; }; 65 | FD29E6182151DC8600D91931 /* QFModelOne.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = QFModelOne.m; sourceTree = ""; }; 66 | FD29E61A2151DC8F00D91931 /* QFModeTwo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = QFModeTwo.h; sourceTree = ""; }; 67 | FD29E61B2151DC8F00D91931 /* QFModeTwo.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = QFModeTwo.m; sourceTree = ""; }; 68 | FD29E6202151DDCE00D91931 /* QFViewProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = QFViewProtocol.h; sourceTree = ""; }; 69 | FD29E6212151DDF900D91931 /* QFModelProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = QFModelProtocol.h; sourceTree = ""; }; 70 | FD29E6232151DE5A00D91931 /* UIResponder+QFEventHandle.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UIResponder+QFEventHandle.h"; sourceTree = ""; }; 71 | FD29E6242151DE5A00D91931 /* UIResponder+QFEventHandle.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UIResponder+QFEventHandle.m"; sourceTree = ""; }; 72 | FD29E62B2151E0A300D91931 /* QFCellOne.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = QFCellOne.h; sourceTree = ""; }; 73 | FD29E62C2151E0A300D91931 /* QFCellOne.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = QFCellOne.m; sourceTree = ""; }; 74 | FD29E62E2151E0B000D91931 /* QFCellTwo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = QFCellTwo.h; sourceTree = ""; }; 75 | FD29E62F2151E0B000D91931 /* QFCellTwo.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = QFCellTwo.m; sourceTree = ""; }; 76 | FD38C8AA216C88060015A18F /* QFDetailViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = QFDetailViewController.h; sourceTree = ""; }; 77 | FD38C8AB216C88060015A18F /* QFDetailViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = QFDetailViewController.m; sourceTree = ""; }; 78 | FD38C8AC216C88060015A18F /* QFDetailViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = QFDetailViewController.xib; sourceTree = ""; }; 79 | /* End PBXFileReference section */ 80 | 81 | /* Begin PBXFrameworksBuildPhase section */ 82 | FD29E5D42151DB7300D91931 /* Frameworks */ = { 83 | isa = PBXFrameworksBuildPhase; 84 | buildActionMask = 2147483647; 85 | files = ( 86 | ); 87 | runOnlyForDeploymentPostprocessing = 0; 88 | }; 89 | FD29E5EC2151DB7400D91931 /* Frameworks */ = { 90 | isa = PBXFrameworksBuildPhase; 91 | buildActionMask = 2147483647; 92 | files = ( 93 | ); 94 | runOnlyForDeploymentPostprocessing = 0; 95 | }; 96 | FD29E5F72151DB7400D91931 /* Frameworks */ = { 97 | isa = PBXFrameworksBuildPhase; 98 | buildActionMask = 2147483647; 99 | files = ( 100 | ); 101 | runOnlyForDeploymentPostprocessing = 0; 102 | }; 103 | /* End PBXFrameworksBuildPhase section */ 104 | 105 | /* Begin PBXGroup section */ 106 | FD29E5CE2151DB7300D91931 = { 107 | isa = PBXGroup; 108 | children = ( 109 | FD29E5D92151DB7300D91931 /* MutableCellTableView */, 110 | FD29E5F22151DB7400D91931 /* MutableCellTableViewTests */, 111 | FD29E5FD2151DB7400D91931 /* MutableCellTableViewUITests */, 112 | FD29E5D82151DB7300D91931 /* Products */, 113 | ); 114 | sourceTree = ""; 115 | }; 116 | FD29E5D82151DB7300D91931 /* Products */ = { 117 | isa = PBXGroup; 118 | children = ( 119 | FD29E5D72151DB7300D91931 /* MutableCellTableView.app */, 120 | FD29E5EF2151DB7400D91931 /* MutableCellTableViewTests.xctest */, 121 | FD29E5FA2151DB7400D91931 /* MutableCellTableViewUITests.xctest */, 122 | ); 123 | name = Products; 124 | sourceTree = ""; 125 | }; 126 | FD29E5D92151DB7300D91931 /* MutableCellTableView */ = { 127 | isa = PBXGroup; 128 | children = ( 129 | FD29E6222151DE3900D91931 /* Category */, 130 | FD29E60E2151DC3C00D91931 /* Controller */, 131 | FD29E60C2151DC3C00D91931 /* Model */, 132 | FD29E6112151DC3C00D91931 /* Protocol */, 133 | FD29E6122151DC3C00D91931 /* View */, 134 | FD29E60D2151DC3C00D91931 /* ViewModel */, 135 | FD29E5DA2151DB7300D91931 /* AppDelegate.h */, 136 | FD29E5DB2151DB7300D91931 /* AppDelegate.m */, 137 | FD29E5E02151DB7300D91931 /* Main.storyboard */, 138 | FD29E5E32151DB7400D91931 /* Assets.xcassets */, 139 | FD29E5E52151DB7400D91931 /* LaunchScreen.storyboard */, 140 | FD29E5E82151DB7400D91931 /* Info.plist */, 141 | FD29E5E92151DB7400D91931 /* main.m */, 142 | ); 143 | path = MutableCellTableView; 144 | sourceTree = ""; 145 | }; 146 | FD29E5F22151DB7400D91931 /* MutableCellTableViewTests */ = { 147 | isa = PBXGroup; 148 | children = ( 149 | FD29E5F32151DB7400D91931 /* MutableCellTableViewTests.m */, 150 | FD29E5F52151DB7400D91931 /* Info.plist */, 151 | ); 152 | path = MutableCellTableViewTests; 153 | sourceTree = ""; 154 | }; 155 | FD29E5FD2151DB7400D91931 /* MutableCellTableViewUITests */ = { 156 | isa = PBXGroup; 157 | children = ( 158 | FD29E5FE2151DB7400D91931 /* MutableCellTableViewUITests.m */, 159 | FD29E6002151DB7400D91931 /* Info.plist */, 160 | ); 161 | path = MutableCellTableViewUITests; 162 | sourceTree = ""; 163 | }; 164 | FD29E60C2151DC3C00D91931 /* Model */ = { 165 | isa = PBXGroup; 166 | children = ( 167 | FD29E6172151DC8600D91931 /* QFModelOne.h */, 168 | FD29E6182151DC8600D91931 /* QFModelOne.m */, 169 | FD29E61A2151DC8F00D91931 /* QFModeTwo.h */, 170 | FD29E61B2151DC8F00D91931 /* QFModeTwo.m */, 171 | ); 172 | path = Model; 173 | sourceTree = ""; 174 | }; 175 | FD29E60D2151DC3C00D91931 /* ViewModel */ = { 176 | isa = PBXGroup; 177 | children = ( 178 | FD29E6142151DC5A00D91931 /* QFViewModel.h */, 179 | FD29E6152151DC5A00D91931 /* QFViewModel.m */, 180 | ); 181 | path = ViewModel; 182 | sourceTree = ""; 183 | }; 184 | FD29E60E2151DC3C00D91931 /* Controller */ = { 185 | isa = PBXGroup; 186 | children = ( 187 | FD29E6102151DC3C00D91931 /* ViewController.h */, 188 | FD29E60F2151DC3C00D91931 /* ViewController.m */, 189 | FD38C8AA216C88060015A18F /* QFDetailViewController.h */, 190 | FD38C8AB216C88060015A18F /* QFDetailViewController.m */, 191 | FD38C8AC216C88060015A18F /* QFDetailViewController.xib */, 192 | ); 193 | path = Controller; 194 | sourceTree = ""; 195 | }; 196 | FD29E6112151DC3C00D91931 /* Protocol */ = { 197 | isa = PBXGroup; 198 | children = ( 199 | FD29E6202151DDCE00D91931 /* QFViewProtocol.h */, 200 | FD29E6212151DDF900D91931 /* QFModelProtocol.h */, 201 | ); 202 | path = Protocol; 203 | sourceTree = ""; 204 | }; 205 | FD29E6122151DC3C00D91931 /* View */ = { 206 | isa = PBXGroup; 207 | children = ( 208 | FD29E62B2151E0A300D91931 /* QFCellOne.h */, 209 | FD29E62C2151E0A300D91931 /* QFCellOne.m */, 210 | FD29E62E2151E0B000D91931 /* QFCellTwo.h */, 211 | FD29E62F2151E0B000D91931 /* QFCellTwo.m */, 212 | ); 213 | path = View; 214 | sourceTree = ""; 215 | }; 216 | FD29E6222151DE3900D91931 /* Category */ = { 217 | isa = PBXGroup; 218 | children = ( 219 | FD29E6232151DE5A00D91931 /* UIResponder+QFEventHandle.h */, 220 | FD29E6242151DE5A00D91931 /* UIResponder+QFEventHandle.m */, 221 | ); 222 | path = Category; 223 | sourceTree = ""; 224 | }; 225 | /* End PBXGroup section */ 226 | 227 | /* Begin PBXNativeTarget section */ 228 | FD29E5D62151DB7300D91931 /* MutableCellTableView */ = { 229 | isa = PBXNativeTarget; 230 | buildConfigurationList = FD29E6032151DB7400D91931 /* Build configuration list for PBXNativeTarget "MutableCellTableView" */; 231 | buildPhases = ( 232 | FD29E5D32151DB7300D91931 /* Sources */, 233 | FD29E5D42151DB7300D91931 /* Frameworks */, 234 | FD29E5D52151DB7300D91931 /* Resources */, 235 | ); 236 | buildRules = ( 237 | ); 238 | dependencies = ( 239 | ); 240 | name = MutableCellTableView; 241 | productName = MutableCellTableView; 242 | productReference = FD29E5D72151DB7300D91931 /* MutableCellTableView.app */; 243 | productType = "com.apple.product-type.application"; 244 | }; 245 | FD29E5EE2151DB7400D91931 /* MutableCellTableViewTests */ = { 246 | isa = PBXNativeTarget; 247 | buildConfigurationList = FD29E6062151DB7400D91931 /* Build configuration list for PBXNativeTarget "MutableCellTableViewTests" */; 248 | buildPhases = ( 249 | FD29E5EB2151DB7400D91931 /* Sources */, 250 | FD29E5EC2151DB7400D91931 /* Frameworks */, 251 | FD29E5ED2151DB7400D91931 /* Resources */, 252 | ); 253 | buildRules = ( 254 | ); 255 | dependencies = ( 256 | FD29E5F12151DB7400D91931 /* PBXTargetDependency */, 257 | ); 258 | name = MutableCellTableViewTests; 259 | productName = MutableCellTableViewTests; 260 | productReference = FD29E5EF2151DB7400D91931 /* MutableCellTableViewTests.xctest */; 261 | productType = "com.apple.product-type.bundle.unit-test"; 262 | }; 263 | FD29E5F92151DB7400D91931 /* MutableCellTableViewUITests */ = { 264 | isa = PBXNativeTarget; 265 | buildConfigurationList = FD29E6092151DB7400D91931 /* Build configuration list for PBXNativeTarget "MutableCellTableViewUITests" */; 266 | buildPhases = ( 267 | FD29E5F62151DB7400D91931 /* Sources */, 268 | FD29E5F72151DB7400D91931 /* Frameworks */, 269 | FD29E5F82151DB7400D91931 /* Resources */, 270 | ); 271 | buildRules = ( 272 | ); 273 | dependencies = ( 274 | FD29E5FC2151DB7400D91931 /* PBXTargetDependency */, 275 | ); 276 | name = MutableCellTableViewUITests; 277 | productName = MutableCellTableViewUITests; 278 | productReference = FD29E5FA2151DB7400D91931 /* MutableCellTableViewUITests.xctest */; 279 | productType = "com.apple.product-type.bundle.ui-testing"; 280 | }; 281 | /* End PBXNativeTarget section */ 282 | 283 | /* Begin PBXProject section */ 284 | FD29E5CF2151DB7300D91931 /* Project object */ = { 285 | isa = PBXProject; 286 | attributes = { 287 | CLASSPREFIX = QF; 288 | LastUpgradeCheck = 0940; 289 | ORGANIZATIONNAME = qingfengiOS; 290 | TargetAttributes = { 291 | FD29E5D62151DB7300D91931 = { 292 | CreatedOnToolsVersion = 9.4.1; 293 | }; 294 | FD29E5EE2151DB7400D91931 = { 295 | CreatedOnToolsVersion = 9.4.1; 296 | TestTargetID = FD29E5D62151DB7300D91931; 297 | }; 298 | FD29E5F92151DB7400D91931 = { 299 | CreatedOnToolsVersion = 9.4.1; 300 | TestTargetID = FD29E5D62151DB7300D91931; 301 | }; 302 | }; 303 | }; 304 | buildConfigurationList = FD29E5D22151DB7300D91931 /* Build configuration list for PBXProject "MutableCellTableView" */; 305 | compatibilityVersion = "Xcode 9.3"; 306 | developmentRegion = en; 307 | hasScannedForEncodings = 0; 308 | knownRegions = ( 309 | en, 310 | Base, 311 | ); 312 | mainGroup = FD29E5CE2151DB7300D91931; 313 | productRefGroup = FD29E5D82151DB7300D91931 /* Products */; 314 | projectDirPath = ""; 315 | projectRoot = ""; 316 | targets = ( 317 | FD29E5D62151DB7300D91931 /* MutableCellTableView */, 318 | FD29E5EE2151DB7400D91931 /* MutableCellTableViewTests */, 319 | FD29E5F92151DB7400D91931 /* MutableCellTableViewUITests */, 320 | ); 321 | }; 322 | /* End PBXProject section */ 323 | 324 | /* Begin PBXResourcesBuildPhase section */ 325 | FD29E5D52151DB7300D91931 /* Resources */ = { 326 | isa = PBXResourcesBuildPhase; 327 | buildActionMask = 2147483647; 328 | files = ( 329 | FD38C8AE216C88060015A18F /* QFDetailViewController.xib in Resources */, 330 | FD29E5E72151DB7400D91931 /* LaunchScreen.storyboard in Resources */, 331 | FD29E5E42151DB7400D91931 /* Assets.xcassets in Resources */, 332 | FD29E5E22151DB7300D91931 /* Main.storyboard in Resources */, 333 | ); 334 | runOnlyForDeploymentPostprocessing = 0; 335 | }; 336 | FD29E5ED2151DB7400D91931 /* Resources */ = { 337 | isa = PBXResourcesBuildPhase; 338 | buildActionMask = 2147483647; 339 | files = ( 340 | ); 341 | runOnlyForDeploymentPostprocessing = 0; 342 | }; 343 | FD29E5F82151DB7400D91931 /* Resources */ = { 344 | isa = PBXResourcesBuildPhase; 345 | buildActionMask = 2147483647; 346 | files = ( 347 | ); 348 | runOnlyForDeploymentPostprocessing = 0; 349 | }; 350 | /* End PBXResourcesBuildPhase section */ 351 | 352 | /* Begin PBXSourcesBuildPhase section */ 353 | FD29E5D32151DB7300D91931 /* Sources */ = { 354 | isa = PBXSourcesBuildPhase; 355 | buildActionMask = 2147483647; 356 | files = ( 357 | FD29E6132151DC3C00D91931 /* ViewController.m in Sources */, 358 | FD38C8AD216C88060015A18F /* QFDetailViewController.m in Sources */, 359 | FD29E62D2151E0A300D91931 /* QFCellOne.m in Sources */, 360 | FD29E6192151DC8600D91931 /* QFModelOne.m in Sources */, 361 | FD29E5EA2151DB7400D91931 /* main.m in Sources */, 362 | FD29E61C2151DC8F00D91931 /* QFModeTwo.m in Sources */, 363 | FD29E6302151E0B000D91931 /* QFCellTwo.m in Sources */, 364 | FD29E6162151DC5A00D91931 /* QFViewModel.m in Sources */, 365 | FD29E6252151DE5A00D91931 /* UIResponder+QFEventHandle.m in Sources */, 366 | FD29E5DC2151DB7300D91931 /* AppDelegate.m in Sources */, 367 | ); 368 | runOnlyForDeploymentPostprocessing = 0; 369 | }; 370 | FD29E5EB2151DB7400D91931 /* Sources */ = { 371 | isa = PBXSourcesBuildPhase; 372 | buildActionMask = 2147483647; 373 | files = ( 374 | FD29E5F42151DB7400D91931 /* MutableCellTableViewTests.m in Sources */, 375 | ); 376 | runOnlyForDeploymentPostprocessing = 0; 377 | }; 378 | FD29E5F62151DB7400D91931 /* Sources */ = { 379 | isa = PBXSourcesBuildPhase; 380 | buildActionMask = 2147483647; 381 | files = ( 382 | FD29E5FF2151DB7400D91931 /* MutableCellTableViewUITests.m in Sources */, 383 | ); 384 | runOnlyForDeploymentPostprocessing = 0; 385 | }; 386 | /* End PBXSourcesBuildPhase section */ 387 | 388 | /* Begin PBXTargetDependency section */ 389 | FD29E5F12151DB7400D91931 /* PBXTargetDependency */ = { 390 | isa = PBXTargetDependency; 391 | target = FD29E5D62151DB7300D91931 /* MutableCellTableView */; 392 | targetProxy = FD29E5F02151DB7400D91931 /* PBXContainerItemProxy */; 393 | }; 394 | FD29E5FC2151DB7400D91931 /* PBXTargetDependency */ = { 395 | isa = PBXTargetDependency; 396 | target = FD29E5D62151DB7300D91931 /* MutableCellTableView */; 397 | targetProxy = FD29E5FB2151DB7400D91931 /* PBXContainerItemProxy */; 398 | }; 399 | /* End PBXTargetDependency section */ 400 | 401 | /* Begin PBXVariantGroup section */ 402 | FD29E5E02151DB7300D91931 /* Main.storyboard */ = { 403 | isa = PBXVariantGroup; 404 | children = ( 405 | FD29E5E12151DB7300D91931 /* Base */, 406 | ); 407 | name = Main.storyboard; 408 | sourceTree = ""; 409 | }; 410 | FD29E5E52151DB7400D91931 /* LaunchScreen.storyboard */ = { 411 | isa = PBXVariantGroup; 412 | children = ( 413 | FD29E5E62151DB7400D91931 /* Base */, 414 | ); 415 | name = LaunchScreen.storyboard; 416 | sourceTree = ""; 417 | }; 418 | /* End PBXVariantGroup section */ 419 | 420 | /* Begin XCBuildConfiguration section */ 421 | FD29E6012151DB7400D91931 /* Debug */ = { 422 | isa = XCBuildConfiguration; 423 | buildSettings = { 424 | ALWAYS_SEARCH_USER_PATHS = NO; 425 | CLANG_ANALYZER_NONNULL = YES; 426 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 427 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 428 | CLANG_CXX_LIBRARY = "libc++"; 429 | CLANG_ENABLE_MODULES = YES; 430 | CLANG_ENABLE_OBJC_ARC = YES; 431 | CLANG_ENABLE_OBJC_WEAK = YES; 432 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 433 | CLANG_WARN_BOOL_CONVERSION = YES; 434 | CLANG_WARN_COMMA = YES; 435 | CLANG_WARN_CONSTANT_CONVERSION = YES; 436 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 437 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 438 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 439 | CLANG_WARN_EMPTY_BODY = YES; 440 | CLANG_WARN_ENUM_CONVERSION = YES; 441 | CLANG_WARN_INFINITE_RECURSION = YES; 442 | CLANG_WARN_INT_CONVERSION = YES; 443 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 444 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 445 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 446 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 447 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 448 | CLANG_WARN_STRICT_PROTOTYPES = YES; 449 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 450 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 451 | CLANG_WARN_UNREACHABLE_CODE = YES; 452 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 453 | CODE_SIGN_IDENTITY = "iPhone Developer"; 454 | COPY_PHASE_STRIP = NO; 455 | DEBUG_INFORMATION_FORMAT = dwarf; 456 | ENABLE_STRICT_OBJC_MSGSEND = YES; 457 | ENABLE_TESTABILITY = YES; 458 | GCC_C_LANGUAGE_STANDARD = gnu11; 459 | GCC_DYNAMIC_NO_PIC = NO; 460 | GCC_NO_COMMON_BLOCKS = YES; 461 | GCC_OPTIMIZATION_LEVEL = 0; 462 | GCC_PREPROCESSOR_DEFINITIONS = ( 463 | "DEBUG=1", 464 | "$(inherited)", 465 | ); 466 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 467 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 468 | GCC_WARN_UNDECLARED_SELECTOR = YES; 469 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 470 | GCC_WARN_UNUSED_FUNCTION = YES; 471 | GCC_WARN_UNUSED_VARIABLE = YES; 472 | IPHONEOS_DEPLOYMENT_TARGET = 11.4; 473 | MTL_ENABLE_DEBUG_INFO = YES; 474 | ONLY_ACTIVE_ARCH = YES; 475 | SDKROOT = iphoneos; 476 | }; 477 | name = Debug; 478 | }; 479 | FD29E6022151DB7400D91931 /* Release */ = { 480 | isa = XCBuildConfiguration; 481 | buildSettings = { 482 | ALWAYS_SEARCH_USER_PATHS = NO; 483 | CLANG_ANALYZER_NONNULL = YES; 484 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 485 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 486 | CLANG_CXX_LIBRARY = "libc++"; 487 | CLANG_ENABLE_MODULES = YES; 488 | CLANG_ENABLE_OBJC_ARC = YES; 489 | CLANG_ENABLE_OBJC_WEAK = YES; 490 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 491 | CLANG_WARN_BOOL_CONVERSION = YES; 492 | CLANG_WARN_COMMA = YES; 493 | CLANG_WARN_CONSTANT_CONVERSION = YES; 494 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 495 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 496 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 497 | CLANG_WARN_EMPTY_BODY = YES; 498 | CLANG_WARN_ENUM_CONVERSION = YES; 499 | CLANG_WARN_INFINITE_RECURSION = YES; 500 | CLANG_WARN_INT_CONVERSION = YES; 501 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 502 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 503 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 504 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 505 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 506 | CLANG_WARN_STRICT_PROTOTYPES = YES; 507 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 508 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 509 | CLANG_WARN_UNREACHABLE_CODE = YES; 510 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 511 | CODE_SIGN_IDENTITY = "iPhone Developer"; 512 | COPY_PHASE_STRIP = NO; 513 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 514 | ENABLE_NS_ASSERTIONS = NO; 515 | ENABLE_STRICT_OBJC_MSGSEND = YES; 516 | GCC_C_LANGUAGE_STANDARD = gnu11; 517 | GCC_NO_COMMON_BLOCKS = YES; 518 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 519 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 520 | GCC_WARN_UNDECLARED_SELECTOR = YES; 521 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 522 | GCC_WARN_UNUSED_FUNCTION = YES; 523 | GCC_WARN_UNUSED_VARIABLE = YES; 524 | IPHONEOS_DEPLOYMENT_TARGET = 11.4; 525 | MTL_ENABLE_DEBUG_INFO = NO; 526 | SDKROOT = iphoneos; 527 | VALIDATE_PRODUCT = YES; 528 | }; 529 | name = Release; 530 | }; 531 | FD29E6042151DB7400D91931 /* Debug */ = { 532 | isa = XCBuildConfiguration; 533 | buildSettings = { 534 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 535 | CODE_SIGN_STYLE = Automatic; 536 | DEVELOPMENT_TEAM = DZK6T3AW3W; 537 | INFOPLIST_FILE = MutableCellTableView/Info.plist; 538 | LD_RUNPATH_SEARCH_PATHS = ( 539 | "$(inherited)", 540 | "@executable_path/Frameworks", 541 | ); 542 | PRODUCT_BUNDLE_IDENTIFIER = com.shanglv51.www.MutableCellTableView; 543 | PRODUCT_NAME = "$(TARGET_NAME)"; 544 | TARGETED_DEVICE_FAMILY = "1,2"; 545 | }; 546 | name = Debug; 547 | }; 548 | FD29E6052151DB7400D91931 /* Release */ = { 549 | isa = XCBuildConfiguration; 550 | buildSettings = { 551 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 552 | CODE_SIGN_STYLE = Automatic; 553 | DEVELOPMENT_TEAM = DZK6T3AW3W; 554 | INFOPLIST_FILE = MutableCellTableView/Info.plist; 555 | LD_RUNPATH_SEARCH_PATHS = ( 556 | "$(inherited)", 557 | "@executable_path/Frameworks", 558 | ); 559 | PRODUCT_BUNDLE_IDENTIFIER = com.shanglv51.www.MutableCellTableView; 560 | PRODUCT_NAME = "$(TARGET_NAME)"; 561 | TARGETED_DEVICE_FAMILY = "1,2"; 562 | }; 563 | name = Release; 564 | }; 565 | FD29E6072151DB7400D91931 /* Debug */ = { 566 | isa = XCBuildConfiguration; 567 | buildSettings = { 568 | BUNDLE_LOADER = "$(TEST_HOST)"; 569 | CODE_SIGN_STYLE = Automatic; 570 | DEVELOPMENT_TEAM = DZK6T3AW3W; 571 | INFOPLIST_FILE = MutableCellTableViewTests/Info.plist; 572 | LD_RUNPATH_SEARCH_PATHS = ( 573 | "$(inherited)", 574 | "@executable_path/Frameworks", 575 | "@loader_path/Frameworks", 576 | ); 577 | PRODUCT_BUNDLE_IDENTIFIER = com.shanglv51.www.MutableCellTableViewTests; 578 | PRODUCT_NAME = "$(TARGET_NAME)"; 579 | TARGETED_DEVICE_FAMILY = "1,2"; 580 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/MutableCellTableView.app/MutableCellTableView"; 581 | }; 582 | name = Debug; 583 | }; 584 | FD29E6082151DB7400D91931 /* Release */ = { 585 | isa = XCBuildConfiguration; 586 | buildSettings = { 587 | BUNDLE_LOADER = "$(TEST_HOST)"; 588 | CODE_SIGN_STYLE = Automatic; 589 | DEVELOPMENT_TEAM = DZK6T3AW3W; 590 | INFOPLIST_FILE = MutableCellTableViewTests/Info.plist; 591 | LD_RUNPATH_SEARCH_PATHS = ( 592 | "$(inherited)", 593 | "@executable_path/Frameworks", 594 | "@loader_path/Frameworks", 595 | ); 596 | PRODUCT_BUNDLE_IDENTIFIER = com.shanglv51.www.MutableCellTableViewTests; 597 | PRODUCT_NAME = "$(TARGET_NAME)"; 598 | TARGETED_DEVICE_FAMILY = "1,2"; 599 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/MutableCellTableView.app/MutableCellTableView"; 600 | }; 601 | name = Release; 602 | }; 603 | FD29E60A2151DB7400D91931 /* Debug */ = { 604 | isa = XCBuildConfiguration; 605 | buildSettings = { 606 | CODE_SIGN_STYLE = Automatic; 607 | DEVELOPMENT_TEAM = DZK6T3AW3W; 608 | INFOPLIST_FILE = MutableCellTableViewUITests/Info.plist; 609 | LD_RUNPATH_SEARCH_PATHS = ( 610 | "$(inherited)", 611 | "@executable_path/Frameworks", 612 | "@loader_path/Frameworks", 613 | ); 614 | PRODUCT_BUNDLE_IDENTIFIER = com.shanglv51.www.MutableCellTableViewUITests; 615 | PRODUCT_NAME = "$(TARGET_NAME)"; 616 | TARGETED_DEVICE_FAMILY = "1,2"; 617 | TEST_TARGET_NAME = MutableCellTableView; 618 | }; 619 | name = Debug; 620 | }; 621 | FD29E60B2151DB7400D91931 /* Release */ = { 622 | isa = XCBuildConfiguration; 623 | buildSettings = { 624 | CODE_SIGN_STYLE = Automatic; 625 | DEVELOPMENT_TEAM = DZK6T3AW3W; 626 | INFOPLIST_FILE = MutableCellTableViewUITests/Info.plist; 627 | LD_RUNPATH_SEARCH_PATHS = ( 628 | "$(inherited)", 629 | "@executable_path/Frameworks", 630 | "@loader_path/Frameworks", 631 | ); 632 | PRODUCT_BUNDLE_IDENTIFIER = com.shanglv51.www.MutableCellTableViewUITests; 633 | PRODUCT_NAME = "$(TARGET_NAME)"; 634 | TARGETED_DEVICE_FAMILY = "1,2"; 635 | TEST_TARGET_NAME = MutableCellTableView; 636 | }; 637 | name = Release; 638 | }; 639 | /* End XCBuildConfiguration section */ 640 | 641 | /* Begin XCConfigurationList section */ 642 | FD29E5D22151DB7300D91931 /* Build configuration list for PBXProject "MutableCellTableView" */ = { 643 | isa = XCConfigurationList; 644 | buildConfigurations = ( 645 | FD29E6012151DB7400D91931 /* Debug */, 646 | FD29E6022151DB7400D91931 /* Release */, 647 | ); 648 | defaultConfigurationIsVisible = 0; 649 | defaultConfigurationName = Release; 650 | }; 651 | FD29E6032151DB7400D91931 /* Build configuration list for PBXNativeTarget "MutableCellTableView" */ = { 652 | isa = XCConfigurationList; 653 | buildConfigurations = ( 654 | FD29E6042151DB7400D91931 /* Debug */, 655 | FD29E6052151DB7400D91931 /* Release */, 656 | ); 657 | defaultConfigurationIsVisible = 0; 658 | defaultConfigurationName = Release; 659 | }; 660 | FD29E6062151DB7400D91931 /* Build configuration list for PBXNativeTarget "MutableCellTableViewTests" */ = { 661 | isa = XCConfigurationList; 662 | buildConfigurations = ( 663 | FD29E6072151DB7400D91931 /* Debug */, 664 | FD29E6082151DB7400D91931 /* Release */, 665 | ); 666 | defaultConfigurationIsVisible = 0; 667 | defaultConfigurationName = Release; 668 | }; 669 | FD29E6092151DB7400D91931 /* Build configuration list for PBXNativeTarget "MutableCellTableViewUITests" */ = { 670 | isa = XCConfigurationList; 671 | buildConfigurations = ( 672 | FD29E60A2151DB7400D91931 /* Debug */, 673 | FD29E60B2151DB7400D91931 /* Release */, 674 | ); 675 | defaultConfigurationIsVisible = 0; 676 | defaultConfigurationName = Release; 677 | }; 678 | /* End XCConfigurationList section */ 679 | }; 680 | rootObject = FD29E5CF2151DB7300D91931 /* Project object */; 681 | } 682 | -------------------------------------------------------------------------------- /MutableCellTableView.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /MutableCellTableView.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /MutableCellTableView.xcodeproj/project.xcworkspace/xcuserdata/liyiping.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qingfengiOS/MutableCellTableView/386ae4c13f213c3ecb528e350b2607900bbde4c5/MutableCellTableView.xcodeproj/project.xcworkspace/xcuserdata/liyiping.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /MutableCellTableView.xcodeproj/xcuserdata/liyiping.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /MutableCellTableView.xcodeproj/xcuserdata/liyiping.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | MutableCellTableView.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /MutableCellTableView/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qingfengiOS/MutableCellTableView/386ae4c13f213c3ecb528e350b2607900bbde4c5/MutableCellTableView/.DS_Store -------------------------------------------------------------------------------- /MutableCellTableView/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // MutableCellTableView 4 | // 5 | // Created by 情风 on 2018/9/19. 6 | // Copyright © 2018年 qingfengiOS. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /MutableCellTableView/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // MutableCellTableView 4 | // 5 | // Created by 情风 on 2018/9/19. 6 | // Copyright © 2018年 qingfengiOS. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | - (void)routerEventWithName:(NSString *)eventName userInfo:(NSDictionary *)userInfo { 18 | 19 | } 20 | 21 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 22 | // Override point for customization after application launch. 23 | return YES; 24 | } 25 | 26 | 27 | - (void)applicationWillResignActive:(UIApplication *)application { 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 | 33 | - (void)applicationDidEnterBackground:(UIApplication *)application { 34 | // 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. 35 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 36 | } 37 | 38 | 39 | - (void)applicationWillEnterForeground:(UIApplication *)application { 40 | // 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. 41 | } 42 | 43 | 44 | - (void)applicationDidBecomeActive:(UIApplication *)application { 45 | // 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. 46 | } 47 | 48 | 49 | - (void)applicationWillTerminate:(UIApplication *)application { 50 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 51 | } 52 | 53 | 54 | @end 55 | -------------------------------------------------------------------------------- /MutableCellTableView/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 | } -------------------------------------------------------------------------------- /MutableCellTableView/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /MutableCellTableView/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 | -------------------------------------------------------------------------------- /MutableCellTableView/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 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /MutableCellTableView/Category/UIResponder+QFEventHandle.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIResponder+QFEventHandle.h 3 | // MutableCellTableView 4 | // 5 | // Created by 情风 on 2018/9/19. 6 | // Copyright © 2018年 qingfengiOS. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface UIResponder (QFEventHandle) 12 | 13 | /** 14 | 通过事件响应链条传递事件 15 | 16 | @param eventName 事件名 17 | @param userInfo 附加参数 18 | */ 19 | - (void)routerEventWithName:(NSString *)eventName userInfo:(NSDictionary *)userInfo; 20 | 21 | /** 22 | 通过方法SEL生成NSInvocation 23 | 24 | @param selector 方法 25 | @return Invocation对象 26 | */ 27 | - (NSInvocation *)createInvocationWithSelector:(SEL)selector; 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /MutableCellTableView/Category/UIResponder+QFEventHandle.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIResponder+QFEventHandle.m 3 | // MutableCellTableView 4 | // 5 | // Created by 情风 on 2018/9/19. 6 | // Copyright © 2018年 qingfengiOS. All rights reserved. 7 | // 8 | 9 | #import "UIResponder+QFEventHandle.h" 10 | 11 | @implementation UIResponder (QFEventHandle) 12 | 13 | 14 | /** 15 | 通过事件响应链条传递事件 16 | 17 | @param eventName 事件名 18 | @param userInfo 附加参数 19 | */ 20 | - (void)routerEventWithName:(NSString *)eventName userInfo:(NSDictionary *)userInfo { 21 | [[self nextResponder] routerEventWithName:eventName userInfo:userInfo]; 22 | } 23 | 24 | /** 25 | 通过方法SEL生成NSInvocation 26 | 27 | @param selector 方法 28 | @return Invocation对象 29 | */ 30 | - (NSInvocation *)createInvocationWithSelector:(SEL)selector { 31 | //通过方法名创建方法签名 32 | NSMethodSignature *signature = [[self class] instanceMethodSignatureForSelector:selector]; 33 | //创建invocation 34 | NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature]; 35 | [invocation setTarget:self]; 36 | [invocation setSelector:selector]; 37 | return invocation; 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /MutableCellTableView/Controller/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qingfengiOS/MutableCellTableView/386ae4c13f213c3ecb528e350b2607900bbde4c5/MutableCellTableView/Controller/.DS_Store -------------------------------------------------------------------------------- /MutableCellTableView/Controller/QFDetailViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // QFDetailViewController.h 3 | // MutableCellTableView 4 | // 5 | // Created by 李一平 on 2018/10/9. 6 | // Copyright © 2018年 qingfengiOS. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface QFDetailViewController : UIViewController 12 | 13 | /// 类型 14 | @property (nonatomic, copy) NSString *typeName; 15 | 16 | /// 参数 17 | @property (nonatomic, strong) NSDictionary *paramterDic; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /MutableCellTableView/Controller/QFDetailViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // QFDetailViewController.m 3 | // MutableCellTableView 4 | // 5 | // Created by 李一平 on 2018/10/9. 6 | // Copyright © 2018年 qingfengiOS. All rights reserved. 7 | // 8 | 9 | #import "QFDetailViewController.h" 10 | 11 | @interface QFDetailViewController () 12 | @property (weak, nonatomic) IBOutlet UILabel *typeLabel; 13 | @property (weak, nonatomic) IBOutlet UITextView *paramterTextView; 14 | @end 15 | 16 | @implementation QFDetailViewController 17 | 18 | #pragma mark - Life Cycle 19 | - (void)viewDidLoad { 20 | [super viewDidLoad]; 21 | self.typeLabel.text = self.typeName; 22 | self.paramterTextView.text = [self dictionaryToString:self.paramterDic]; 23 | } 24 | 25 | 26 | #pragma mark - Event Response 27 | - (IBAction)closeButtonAction:(id)sender { 28 | [self dismissViewControllerAnimated:YES completion:nil]; 29 | } 30 | 31 | #pragma mark - CustomMethod 32 | - (NSString*)dictionaryToString:(NSDictionary *)parameter { 33 | NSError *parseError = nil; 34 | NSData *jsonData = [NSJSONSerialization dataWithJSONObject:parameter options:NSJSONWritingPrettyPrinted error:&parseError]; 35 | return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; 36 | } 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /MutableCellTableView/Controller/QFDetailViewController.xib: -------------------------------------------------------------------------------- 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 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /MutableCellTableView/Controller/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // MutableCellTableView 4 | // 5 | // Created by 情风 on 2018/9/19. 6 | // Copyright © 2018年 qingfengiOS. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | 17 | -------------------------------------------------------------------------------- /MutableCellTableView/Controller/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // MutableCellTableView 4 | // 5 | // Created by 情风 on 2018/9/19. 6 | // Copyright © 2018年 qingfengiOS. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "QFDetailViewController.h" 11 | 12 | #import "QFViewModel.h" 13 | 14 | #import "QFCellOne.h" 15 | #import "QFCellTwo.h" 16 | 17 | #import "UIResponder+QFEventHandle.h" 18 | 19 | @interface ViewController () 20 | 21 | /// tableView 22 | @property (nonatomic, strong) UITableView *tableView; 23 | 24 | /// ViewModel 25 | @property (nonatomic, strong) QFViewModel *viewModel; 26 | 27 | /// 事件策略字典 key:事件名 value:事件的invocation对象 28 | @property (nonatomic, strong) NSDictionary *eventStrategy; 29 | 30 | @end 31 | 32 | NSString *const kEventOneName = @"QFCellOneEvent"; 33 | NSString *const kEventTwoName = @"QFCellTwoEvent"; 34 | 35 | static NSString *const kCellOneIdentifier = @"QFCellOne"; 36 | static NSString *const kCellTwoIdentifier = @"QFCellTwo"; 37 | 38 | @implementation ViewController 39 | 40 | #pragma mark - Life Cycle 41 | - (void)viewDidLoad { 42 | [super viewDidLoad]; 43 | [self initAppreaence]; 44 | } 45 | 46 | #pragma mark - InitAppreaence 47 | - (void)initAppreaence { 48 | [self.tableView registerClass:[QFCellOne class] forCellReuseIdentifier:kCellOneIdentifier]; 49 | [self.tableView registerClass:[QFCellTwo class] forCellReuseIdentifier:kCellTwoIdentifier]; 50 | [self.view addSubview:self.tableView]; 51 | } 52 | 53 | #pragma mark - Event Response 54 | - (void)routerEventWithName:(NSString *)eventName userInfo:(NSDictionary *)userInfo { 55 | // 处理事件 56 | [self handleEventWithName:eventName parameter:userInfo]; 57 | 58 | // 把响应链继续传递下去 59 | [super routerEventWithName:eventName userInfo:userInfo]; 60 | } 61 | 62 | - (void)handleEventWithName:(NSString *)eventName parameter:(NSDictionary *)parameter { 63 | // 获取invocation对象 64 | NSInvocation *invocation = self.strategyDictionary[eventName]; 65 | // 设置invocation参数 66 | [invocation setArgument:¶meter atIndex:2]; 67 | // 调用方法 68 | [invocation invoke]; 69 | } 70 | 71 | - (void)cellOneEventWithParamter:(NSDictionary *)paramter { 72 | NSLog(@"第一种cell事件---------参数:%@",paramter); 73 | QFDetailViewController *viewController = [QFDetailViewController new]; 74 | viewController.typeName = @"Cell类型一"; 75 | viewController.paramterDic = paramter; 76 | [self presentViewController:viewController animated:YES completion:nil]; 77 | } 78 | 79 | - (void)cellTwoEventWithParamter:(NSDictionary *)paramter { 80 | NSLog(@"第二种cell事件---------参数:%@",paramter); 81 | QFDetailViewController *viewController = [QFDetailViewController new]; 82 | viewController.typeName = @"Cell类型二"; 83 | viewController.paramterDic = paramter; 84 | [self presentViewController:viewController animated:YES completion:nil]; 85 | } 86 | 87 | #pragma mark - TableViewDelegate/dataSource 88 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 89 | return [self.viewModel numberOfRowsInSection:section]; 90 | } 91 | 92 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 93 | 94 | id model = [self.viewModel tableView:tableView itemForRowAtIndexPath:indexPath]; 95 | id cell = [tableView dequeueReusableCellWithIdentifier:model.identifier]; 96 | [cell configCellDateByModel:model]; 97 | return cell; 98 | } 99 | 100 | 101 | #pragma mark - Getters 102 | - (QFViewModel *)viewModel { 103 | if (!_viewModel) { 104 | _viewModel = QFViewModel.new; 105 | } 106 | return _viewModel; 107 | } 108 | 109 | - (NSDictionary *)strategyDictionary { 110 | if (!_eventStrategy) { 111 | _eventStrategy = @{ 112 | kEventOneName:[self createInvocationWithSelector:@selector(cellOneEventWithParamter:)], 113 | kEventTwoName:[self createInvocationWithSelector:@selector(cellTwoEventWithParamter:)] 114 | }; 115 | } 116 | return _eventStrategy; 117 | } 118 | 119 | 120 | #pragma mark - Getters 121 | - (UITableView *)tableView { 122 | if (!_tableView) { 123 | _tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height) style:UITableViewStylePlain]; 124 | _tableView.delegate = self; 125 | _tableView.dataSource = self; 126 | _tableView.tableFooterView = [[UIView alloc] init]; 127 | } 128 | return _tableView; 129 | } 130 | 131 | @end 132 | -------------------------------------------------------------------------------- /MutableCellTableView/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 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /MutableCellTableView/Model/QFModeTwo.h: -------------------------------------------------------------------------------- 1 | // 2 | // ModeTwo.h 3 | // MutableCellTableView 4 | // 5 | // Created by 情风 on 2018/9/19. 6 | // Copyright © 2018年 qingfengiOS. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "QFModelProtocol.h" 11 | 12 | @interface QFModeTwo : NSObject 13 | 14 | @property (nonatomic, copy) NSString *nameString; 15 | @property (nonatomic, assign) NSUInteger age; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /MutableCellTableView/Model/QFModeTwo.m: -------------------------------------------------------------------------------- 1 | // 2 | // ModeTwo.m 3 | // MutableCellTableView 4 | // 5 | // Created by 情风 on 2018/9/19. 6 | // Copyright © 2018年 qingfengiOS. All rights reserved. 7 | // 8 | 9 | #import "QFModeTwo.h" 10 | 11 | @implementation QFModeTwo 12 | 13 | - (NSString *)nameString { 14 | return @"情风"; 15 | } 16 | 17 | - (NSUInteger)age { 18 | return 18; 19 | } 20 | 21 | - (NSString *)identifier { 22 | return @"QFCellTwo"; 23 | } 24 | 25 | - (CGFloat)height { 26 | return 50.0f; 27 | } 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /MutableCellTableView/Model/QFModelOne.h: -------------------------------------------------------------------------------- 1 | // 2 | // ModelOne.h 3 | // MutableCellTableView 4 | // 5 | // Created by 情风 on 2018/9/19. 6 | // Copyright © 2018年 qingfengiOS. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "QFModelProtocol.h" 11 | 12 | @interface QFModelOne : NSObject 13 | 14 | @property (nonatomic, copy) NSString *titleString; 15 | @property (nonatomic, copy) NSString *subTitleString; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /MutableCellTableView/Model/QFModelOne.m: -------------------------------------------------------------------------------- 1 | // 2 | // ModelOne.m 3 | // MutableCellTableView 4 | // 5 | // Created by 情风 on 2018/9/19. 6 | // Copyright © 2018年 qingfengiOS. All rights reserved. 7 | // 8 | 9 | #import "QFModelOne.h" 10 | 11 | @implementation QFModelOne 12 | 13 | - (NSString *)titleString { 14 | return @"标题"; 15 | } 16 | 17 | - (NSString *)subTitleString { 18 | return @"副标题"; 19 | } 20 | 21 | 22 | - (NSString *)identifier { 23 | return @"QFCellOne"; 24 | } 25 | 26 | - (CGFloat)height { 27 | return 65.0f; 28 | } 29 | @end 30 | -------------------------------------------------------------------------------- /MutableCellTableView/Protocol/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qingfengiOS/MutableCellTableView/386ae4c13f213c3ecb528e350b2607900bbde4c5/MutableCellTableView/Protocol/.DS_Store -------------------------------------------------------------------------------- /MutableCellTableView/Protocol/QFModelProtocol.h: -------------------------------------------------------------------------------- 1 | // 2 | // QFModelProtocol.h 3 | // MutableCellTableView 4 | // 5 | // Created by 情风 on 2018/9/19. 6 | // Copyright © 2018年 qingfengiOS. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | /** 12 | 协议用于保存每个model对应cell的重用标志符和行高,也可以不使用这个协议 直接在对一个的model里指明 13 | */ 14 | @protocol QFModelProtocol 15 | 16 | - (NSString *)identifier; 17 | 18 | - (CGFloat)height; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /MutableCellTableView/Protocol/QFViewProtocol.h: -------------------------------------------------------------------------------- 1 | // 2 | // QFViewProtocol.h 3 | // MutableCellTableView 4 | // 5 | // Created by 情风 on 2018/9/19. 6 | // Copyright © 2018年 qingfengiOS. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "QFModelProtocol.h" 11 | 12 | /** 13 | 协议用于保存每个cell的数据源设置方法,也可以不用,直接在每个类型的cell头文件中定义,考虑到开放封闭原则,建议使用 14 | */ 15 | @protocol QFViewProtocol 16 | 17 | /** 18 | 通过model 配置cell展示 19 | 20 | @param model model 21 | */ 22 | - (void)configCellDateByModel:(id)model; 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /MutableCellTableView/View/QFCellOne.h: -------------------------------------------------------------------------------- 1 | // 2 | // QFCellOne.h 3 | // MutableCellTableView 4 | // 5 | // Created by 情风 on 2018/9/19. 6 | // Copyright © 2018年 qingfengiOS. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "QFViewProtocol.h" 11 | 12 | @interface QFCellOne : UITableViewCell 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /MutableCellTableView/View/QFCellOne.m: -------------------------------------------------------------------------------- 1 | // 2 | // QFCellOne.m 3 | // MutableCellTableView 4 | // 5 | // Created by 情风 on 2018/9/19. 6 | // Copyright © 2018年 qingfengiOS. All rights reserved. 7 | // 8 | 9 | #import "QFCellOne.h" 10 | #import "QFModelOne.h" 11 | #import "UIResponder+QFEventHandle.h" 12 | 13 | @interface QFCellOne () 14 | @property (nonatomic, strong) UILabel *titleLabel; 15 | @property (nonatomic, strong) UILabel *subLabel; 16 | @end 17 | 18 | extern NSString *kEventOneName; 19 | 20 | @implementation QFCellOne 21 | 22 | - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { 23 | if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) { 24 | [self initAppreaence]; 25 | } 26 | return self; 27 | } 28 | 29 | 30 | #pragma mark - InitAppreaence 31 | - (void)initAppreaence { 32 | self.titleLabel = [[UILabel alloc]initWithFrame:CGRectMake(10, 10, 100, 20 )]; 33 | self.titleLabel.textColor = [UIColor redColor]; 34 | [self.contentView addSubview:self.titleLabel]; 35 | 36 | self.subLabel = [[UILabel alloc]initWithFrame:CGRectMake(10, 30, 100, 20 )]; 37 | self.subLabel.textColor = [UIColor redColor]; 38 | [self.contentView addSubview:self.subLabel]; 39 | } 40 | 41 | #pragma mark - Configration 42 | - (void)configCellDateByModel:(id)model{ 43 | QFModelOne *modelOne = (QFModelOne *)model; 44 | self.titleLabel.text = modelOne.titleString; 45 | self.subLabel.text = modelOne.subTitleString; 46 | } 47 | 48 | #pragma mark - Event Handle 49 | - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { 50 | [self routerEventWithName:kEventOneName userInfo:@{@"keyOne": @"valueOne"}]; 51 | } 52 | 53 | 54 | @end 55 | -------------------------------------------------------------------------------- /MutableCellTableView/View/QFCellTwo.h: -------------------------------------------------------------------------------- 1 | // 2 | // QFCellTwo.h 3 | // MutableCellTableView 4 | // 5 | // Created by 情风 on 2018/9/19. 6 | // Copyright © 2018年 qingfengiOS. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "QFViewProtocol.h" 11 | 12 | @interface QFCellTwo : UITableViewCell 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /MutableCellTableView/View/QFCellTwo.m: -------------------------------------------------------------------------------- 1 | // 2 | // QFCellTwo.m 3 | // MutableCellTableView 4 | // 5 | // Created by 情风 on 2018/9/19. 6 | // Copyright © 2018年 qingfengiOS. All rights reserved. 7 | // 8 | 9 | #import "QFCellTwo.h" 10 | #import "QFModeTwo.h" 11 | #import "UIResponder+QFEventHandle.h" 12 | @interface QFCellTwo () 13 | @property (nonatomic, strong) UILabel *nameLabel; 14 | @property (nonatomic, strong) UILabel *ageLabel; 15 | @end 16 | 17 | extern NSString *kEventTwoName; 18 | 19 | @implementation QFCellTwo 20 | - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { 21 | if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) { 22 | [self initAppreaence]; 23 | } 24 | return self; 25 | } 26 | 27 | #pragma mark - InitAppreaence 28 | - (void)initAppreaence { 29 | self.nameLabel = [[UILabel alloc]initWithFrame:CGRectMake(10, 12, 100, 20 )]; 30 | self.nameLabel.textColor = [UIColor redColor]; 31 | [self.contentView addSubview:self.nameLabel]; 32 | 33 | self.ageLabel = [[UILabel alloc]initWithFrame:CGRectMake(120, 12, 100, 20 )]; 34 | self.ageLabel.textColor = [UIColor redColor]; 35 | self.ageLabel.textAlignment = NSTextAlignmentRight; 36 | [self.contentView addSubview:self.ageLabel]; 37 | 38 | } 39 | #pragma mark - Configration 40 | - (void)configCellDateByModel:(id)model{ 41 | QFModeTwo *modelTwo = (QFModeTwo *)model; 42 | self.nameLabel.text = modelTwo.nameString; 43 | self.ageLabel.text = [NSString stringWithFormat:@"%lu",(unsigned long)modelTwo.age]; 44 | } 45 | 46 | #pragma mark - Event Handle 47 | - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { 48 | [self routerEventWithName:kEventTwoName userInfo:@{@"keyTwo": @"valueTwo"}]; 49 | } 50 | 51 | 52 | @end 53 | -------------------------------------------------------------------------------- /MutableCellTableView/ViewModel/QFViewModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewModel.h 3 | // MutableCellTableView 4 | // 5 | // Created by 情风 on 2018/9/19. 6 | // Copyright © 2018年 qingfengiOS. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "QFModelProtocol.h" 11 | 12 | @interface QFViewModel : NSObject 13 | 14 | - (NSInteger)numberOfRowsInSection:(NSInteger)section; 15 | 16 | - (id)tableView:(UITableView *)tableView itemForRowAtIndexPath:(NSIndexPath *)indexPath; 17 | @end 18 | -------------------------------------------------------------------------------- /MutableCellTableView/ViewModel/QFViewModel.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewModel.m 3 | // MutableCellTableView 4 | // 5 | // Created by 情风 on 2018/9/19. 6 | // Copyright © 2018年 qingfengiOS. All rights reserved. 7 | // 8 | 9 | #import "QFViewModel.h" 10 | 11 | #import "QFModelOne.h" 12 | #import "QFModeTwo.h" 13 | 14 | @interface QFViewModel () 15 | @property (nonatomic, strong) NSArray *dataArray;//数据源数组 16 | @end 17 | 18 | @implementation QFViewModel 19 | 20 | #pragma mark - Life Cycle 21 | - (instancetype)init { 22 | if (self = [super init]) { 23 | [self initDataSource]; 24 | } 25 | return self; 26 | } 27 | 28 | #pragma mark - InitDataSource 29 | - (void)initDataSource { 30 | QFModelOne *modelOne = [QFModelOne new]; 31 | QFModeTwo *modelTwo = [QFModeTwo new]; 32 | self.dataArray = @[modelOne,modelTwo,modelOne,modelTwo,modelTwo,modelOne]; 33 | } 34 | 35 | #pragma mark - TableViewDelegate/dataSource 36 | - (NSInteger)numberOfRowsInSection:(NSInteger)section { 37 | return self.dataArray.count; 38 | } 39 | 40 | - (id)tableView:(UITableView *)tableView itemForRowAtIndexPath:(NSIndexPath *)indexPath { 41 | id model = self.dataArray[indexPath.row]; 42 | return model; 43 | } 44 | 45 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { 46 | id model = self.dataArray[indexPath.row]; 47 | return model.height; 48 | } 49 | 50 | 51 | 52 | @end 53 | -------------------------------------------------------------------------------- /MutableCellTableView/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // MutableCellTableView 4 | // 5 | // Created by 情风 on 2018/9/19. 6 | // Copyright © 2018年 qingfengiOS. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /MutableCellTableViewTests/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 | -------------------------------------------------------------------------------- /MutableCellTableViewTests/MutableCellTableViewTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // MutableCellTableViewTests.m 3 | // MutableCellTableViewTests 4 | // 5 | // Created by 情风 on 2018/9/19. 6 | // Copyright © 2018年 qingfengiOS. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface MutableCellTableViewTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation MutableCellTableViewTests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | // Put setup code here. This method is called before the invocation of each test method in the class. 20 | } 21 | 22 | - (void)tearDown { 23 | // Put teardown code here. This method is called after the invocation of each test method in the class. 24 | [super tearDown]; 25 | } 26 | 27 | - (void)testExample { 28 | // This is an example of a functional test case. 29 | // Use XCTAssert and related functions to verify your tests produce the correct results. 30 | } 31 | 32 | - (void)testPerformanceExample { 33 | // This is an example of a performance test case. 34 | [self measureBlock:^{ 35 | // Put the code you want to measure the time of here. 36 | }]; 37 | } 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /MutableCellTableViewUITests/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 | -------------------------------------------------------------------------------- /MutableCellTableViewUITests/MutableCellTableViewUITests.m: -------------------------------------------------------------------------------- 1 | // 2 | // MutableCellTableViewUITests.m 3 | // MutableCellTableViewUITests 4 | // 5 | // Created by 情风 on 2018/9/19. 6 | // Copyright © 2018年 qingfengiOS. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface MutableCellTableViewUITests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation MutableCellTableViewUITests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | 22 | // In UI tests it is usually best to stop immediately when a failure occurs. 23 | self.continueAfterFailure = NO; 24 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. 25 | [[[XCUIApplication alloc] init] launch]; 26 | 27 | // 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. 28 | } 29 | 30 | - (void)tearDown { 31 | // Put teardown code here. This method is called after the invocation of each test method in the class. 32 | [super tearDown]; 33 | } 34 | 35 | - (void)testExample { 36 | // Use recording to get started writing UI tests. 37 | // Use XCTAssert and related functions to verify your tests produce the correct results. 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qingfengiOS/MutableCellTableView/386ae4c13f213c3ecb528e350b2607900bbde4c5/README -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 前言 2 | 在iOS开发中,常见的MVC中,复杂界面的Controller中的代码极其臃肿,动则上千行的代码量对后期维护简直是一种灾难,因此MVC也被调侃为Messive ViewController,特别是有多种类型Cell的TableView存在时,在```-tableView:cellForRowAtIndexPath:```代理方法中充斥着大量的if-else分支,这次我们尝试用一种新的方式来“优雅”地实现这个方法。 3 | 4 | 传统iOS的对象间交互模式就那么几种:直接property传值、delegate、KVO、block、protocol、多态、Target-Action。这次来说说基于ResponderChain来实现对象间交互。 5 | 6 | 这种方式通过在UIResponder上挂一个category,使得事件和参数可以沿着responder chain逐步传递。 7 | 8 | 这相当于借用responder chain实现了一个自己的事件传递链。这在事件需要层层传递的时候特别好用,然而这种对象交互方式的有效场景仅限于在responder chain上的UIResponder对象上。 9 | 10 | ## 二、MVVM分离逻辑,解耦 11 | 网上关于MVVM的文章很多而且每个人的理解可能都有小小的差别,这里不做赘述,这里说说我在项目中所用到的MVVM,如果错误,请看官多多指教。我的tableView定义在Controller中,其代理方法也在Contriller实现,ViewModel为其提供必要的数据: 12 | 13 | 头文件中: 14 | 15 | ``` 16 | #import 17 | 18 | @interface QFViewModel : NSObject 19 | 20 | - (NSInteger)numberOfRowsInSection:(NSInteger)section; 21 | 22 | - (id)tableView:(UITableView *)tableView itemForRowAtIndexPath:(NSIndexPath *)indexPath; 23 | 24 | @end 25 | ``` 26 | 27 | 实现文件中两个关键方法: 28 | 29 | ``` 30 | - (NSInteger)numberOfRowsInSection:(NSInteger)section { 31 | return self.dataArray.count; 32 | } 33 | 34 | - (id)tableView:(UITableView *)tableView itemForRowAtIndexPath:(NSIndexPath *)indexPath { 35 | id model = self.dataArray[indexPath.row]; 36 | return model; 37 | } 38 | ``` 39 | 这里用到了协议Protocol做解耦,两个协议,一个视图层的协议```QFViewProtocol```,一个模型的协议```QFModelProtocol``` 40 | 41 | - QFViewProtocol 这里提供一个方法,通过模型数据设置界面的展示 42 | 43 | ``` 44 | /** 45 | 协议用于保存每个cell的数据源设置方法,也可以不用,直接在每个类型的cell头文件中定义,考虑到开放封闭原则,建议使用 46 | */ 47 | @protocol QFViewProtocol 48 | 49 | /** 50 | 通过model 配置cell展示 51 | 52 | @param model model 53 | */ 54 | - (void)configCellDateByModel:(id)model; 55 | ``` 56 | - QFModelProtocol 这里提供两个属性,一个重用标志符,一个行高 57 | 58 | ``` 59 | #import 60 | 61 | /** 62 | 协议用于保存每个model对应cell的重用标志符和行高,也可以不使用这个协议 直接在对一个的model里指明 63 | */ 64 | @protocol QFModelProtocol 65 | 66 | - (NSString *)identifier; 67 | 68 | - (CGFloat)height; 69 | 70 | @end 71 | ``` 72 | 在控制器层中直接创建并且addSubView: 73 | 74 | ``` 75 | - (void)initAppreaence { 76 | [self.tableView registerClass:[QFCellOne class] forCellReuseIdentifier:kCellOneIdentifier]; 77 | [self.tableView registerClass:[QFCellTwo class] forCellReuseIdentifier:kCellTwoIdentifier]; 78 | [self.view addSubview:self.tableView]; 79 | } 80 | ``` 81 | 82 | 83 | ## 三、基于ResponderChain传递点击事件 84 | 在iOS的事件传递响应中有一棵响应树,使用此可以消除掉各个类中的头文件引用。使用这个特性只需要一个方法即可,为UIResponder添加分类,实现一个方法: 85 | 86 | ``` 87 | /** 88 | 通过事件响应链条传递事件 89 | 90 | @param eventName 事件名 91 | @param userInfo 附加参数 92 | */ 93 | - (void)routerEventWithName:(NSString *)eventName userInfo:(NSDictionary *)userInfo { 94 | [[self nextResponder] routerEventWithName:eventName userInfo:userInfo]; 95 | } 96 | ``` 97 | 98 | 发送事件的时候使用: 99 | 100 | ``` 101 | [self routerEventWithName:kEventOneName userInfo:@{@"keyOne": @"valueOne"}]; 102 | ``` 103 | >这里使用了一个字典来做参数的传递,这里可以使用装饰者模式,在事件层层向上传递的时候,每一层都可以往UserInfo这个字典中添加数据。那么到了最终事件处理的时候,就能收集到各层综合得到的数据,从而完成最终的事件处理。 104 | 105 | 如果要把这个事件继续传递下去直到APPDelegate中的话,调用: 106 | 107 | ``` 108 | // 把响应链继续传递下去 109 | [super routerEventWithName:eventName userInfo:userInfo]; 110 | ``` 111 | ## 四、策略模式避免if-else 112 | 在《大话设计模式》一书中,使用了商场打折的案例分析了策略模式对于不同算法的封装,有兴趣可以去看看,这里我们使用策略模式封装的是NSInvocation,他用于做方法调用,在消息转发的最后阶段会通过NSInvocation来转发。我们以一个方法调用的实例来看NSInvocation 113 | 114 | ``` 115 | #pragma mark - invocation调用方法 116 | - (void)invocation { 117 | SEL myMethod = @selector(testInvocationWithString:number:); 118 | NSMethodSignature *sig = [[self class] instanceMethodSignatureForSelector:myMethod]; 119 | NSInvocation * invocatin = [NSInvocation invocationWithMethodSignature:sig]; 120 | 121 | [invocatin setTarget:self]; 122 | [invocatin setSelector:myMethod]; 123 | 124 | NSString *a = @"string"; 125 | NSInteger b = 10; 126 | [invocatin setArgument:&a atIndex:2]; 127 | [invocatin setArgument:&b atIndex:3]; 128 | 129 | NSInteger res = 0; 130 | [invocatin invoke]; 131 | [invocatin getReturnValue:&res]; 132 | 133 | NSLog(@"%ld",(long)res); 134 | } 135 | 136 | - (NSInteger)testInvocationWithString:(NSString *)str number:(NSInteger)number { 137 | 138 | return str.length + number; 139 | } 140 | ``` 141 | 142 | - 第一步通过方法,生成方法签名; 143 | - 第二步设置参数,注意这里```[invocatin setArgument:&a atIndex:2];```的index从2开始而不是0,因为还有两个隐藏参数self和_cmd占用了两个 144 | - 第三步调用```[invocatin invoke];``` 145 | 146 | 好了我们回归主题,这里用一个dictionary,保存方法调用的必要参数,字典的key是事件名,value是对应的invocation对象,当事件发生时,直接调用 147 | 148 | ``` 149 | - (NSDictionary *)strategyDictionary { 150 | if (!_eventStrategy) { 151 | _eventStrategy = @{ 152 | kEventOneName:[self createInvocationWithSelector:@selector(cellOneEventWithParamter:)], 153 | kEventTwoName:[self createInvocationWithSelector:@selector(cellTwoEventWithParamter:)] 154 | }; 155 | } 156 | return _eventStrategy; 157 | } 158 | 159 | ``` 160 | 161 | 这里调用```UIResponder```中的的方法```- (NSInvocation *)createInvocationWithSelector:(SEL)selector```生成invocation: 162 | 163 | ``` 164 | /** 165 | 通过方法SEL生成NSInvocation 166 | 167 | @param selector 方法 168 | @return Invocation对象 169 | */ 170 | - (NSInvocation *)createInvocationWithSelector:(SEL)selector { 171 | //通过方法名创建方法签名 172 | NSMethodSignature *signature = [[self class] instanceMethodSignatureForSelector:selector]; 173 | //创建invocation 174 | NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature]; 175 | [invocation setTarget:self]; 176 | [invocation setSelector:selector]; 177 | return invocation; 178 | } 179 | ``` 180 | ## 五、事件处理 181 | 经过上面的步骤,我们可以在Controller中通过```- (void)routerEventWithName:(NSString *)eventName userInfo:(NSDictionary *)userInfo ```拿到事件做响应的处理,如果有必要,把这个事件继续传递下去: 182 | 183 | ``` 184 | #pragma mark - Event Response 185 | - (void)routerEventWithName:(NSString *)eventName userInfo:(NSDictionary *)userInfo { 186 | // 处理事件 187 | [self handleEventWithName:eventName parameter:userInfo]; 188 | 189 | // 把响应链继续传递下去 190 | [super routerEventWithName:eventName userInfo:userInfo]; 191 | } 192 | 193 | - (void)handleEventWithName:(NSString *)eventName parameter:(NSDictionary *)parameter { 194 | // 获取invocation对象 195 | NSInvocation *invocation = self.strategyDictionary[eventName]; 196 | // 设置invocation参数 197 | [invocation setArgument:¶meter atIndex:2]; 198 | // 调用方法 199 | [invocation invoke]; 200 | } 201 | 202 | - (void)cellOneEventWithParamter:(NSDictionary *)paramter { 203 | NSLog(@"第一种cell事件---------参数:%@",paramter); 204 | QFDetailViewController *viewController = [QFDetailViewController new]; 205 | viewController.typeName = @"Cell类型一"; 206 | viewController.paramterDic = paramter; 207 | [self presentViewController:viewController animated:YES completion:nil]; 208 | } 209 | 210 | - (void)cellTwoEventWithParamter:(NSDictionary *)paramter { 211 | NSLog(@"第二种cell事件---------参数:%@",paramter); 212 | QFDetailViewController *viewController = [QFDetailViewController new]; 213 | viewController.typeName = @"Cell类型二"; 214 | viewController.paramterDic = paramter; 215 | [self presentViewController:viewController animated:YES completion:nil]; 216 | } 217 | ``` 218 | ## 六、后记 219 | 本篇到此结束了,总结起来,用到的东西还是不少,很多东西都值得深入: 220 | 221 | - Protocol的使用 222 | - 事件处理:事件产生、传递及响应的机制 223 | - 设计模式:策略模式、装饰者模式以及MVVM的使用 224 | - NSInvocation的使用及消息转发机制 225 | 226 | [Demo演示](https://github.com/qingfengiOS/MutableCellTableView) 227 | 有任何意见和建议欢迎交流指导,如果可以,请顺手给个star。 228 | 229 | 感谢评论区各位的赐教,纠正了我把tableView定义在VM中的颠覆性错误! 230 | 231 | 最后,万分感谢[Casa大佬](https://casatwy.com)的分享! 232 | [一种基于ResponderChain的对象交互方式](https://casatwy.com/responder_chain_communication.html#seg3) 233 | --------------------------------------------------------------------------------