├── .swift-version ├── CellCountDown.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ └── herobin.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ └── herobin.xcuserdatad │ └── xcschemes │ ├── CellCountDown.xcscheme │ └── xcschememanagement.plist ├── CellCountDown ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets │ └── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── icon-20@2x.png │ │ ├── icon-20@3x.png │ │ ├── icon-29@2x.png │ │ ├── icon-29@3x.png │ │ ├── icon-40@2x.png │ │ ├── icon-40@3x.png │ │ ├── icon-60@2x.png │ │ └── icon-60@3x.png ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── Classes │ ├── OYModel.h │ ├── OYModel.m │ ├── OYMultiplePageOneVC.h │ ├── OYMultiplePageOneVC.m │ ├── OYMultiplePageTwoVC.h │ ├── OYMultiplePageTwoVC.m │ ├── OYMultipleTableVC.h │ ├── OYMultipleTableVC.m │ ├── OYPagingTableVC.h │ ├── OYPagingTableVC.m │ ├── OYSingleTableVC.h │ ├── OYSingleTableVC.m │ ├── OYTableViewCell.h │ ├── OYTableViewCell.m │ ├── OYTopViewController.h │ └── OYTopViewController.m ├── Info.plist ├── OYCountDownManager │ ├── OYCountDownManager.h │ └── OYCountDownManager.m └── main.m ├── LICENSE ├── OYCountDownManager.podspec ├── Podfile ├── README.md ├── gif-multiplePage.gif ├── gif-multipleTable.gif ├── gif-paging.gif └── gif-single.gif /.swift-version: -------------------------------------------------------------------------------- 1 | 3.0 2 | -------------------------------------------------------------------------------- /CellCountDown.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 6A082DB61FBBEFC20023BF90 /* OYCountDownManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 6A082DB51FBBEFC20023BF90 /* OYCountDownManager.m */; }; 11 | 6A6ECC441F8B4C18006AA322 /* OYTopViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6A2D90001F8B464F0080EAAA /* OYTopViewController.m */; }; 12 | 6A6ECC451F8B4C1C006AA322 /* OYSingleTableVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 6A2D8FFC1F8B464F0080EAAA /* OYSingleTableVC.m */; }; 13 | 6A6ECC461F8B4C20006AA322 /* OYMultipleTableVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 6A2D8FF81F8B464F0080EAAA /* OYMultipleTableVC.m */; }; 14 | 6A6ECC471F8B4C24006AA322 /* OYPagingTableVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 6A2D8FFA1F8B464F0080EAAA /* OYPagingTableVC.m */; }; 15 | 6A6ECC481F8B4C28006AA322 /* OYTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 6A2D8FFE1F8B464F0080EAAA /* OYTableViewCell.m */; }; 16 | 6A6ECC491F8B4C2B006AA322 /* OYModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 6A2D8FF61F8B464F0080EAAA /* OYModel.m */; }; 17 | 6A6ECC4F1F8B5DE5006AA322 /* OYMultiplePageOneVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 6A6ECC4E1F8B5DE5006AA322 /* OYMultiplePageOneVC.m */; }; 18 | 6A6ECC521F8B5DF1006AA322 /* OYMultiplePageTwoVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 6A6ECC511F8B5DF1006AA322 /* OYMultiplePageTwoVC.m */; }; 19 | 87492F4D1D85A5F90032D7FF /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 87492F4C1D85A5F90032D7FF /* main.m */; }; 20 | 87492F501D85A5F90032D7FF /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 87492F4F1D85A5F90032D7FF /* AppDelegate.m */; }; 21 | 87492F561D85A5F90032D7FF /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 87492F541D85A5F90032D7FF /* Main.storyboard */; }; 22 | 87492F581D85A5F90032D7FF /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 87492F571D85A5F90032D7FF /* Assets.xcassets */; }; 23 | 87492F5B1D85A5F90032D7FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 87492F591D85A5F90032D7FF /* LaunchScreen.storyboard */; }; 24 | EEA6F2E592AA44590B08FD63 /* libPods-CellCountDown.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E56A79A6E1A6C5DD8BB06A2 /* libPods-CellCountDown.a */; }; 25 | /* End PBXBuildFile section */ 26 | 27 | /* Begin PBXFileReference section */ 28 | 08B892AE5C5905A2FAC6CCCE /* Pods-CellCountDown.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CellCountDown.release.xcconfig"; path = "Pods/Target Support Files/Pods-CellCountDown/Pods-CellCountDown.release.xcconfig"; sourceTree = ""; }; 29 | 5E56A79A6E1A6C5DD8BB06A2 /* libPods-CellCountDown.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-CellCountDown.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 30 | 6A082DB41FBBEFC20023BF90 /* OYCountDownManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OYCountDownManager.h; sourceTree = ""; }; 31 | 6A082DB51FBBEFC20023BF90 /* OYCountDownManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OYCountDownManager.m; sourceTree = ""; }; 32 | 6A2D8FF51F8B464F0080EAAA /* OYModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OYModel.h; sourceTree = ""; }; 33 | 6A2D8FF61F8B464F0080EAAA /* OYModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OYModel.m; sourceTree = ""; }; 34 | 6A2D8FF71F8B464F0080EAAA /* OYMultipleTableVC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OYMultipleTableVC.h; sourceTree = ""; }; 35 | 6A2D8FF81F8B464F0080EAAA /* OYMultipleTableVC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OYMultipleTableVC.m; sourceTree = ""; }; 36 | 6A2D8FF91F8B464F0080EAAA /* OYPagingTableVC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OYPagingTableVC.h; sourceTree = ""; }; 37 | 6A2D8FFA1F8B464F0080EAAA /* OYPagingTableVC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OYPagingTableVC.m; sourceTree = ""; }; 38 | 6A2D8FFB1F8B464F0080EAAA /* OYSingleTableVC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OYSingleTableVC.h; sourceTree = ""; }; 39 | 6A2D8FFC1F8B464F0080EAAA /* OYSingleTableVC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OYSingleTableVC.m; sourceTree = ""; }; 40 | 6A2D8FFD1F8B464F0080EAAA /* OYTableViewCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OYTableViewCell.h; sourceTree = ""; }; 41 | 6A2D8FFE1F8B464F0080EAAA /* OYTableViewCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OYTableViewCell.m; sourceTree = ""; }; 42 | 6A2D8FFF1F8B464F0080EAAA /* OYTopViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OYTopViewController.h; sourceTree = ""; }; 43 | 6A2D90001F8B464F0080EAAA /* OYTopViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OYTopViewController.m; sourceTree = ""; }; 44 | 6A6ECC4D1F8B5DE5006AA322 /* OYMultiplePageOneVC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OYMultiplePageOneVC.h; sourceTree = ""; }; 45 | 6A6ECC4E1F8B5DE5006AA322 /* OYMultiplePageOneVC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OYMultiplePageOneVC.m; sourceTree = ""; }; 46 | 6A6ECC501F8B5DF1006AA322 /* OYMultiplePageTwoVC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OYMultiplePageTwoVC.h; sourceTree = ""; }; 47 | 6A6ECC511F8B5DF1006AA322 /* OYMultiplePageTwoVC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OYMultiplePageTwoVC.m; sourceTree = ""; }; 48 | 87492F481D85A5F90032D7FF /* CellCountDown.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = CellCountDown.app; sourceTree = BUILT_PRODUCTS_DIR; }; 49 | 87492F4C1D85A5F90032D7FF /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 50 | 87492F4E1D85A5F90032D7FF /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 51 | 87492F4F1D85A5F90032D7FF /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 52 | 87492F551D85A5F90032D7FF /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 53 | 87492F571D85A5F90032D7FF /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 54 | 87492F5A1D85A5F90032D7FF /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 55 | 87492F5C1D85A5F90032D7FF /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 56 | FE31B69A7C8446D6A10E6984 /* Pods-CellCountDown.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CellCountDown.debug.xcconfig"; path = "Pods/Target Support Files/Pods-CellCountDown/Pods-CellCountDown.debug.xcconfig"; sourceTree = ""; }; 57 | /* End PBXFileReference section */ 58 | 59 | /* Begin PBXFrameworksBuildPhase section */ 60 | 87492F451D85A5F90032D7FF /* Frameworks */ = { 61 | isa = PBXFrameworksBuildPhase; 62 | buildActionMask = 2147483647; 63 | files = ( 64 | EEA6F2E592AA44590B08FD63 /* libPods-CellCountDown.a in Frameworks */, 65 | ); 66 | runOnlyForDeploymentPostprocessing = 0; 67 | }; 68 | /* End PBXFrameworksBuildPhase section */ 69 | 70 | /* Begin PBXGroup section */ 71 | 638470C44ACEDF0712BE4732 /* Pods */ = { 72 | isa = PBXGroup; 73 | children = ( 74 | FE31B69A7C8446D6A10E6984 /* Pods-CellCountDown.debug.xcconfig */, 75 | 08B892AE5C5905A2FAC6CCCE /* Pods-CellCountDown.release.xcconfig */, 76 | ); 77 | name = Pods; 78 | sourceTree = ""; 79 | }; 80 | 6A082DB31FBBEFC20023BF90 /* OYCountDownManager */ = { 81 | isa = PBXGroup; 82 | children = ( 83 | 6A082DB41FBBEFC20023BF90 /* OYCountDownManager.h */, 84 | 6A082DB51FBBEFC20023BF90 /* OYCountDownManager.m */, 85 | ); 86 | path = OYCountDownManager; 87 | sourceTree = ""; 88 | }; 89 | 6A2D8FF41F8B464F0080EAAA /* Classes */ = { 90 | isa = PBXGroup; 91 | children = ( 92 | 6A2D8FFF1F8B464F0080EAAA /* OYTopViewController.h */, 93 | 6A2D90001F8B464F0080EAAA /* OYTopViewController.m */, 94 | 6A2D8FFB1F8B464F0080EAAA /* OYSingleTableVC.h */, 95 | 6A2D8FFC1F8B464F0080EAAA /* OYSingleTableVC.m */, 96 | 6A2D8FF71F8B464F0080EAAA /* OYMultipleTableVC.h */, 97 | 6A2D8FF81F8B464F0080EAAA /* OYMultipleTableVC.m */, 98 | 6A6ECC4D1F8B5DE5006AA322 /* OYMultiplePageOneVC.h */, 99 | 6A6ECC4E1F8B5DE5006AA322 /* OYMultiplePageOneVC.m */, 100 | 6A6ECC501F8B5DF1006AA322 /* OYMultiplePageTwoVC.h */, 101 | 6A6ECC511F8B5DF1006AA322 /* OYMultiplePageTwoVC.m */, 102 | 6A2D8FF91F8B464F0080EAAA /* OYPagingTableVC.h */, 103 | 6A2D8FFA1F8B464F0080EAAA /* OYPagingTableVC.m */, 104 | 6A2D8FFD1F8B464F0080EAAA /* OYTableViewCell.h */, 105 | 6A2D8FFE1F8B464F0080EAAA /* OYTableViewCell.m */, 106 | 6A2D8FF51F8B464F0080EAAA /* OYModel.h */, 107 | 6A2D8FF61F8B464F0080EAAA /* OYModel.m */, 108 | ); 109 | path = Classes; 110 | sourceTree = ""; 111 | }; 112 | 87492F3F1D85A5F90032D7FF = { 113 | isa = PBXGroup; 114 | children = ( 115 | 87492F4A1D85A5F90032D7FF /* CellCountDown */, 116 | 87492F491D85A5F90032D7FF /* Products */, 117 | 638470C44ACEDF0712BE4732 /* Pods */, 118 | E93AE584FA0AB52217AAD010 /* Frameworks */, 119 | ); 120 | sourceTree = ""; 121 | }; 122 | 87492F491D85A5F90032D7FF /* Products */ = { 123 | isa = PBXGroup; 124 | children = ( 125 | 87492F481D85A5F90032D7FF /* CellCountDown.app */, 126 | ); 127 | name = Products; 128 | sourceTree = ""; 129 | }; 130 | 87492F4A1D85A5F90032D7FF /* CellCountDown */ = { 131 | isa = PBXGroup; 132 | children = ( 133 | 87492F4E1D85A5F90032D7FF /* AppDelegate.h */, 134 | 87492F4F1D85A5F90032D7FF /* AppDelegate.m */, 135 | 6A082DB31FBBEFC20023BF90 /* OYCountDownManager */, 136 | 6A2D8FF41F8B464F0080EAAA /* Classes */, 137 | 87492F541D85A5F90032D7FF /* Main.storyboard */, 138 | 87492F571D85A5F90032D7FF /* Assets.xcassets */, 139 | 87492F591D85A5F90032D7FF /* LaunchScreen.storyboard */, 140 | 87492F5C1D85A5F90032D7FF /* Info.plist */, 141 | 87492F4B1D85A5F90032D7FF /* Supporting Files */, 142 | ); 143 | path = CellCountDown; 144 | sourceTree = ""; 145 | }; 146 | 87492F4B1D85A5F90032D7FF /* Supporting Files */ = { 147 | isa = PBXGroup; 148 | children = ( 149 | 87492F4C1D85A5F90032D7FF /* main.m */, 150 | ); 151 | name = "Supporting Files"; 152 | sourceTree = ""; 153 | }; 154 | E93AE584FA0AB52217AAD010 /* Frameworks */ = { 155 | isa = PBXGroup; 156 | children = ( 157 | 5E56A79A6E1A6C5DD8BB06A2 /* libPods-CellCountDown.a */, 158 | ); 159 | name = Frameworks; 160 | sourceTree = ""; 161 | }; 162 | /* End PBXGroup section */ 163 | 164 | /* Begin PBXNativeTarget section */ 165 | 87492F471D85A5F90032D7FF /* CellCountDown */ = { 166 | isa = PBXNativeTarget; 167 | buildConfigurationList = 87492F5F1D85A5F90032D7FF /* Build configuration list for PBXNativeTarget "CellCountDown" */; 168 | buildPhases = ( 169 | 91722083482328656074012D /* [CP] Check Pods Manifest.lock */, 170 | 87492F441D85A5F90032D7FF /* Sources */, 171 | 87492F451D85A5F90032D7FF /* Frameworks */, 172 | 87492F461D85A5F90032D7FF /* Resources */, 173 | 4478A1902B4640261761114C /* [CP] Embed Pods Frameworks */, 174 | 3B3986FCE85BA2D5235520C5 /* [CP] Copy Pods Resources */, 175 | ); 176 | buildRules = ( 177 | ); 178 | dependencies = ( 179 | ); 180 | name = CellCountDown; 181 | productName = CellCountDown; 182 | productReference = 87492F481D85A5F90032D7FF /* CellCountDown.app */; 183 | productType = "com.apple.product-type.application"; 184 | }; 185 | /* End PBXNativeTarget section */ 186 | 187 | /* Begin PBXProject section */ 188 | 87492F401D85A5F90032D7FF /* Project object */ = { 189 | isa = PBXProject; 190 | attributes = { 191 | LastUpgradeCheck = 0720; 192 | ORGANIZATIONNAME = herobin; 193 | TargetAttributes = { 194 | 87492F471D85A5F90032D7FF = { 195 | CreatedOnToolsVersion = 7.2; 196 | }; 197 | }; 198 | }; 199 | buildConfigurationList = 87492F431D85A5F90032D7FF /* Build configuration list for PBXProject "CellCountDown" */; 200 | compatibilityVersion = "Xcode 3.2"; 201 | developmentRegion = English; 202 | hasScannedForEncodings = 0; 203 | knownRegions = ( 204 | en, 205 | Base, 206 | ); 207 | mainGroup = 87492F3F1D85A5F90032D7FF; 208 | productRefGroup = 87492F491D85A5F90032D7FF /* Products */; 209 | projectDirPath = ""; 210 | projectRoot = ""; 211 | targets = ( 212 | 87492F471D85A5F90032D7FF /* CellCountDown */, 213 | ); 214 | }; 215 | /* End PBXProject section */ 216 | 217 | /* Begin PBXResourcesBuildPhase section */ 218 | 87492F461D85A5F90032D7FF /* Resources */ = { 219 | isa = PBXResourcesBuildPhase; 220 | buildActionMask = 2147483647; 221 | files = ( 222 | 87492F5B1D85A5F90032D7FF /* LaunchScreen.storyboard in Resources */, 223 | 87492F581D85A5F90032D7FF /* Assets.xcassets in Resources */, 224 | 87492F561D85A5F90032D7FF /* Main.storyboard in Resources */, 225 | ); 226 | runOnlyForDeploymentPostprocessing = 0; 227 | }; 228 | /* End PBXResourcesBuildPhase section */ 229 | 230 | /* Begin PBXShellScriptBuildPhase section */ 231 | 3B3986FCE85BA2D5235520C5 /* [CP] Copy Pods Resources */ = { 232 | isa = PBXShellScriptBuildPhase; 233 | buildActionMask = 2147483647; 234 | files = ( 235 | ); 236 | inputPaths = ( 237 | ); 238 | name = "[CP] Copy Pods Resources"; 239 | outputPaths = ( 240 | ); 241 | runOnlyForDeploymentPostprocessing = 0; 242 | shellPath = /bin/sh; 243 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-CellCountDown/Pods-CellCountDown-resources.sh\"\n"; 244 | showEnvVarsInLog = 0; 245 | }; 246 | 4478A1902B4640261761114C /* [CP] Embed Pods Frameworks */ = { 247 | isa = PBXShellScriptBuildPhase; 248 | buildActionMask = 2147483647; 249 | files = ( 250 | ); 251 | inputPaths = ( 252 | ); 253 | name = "[CP] Embed Pods Frameworks"; 254 | outputPaths = ( 255 | ); 256 | runOnlyForDeploymentPostprocessing = 0; 257 | shellPath = /bin/sh; 258 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-CellCountDown/Pods-CellCountDown-frameworks.sh\"\n"; 259 | showEnvVarsInLog = 0; 260 | }; 261 | 91722083482328656074012D /* [CP] Check Pods Manifest.lock */ = { 262 | isa = PBXShellScriptBuildPhase; 263 | buildActionMask = 2147483647; 264 | files = ( 265 | ); 266 | inputPaths = ( 267 | ); 268 | name = "[CP] Check Pods Manifest.lock"; 269 | outputPaths = ( 270 | ); 271 | runOnlyForDeploymentPostprocessing = 0; 272 | shellPath = /bin/sh; 273 | shellScript = "diff \"${PODS_ROOT}/../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"; 274 | showEnvVarsInLog = 0; 275 | }; 276 | /* End PBXShellScriptBuildPhase section */ 277 | 278 | /* Begin PBXSourcesBuildPhase section */ 279 | 87492F441D85A5F90032D7FF /* Sources */ = { 280 | isa = PBXSourcesBuildPhase; 281 | buildActionMask = 2147483647; 282 | files = ( 283 | 6A6ECC491F8B4C2B006AA322 /* OYModel.m in Sources */, 284 | 6A6ECC481F8B4C28006AA322 /* OYTableViewCell.m in Sources */, 285 | 6A6ECC4F1F8B5DE5006AA322 /* OYMultiplePageOneVC.m in Sources */, 286 | 6A6ECC471F8B4C24006AA322 /* OYPagingTableVC.m in Sources */, 287 | 6A6ECC461F8B4C20006AA322 /* OYMultipleTableVC.m in Sources */, 288 | 6A6ECC451F8B4C1C006AA322 /* OYSingleTableVC.m in Sources */, 289 | 6A6ECC441F8B4C18006AA322 /* OYTopViewController.m in Sources */, 290 | 6A6ECC521F8B5DF1006AA322 /* OYMultiplePageTwoVC.m in Sources */, 291 | 87492F501D85A5F90032D7FF /* AppDelegate.m in Sources */, 292 | 87492F4D1D85A5F90032D7FF /* main.m in Sources */, 293 | 6A082DB61FBBEFC20023BF90 /* OYCountDownManager.m in Sources */, 294 | ); 295 | runOnlyForDeploymentPostprocessing = 0; 296 | }; 297 | /* End PBXSourcesBuildPhase section */ 298 | 299 | /* Begin PBXVariantGroup section */ 300 | 87492F541D85A5F90032D7FF /* Main.storyboard */ = { 301 | isa = PBXVariantGroup; 302 | children = ( 303 | 87492F551D85A5F90032D7FF /* Base */, 304 | ); 305 | name = Main.storyboard; 306 | sourceTree = ""; 307 | }; 308 | 87492F591D85A5F90032D7FF /* LaunchScreen.storyboard */ = { 309 | isa = PBXVariantGroup; 310 | children = ( 311 | 87492F5A1D85A5F90032D7FF /* Base */, 312 | ); 313 | name = LaunchScreen.storyboard; 314 | sourceTree = ""; 315 | }; 316 | /* End PBXVariantGroup section */ 317 | 318 | /* Begin XCBuildConfiguration section */ 319 | 87492F5D1D85A5F90032D7FF /* Debug */ = { 320 | isa = XCBuildConfiguration; 321 | buildSettings = { 322 | ALWAYS_SEARCH_USER_PATHS = NO; 323 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 324 | CLANG_CXX_LIBRARY = "libc++"; 325 | CLANG_ENABLE_MODULES = YES; 326 | CLANG_ENABLE_OBJC_ARC = YES; 327 | CLANG_WARN_BOOL_CONVERSION = YES; 328 | CLANG_WARN_CONSTANT_CONVERSION = YES; 329 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 330 | CLANG_WARN_EMPTY_BODY = YES; 331 | CLANG_WARN_ENUM_CONVERSION = YES; 332 | CLANG_WARN_INT_CONVERSION = YES; 333 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 334 | CLANG_WARN_UNREACHABLE_CODE = YES; 335 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 336 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 337 | COPY_PHASE_STRIP = NO; 338 | DEBUG_INFORMATION_FORMAT = dwarf; 339 | ENABLE_STRICT_OBJC_MSGSEND = YES; 340 | ENABLE_TESTABILITY = YES; 341 | GCC_C_LANGUAGE_STANDARD = gnu99; 342 | GCC_DYNAMIC_NO_PIC = NO; 343 | GCC_NO_COMMON_BLOCKS = YES; 344 | GCC_OPTIMIZATION_LEVEL = 0; 345 | GCC_PREPROCESSOR_DEFINITIONS = ( 346 | "DEBUG=1", 347 | "$(inherited)", 348 | ); 349 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 350 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 351 | GCC_WARN_UNDECLARED_SELECTOR = YES; 352 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 353 | GCC_WARN_UNUSED_FUNCTION = YES; 354 | GCC_WARN_UNUSED_VARIABLE = YES; 355 | IPHONEOS_DEPLOYMENT_TARGET = 9.2; 356 | MTL_ENABLE_DEBUG_INFO = YES; 357 | ONLY_ACTIVE_ARCH = YES; 358 | SDKROOT = iphoneos; 359 | TARGETED_DEVICE_FAMILY = "1,2"; 360 | }; 361 | name = Debug; 362 | }; 363 | 87492F5E1D85A5F90032D7FF /* Release */ = { 364 | isa = XCBuildConfiguration; 365 | buildSettings = { 366 | ALWAYS_SEARCH_USER_PATHS = NO; 367 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 368 | CLANG_CXX_LIBRARY = "libc++"; 369 | CLANG_ENABLE_MODULES = YES; 370 | CLANG_ENABLE_OBJC_ARC = YES; 371 | CLANG_WARN_BOOL_CONVERSION = YES; 372 | CLANG_WARN_CONSTANT_CONVERSION = YES; 373 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 374 | CLANG_WARN_EMPTY_BODY = YES; 375 | CLANG_WARN_ENUM_CONVERSION = YES; 376 | CLANG_WARN_INT_CONVERSION = YES; 377 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 378 | CLANG_WARN_UNREACHABLE_CODE = YES; 379 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 380 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 381 | COPY_PHASE_STRIP = NO; 382 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 383 | ENABLE_NS_ASSERTIONS = NO; 384 | ENABLE_STRICT_OBJC_MSGSEND = YES; 385 | GCC_C_LANGUAGE_STANDARD = gnu99; 386 | GCC_NO_COMMON_BLOCKS = YES; 387 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 388 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 389 | GCC_WARN_UNDECLARED_SELECTOR = YES; 390 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 391 | GCC_WARN_UNUSED_FUNCTION = YES; 392 | GCC_WARN_UNUSED_VARIABLE = YES; 393 | IPHONEOS_DEPLOYMENT_TARGET = 9.2; 394 | MTL_ENABLE_DEBUG_INFO = NO; 395 | SDKROOT = iphoneos; 396 | TARGETED_DEVICE_FAMILY = "1,2"; 397 | VALIDATE_PRODUCT = YES; 398 | }; 399 | name = Release; 400 | }; 401 | 87492F601D85A5F90032D7FF /* Debug */ = { 402 | isa = XCBuildConfiguration; 403 | baseConfigurationReference = FE31B69A7C8446D6A10E6984 /* Pods-CellCountDown.debug.xcconfig */; 404 | buildSettings = { 405 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 406 | DEVELOPMENT_TEAM = ""; 407 | INFOPLIST_FILE = CellCountDown/Info.plist; 408 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 409 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 410 | PRODUCT_BUNDLE_IDENTIFIER = com.herobin.iOS.CellCountDown; 411 | PRODUCT_NAME = "$(TARGET_NAME)"; 412 | }; 413 | name = Debug; 414 | }; 415 | 87492F611D85A5F90032D7FF /* Release */ = { 416 | isa = XCBuildConfiguration; 417 | baseConfigurationReference = 08B892AE5C5905A2FAC6CCCE /* Pods-CellCountDown.release.xcconfig */; 418 | buildSettings = { 419 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 420 | DEVELOPMENT_TEAM = ""; 421 | INFOPLIST_FILE = CellCountDown/Info.plist; 422 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 423 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 424 | PRODUCT_BUNDLE_IDENTIFIER = com.herobin.iOS.CellCountDown; 425 | PRODUCT_NAME = "$(TARGET_NAME)"; 426 | }; 427 | name = Release; 428 | }; 429 | /* End XCBuildConfiguration section */ 430 | 431 | /* Begin XCConfigurationList section */ 432 | 87492F431D85A5F90032D7FF /* Build configuration list for PBXProject "CellCountDown" */ = { 433 | isa = XCConfigurationList; 434 | buildConfigurations = ( 435 | 87492F5D1D85A5F90032D7FF /* Debug */, 436 | 87492F5E1D85A5F90032D7FF /* Release */, 437 | ); 438 | defaultConfigurationIsVisible = 0; 439 | defaultConfigurationName = Release; 440 | }; 441 | 87492F5F1D85A5F90032D7FF /* Build configuration list for PBXNativeTarget "CellCountDown" */ = { 442 | isa = XCConfigurationList; 443 | buildConfigurations = ( 444 | 87492F601D85A5F90032D7FF /* Debug */, 445 | 87492F611D85A5F90032D7FF /* Release */, 446 | ); 447 | defaultConfigurationIsVisible = 0; 448 | defaultConfigurationName = Release; 449 | }; 450 | /* End XCConfigurationList section */ 451 | }; 452 | rootObject = 87492F401D85A5F90032D7FF /* Project object */; 453 | } 454 | -------------------------------------------------------------------------------- /CellCountDown.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /CellCountDown.xcodeproj/project.xcworkspace/xcuserdata/herobin.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/herobin22/OYCountDownManager/ab76d5eb8344791a12d2395c1f99033b7fd44871/CellCountDown.xcodeproj/project.xcworkspace/xcuserdata/herobin.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /CellCountDown.xcodeproj/xcuserdata/herobin.xcuserdatad/xcschemes/CellCountDown.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /CellCountDown.xcodeproj/xcuserdata/herobin.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | CellCountDown.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 87492F471D85A5F90032D7FF 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /CellCountDown/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // CellCountDown 4 | // 5 | // Created by herobin on 16/9/11. 6 | // Copyright © 2016年 herobin. 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 | -------------------------------------------------------------------------------- /CellCountDown/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // CellCountDown 4 | // 5 | // Created by herobin on 16/9/11. 6 | // Copyright © 2016年 herobin. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | - (void)applicationWillResignActive:(UIApplication *)application { 24 | // 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. 25 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 26 | } 27 | 28 | - (void)applicationDidEnterBackground:(UIApplication *)application { 29 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 31 | } 32 | 33 | - (void)applicationWillEnterForeground:(UIApplication *)application { 34 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 35 | } 36 | 37 | - (void)applicationDidBecomeActive:(UIApplication *)application { 38 | // 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. 39 | } 40 | 41 | - (void)applicationWillTerminate:(UIApplication *)application { 42 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /CellCountDown/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "icon-20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "icon-20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "icon-29@2x.png", 19 | "scale" : "2x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "icon-29@3x.png", 25 | "scale" : "3x" 26 | }, 27 | { 28 | "size" : "40x40", 29 | "idiom" : "iphone", 30 | "filename" : "icon-40@2x.png", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "icon-40@3x.png", 37 | "scale" : "3x" 38 | }, 39 | { 40 | "size" : "60x60", 41 | "idiom" : "iphone", 42 | "filename" : "icon-60@2x.png", 43 | "scale" : "2x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "icon-60@3x.png", 49 | "scale" : "3x" 50 | }, 51 | { 52 | "idiom" : "ios-marketing", 53 | "size" : "1024x1024", 54 | "scale" : "1x" 55 | } 56 | ], 57 | "info" : { 58 | "version" : 1, 59 | "author" : "xcode" 60 | } 61 | } -------------------------------------------------------------------------------- /CellCountDown/Assets.xcassets/AppIcon.appiconset/icon-20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/herobin22/OYCountDownManager/ab76d5eb8344791a12d2395c1f99033b7fd44871/CellCountDown/Assets.xcassets/AppIcon.appiconset/icon-20@2x.png -------------------------------------------------------------------------------- /CellCountDown/Assets.xcassets/AppIcon.appiconset/icon-20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/herobin22/OYCountDownManager/ab76d5eb8344791a12d2395c1f99033b7fd44871/CellCountDown/Assets.xcassets/AppIcon.appiconset/icon-20@3x.png -------------------------------------------------------------------------------- /CellCountDown/Assets.xcassets/AppIcon.appiconset/icon-29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/herobin22/OYCountDownManager/ab76d5eb8344791a12d2395c1f99033b7fd44871/CellCountDown/Assets.xcassets/AppIcon.appiconset/icon-29@2x.png -------------------------------------------------------------------------------- /CellCountDown/Assets.xcassets/AppIcon.appiconset/icon-29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/herobin22/OYCountDownManager/ab76d5eb8344791a12d2395c1f99033b7fd44871/CellCountDown/Assets.xcassets/AppIcon.appiconset/icon-29@3x.png -------------------------------------------------------------------------------- /CellCountDown/Assets.xcassets/AppIcon.appiconset/icon-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/herobin22/OYCountDownManager/ab76d5eb8344791a12d2395c1f99033b7fd44871/CellCountDown/Assets.xcassets/AppIcon.appiconset/icon-40@2x.png -------------------------------------------------------------------------------- /CellCountDown/Assets.xcassets/AppIcon.appiconset/icon-40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/herobin22/OYCountDownManager/ab76d5eb8344791a12d2395c1f99033b7fd44871/CellCountDown/Assets.xcassets/AppIcon.appiconset/icon-40@3x.png -------------------------------------------------------------------------------- /CellCountDown/Assets.xcassets/AppIcon.appiconset/icon-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/herobin22/OYCountDownManager/ab76d5eb8344791a12d2395c1f99033b7fd44871/CellCountDown/Assets.xcassets/AppIcon.appiconset/icon-60@2x.png -------------------------------------------------------------------------------- /CellCountDown/Assets.xcassets/AppIcon.appiconset/icon-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/herobin22/OYCountDownManager/ab76d5eb8344791a12d2395c1f99033b7fd44871/CellCountDown/Assets.xcassets/AppIcon.appiconset/icon-60@3x.png -------------------------------------------------------------------------------- /CellCountDown/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 | -------------------------------------------------------------------------------- /CellCountDown/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 | 35 | 46 | 57 | 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 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | -------------------------------------------------------------------------------- /CellCountDown/Classes/OYModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // Model.h 3 | // CellCountDown 4 | // 5 | // Created by herobin on 16/9/11. 6 | // Copyright © 2016年 herobin. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface OYModel : NSObject 12 | 13 | @property (nonatomic, copy) NSString *title; 14 | @property (nonatomic, assign) NSInteger count; 15 | 16 | /// 表示时间已经到了 17 | @property (nonatomic, assign) BOOL timeOut; 18 | 19 | /// 倒计时源 20 | @property (nonatomic, copy) NSString *countDownSource; 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /CellCountDown/Classes/OYModel.m: -------------------------------------------------------------------------------- 1 | // 2 | // Model.m 3 | // CellCountDown 4 | // 5 | // Created by herobin on 16/9/11. 6 | // Copyright © 2016年 herobin. All rights reserved. 7 | // 8 | 9 | #import "OYModel.h" 10 | 11 | @implementation OYModel 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /CellCountDown/Classes/OYMultiplePageOneVC.h: -------------------------------------------------------------------------------- 1 | // 2 | // OYMultipPageOneVC.h 3 | // CellCountDown 4 | // 5 | // Created by Gold on 2017/10/9. 6 | // Copyright © 2017年 herobin. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface OYMultiplePageOneVC : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /CellCountDown/Classes/OYMultiplePageOneVC.m: -------------------------------------------------------------------------------- 1 | // 2 | // OYMultipPageOneVC.m 3 | // CellCountDown 4 | // 5 | // Created by Gold on 2017/10/9. 6 | // Copyright © 2017年 herobin. All rights reserved. 7 | // 8 | 9 | #import "OYMultiplePageOneVC.h" 10 | #import "OYTableViewCell.h" 11 | #import "OYCountDownManager.h" 12 | 13 | NSString *const OYMultiplePageSource1 = @"OYMultiplePageSource1"; 14 | 15 | @interface OYMultiplePageOneVC () 16 | 17 | @property (nonatomic, strong) UITableView *tableView; 18 | @property (nonatomic, strong) NSArray *dataSource; 19 | 20 | @end 21 | 22 | @implementation OYMultiplePageOneVC 23 | 24 | - (void)viewDidLoad { 25 | [super viewDidLoad]; 26 | 27 | self.tabBarController.title = @"页面1倒计时"; 28 | self.view.backgroundColor = [UIColor whiteColor]; 29 | [self.view addSubview:self.tableView]; 30 | 31 | // 启动倒计时管理 32 | [kCountDownManager start]; 33 | // 增加倒计时源 34 | [kCountDownManager addSourceWithIdentifier:OYMultiplePageSource1]; 35 | } 36 | 37 | #pragma mark - UITableViewDataSource, UITableViewDelegate 38 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 39 | return 1; 40 | } 41 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 42 | return self.dataSource.count; 43 | } 44 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 45 | OYTableViewCell *cell = (OYTableViewCell *)[tableView dequeueReusableCellWithIdentifier:OYTableViewCellID]; 46 | // 传递模型 47 | OYModel *model = self.dataSource[indexPath.row]; 48 | cell.model = model; 49 | [cell setCountDownZero:^(OYModel *timeOutModel){ 50 | // 回调 51 | if (!timeOutModel.timeOut) { 52 | NSLog(@"MultiplePageTwoVC--%@--时间到了", timeOutModel.title); 53 | } 54 | // 标志 55 | timeOutModel.timeOut = YES; 56 | }]; 57 | return cell; 58 | } 59 | 60 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { 61 | return 50; 62 | } 63 | 64 | #pragma mark - 刷新数据 65 | - (void)reloadData { 66 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 67 | // 模拟网络请求 68 | self.dataSource = nil; 69 | // 调用reload 70 | [kCountDownManager reloadSourceWithIdentifier:OYMultiplePageSource1]; 71 | // 刷新 72 | [self.tableView reloadData]; 73 | // 停止刷新 74 | [self.tableView.refreshControl endRefreshing]; 75 | }); 76 | } 77 | 78 | #pragma mark - Getter 79 | - (UITableView *)tableView { 80 | if (!_tableView) { 81 | _tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain]; 82 | _tableView.dataSource = self; 83 | _tableView.delegate = self; 84 | _tableView.refreshControl = [[UIRefreshControl alloc] init]; 85 | [_tableView.refreshControl addTarget:self action:@selector(reloadData) forControlEvents:UIControlEventValueChanged]; 86 | [_tableView registerClass:NSClassFromString(OYTableViewCellID) forCellReuseIdentifier:OYTableViewCellID]; 87 | } 88 | return _tableView; 89 | } 90 | 91 | - (NSArray *)dataSource { 92 | if (_dataSource == nil) { 93 | NSMutableArray *arrM = [NSMutableArray array]; 94 | for (NSInteger i=0; i<50; i++) { 95 | // 模拟从服务器取得数据 -- 例如:服务器返回的数据为剩余时间数 96 | NSInteger count = arc4random_uniform(100); //生成0-100之间的随机正整数 97 | OYModel *model = [[OYModel alloc]init]; 98 | model.count = count; 99 | model.title = [NSString stringWithFormat:@"第%zd条数据", i]; 100 | model.countDownSource = OYMultiplePageSource1; 101 | [arrM addObject:model]; 102 | } 103 | _dataSource = arrM.copy; 104 | } 105 | return _dataSource; 106 | } 107 | 108 | - (void)dealloc { 109 | [kCountDownManager removeSourceWithIdentifier:OYMultiplePageSource1]; 110 | [kCountDownManager invalidate]; 111 | } 112 | 113 | @end 114 | -------------------------------------------------------------------------------- /CellCountDown/Classes/OYMultiplePageTwoVC.h: -------------------------------------------------------------------------------- 1 | // 2 | // OYMultipPageTwoVC.h 3 | // CellCountDown 4 | // 5 | // Created by Gold on 2017/10/9. 6 | // Copyright © 2017年 herobin. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface OYMultiplePageTwoVC : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /CellCountDown/Classes/OYMultiplePageTwoVC.m: -------------------------------------------------------------------------------- 1 | // 2 | // OYMultipPageTwoVC.m 3 | // CellCountDown 4 | // 5 | // Created by Gold on 2017/10/9. 6 | // Copyright © 2017年 herobin. All rights reserved. 7 | // 8 | 9 | #import "OYMultiplePageTwoVC.h" 10 | #import "OYTableViewCell.h" 11 | #import "OYCountDownManager.h" 12 | 13 | NSString *const OYMultiplePageSource2 = @"OYMultiplePageSource2"; 14 | 15 | @interface OYMultiplePageTwoVC () 16 | 17 | @property (nonatomic, strong) UITableView *tableView; 18 | @property (nonatomic, strong) NSArray *dataSource; 19 | 20 | @end 21 | 22 | @implementation OYMultiplePageTwoVC 23 | 24 | - (void)viewDidLoad { 25 | [super viewDidLoad]; 26 | 27 | self.tabBarController.title = @"页面2倒计时"; 28 | self.view.backgroundColor = [UIColor whiteColor]; 29 | [self.view addSubview:self.tableView]; 30 | 31 | // 启动倒计时管理 32 | [kCountDownManager start]; 33 | // 增加倒计时源 34 | [kCountDownManager addSourceWithIdentifier:OYMultiplePageSource2]; 35 | } 36 | 37 | #pragma mark - UITableViewDataSource, UITableViewDelegate 38 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 39 | return 1; 40 | } 41 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 42 | return self.dataSource.count; 43 | } 44 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 45 | OYTableViewCell *cell = (OYTableViewCell *)[tableView dequeueReusableCellWithIdentifier:OYTableViewCellID]; 46 | // 传递模型 47 | OYModel *model = self.dataSource[indexPath.row]; 48 | cell.model = model; 49 | [cell setCountDownZero:^(OYModel *timeOutModel){ 50 | // 回调 51 | if (!timeOutModel.timeOut) { 52 | NSLog(@"MultiplePageTwoVC--%@--时间到了", timeOutModel.title); 53 | } 54 | // 标志 55 | timeOutModel.timeOut = YES; 56 | }]; 57 | return cell; 58 | } 59 | 60 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { 61 | return 50; 62 | } 63 | 64 | #pragma mark - 刷新数据 65 | - (void)reloadData { 66 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 67 | // 模拟网络请求 68 | self.dataSource = nil; 69 | // 调用reload 70 | [kCountDownManager reloadSourceWithIdentifier:OYMultiplePageSource2]; 71 | // 刷新 72 | [self.tableView reloadData]; 73 | // 停止刷新 74 | [self.tableView.refreshControl endRefreshing]; 75 | }); 76 | } 77 | 78 | #pragma mark - Getter 79 | - (UITableView *)tableView { 80 | if (!_tableView) { 81 | _tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain]; 82 | _tableView.dataSource = self; 83 | _tableView.delegate = self; 84 | _tableView.refreshControl = [[UIRefreshControl alloc] init]; 85 | [_tableView.refreshControl addTarget:self action:@selector(reloadData) forControlEvents:UIControlEventValueChanged]; 86 | [_tableView registerClass:NSClassFromString(OYTableViewCellID) forCellReuseIdentifier:OYTableViewCellID]; 87 | } 88 | return _tableView; 89 | } 90 | 91 | - (NSArray *)dataSource { 92 | if (_dataSource == nil) { 93 | NSMutableArray *arrM = [NSMutableArray array]; 94 | for (NSInteger i=0; i<50; i++) { 95 | // 模拟从服务器取得数据 -- 例如:服务器返回的数据为剩余时间数 96 | NSInteger count = arc4random_uniform(100); //生成0-100之间的随机正整数 97 | OYModel *model = [[OYModel alloc]init]; 98 | model.count = count; 99 | model.title = [NSString stringWithFormat:@"第%zd条数据", i]; 100 | model.countDownSource = OYMultiplePageSource2; 101 | [arrM addObject:model]; 102 | } 103 | _dataSource = arrM.copy; 104 | } 105 | return _dataSource; 106 | } 107 | 108 | - (void)dealloc { 109 | [kCountDownManager removeSourceWithIdentifier:OYMultiplePageSource2]; 110 | [kCountDownManager invalidate]; 111 | } 112 | 113 | 114 | @end 115 | -------------------------------------------------------------------------------- /CellCountDown/Classes/OYMultipleTableVC.h: -------------------------------------------------------------------------------- 1 | // 2 | // OYMultipleTableVC.h 3 | // CellCountDown 4 | // 5 | // Created by herobin on 2017/9/30. 6 | // Copyright © 2017年 herobin. All rights reserved. 7 | // 8 | 9 | /** 一个页面有多个列表倒计时 */ 10 | 11 | #import 12 | 13 | @interface OYMultipleTableVC : UIViewController 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /CellCountDown/Classes/OYMultipleTableVC.m: -------------------------------------------------------------------------------- 1 | // 2 | // OYMultipleTableVC.m 3 | // CellCountDown 4 | // 5 | // Created by herobin on 2017/9/30. 6 | // Copyright © 2017年 herobin. All rights reserved. 7 | // 8 | 9 | #import "OYMultipleTableVC.h" 10 | #import "OYTableViewCell.h" 11 | #import "OYCountDownManager.h" 12 | 13 | NSString *const OYMultipleTableSource1 = @"OYMultipleTableSource1"; 14 | NSString *const OYMultipleTableSource2 = @"OYMultipleTableSource2"; 15 | 16 | @interface OYMultipleTableVC () 17 | 18 | @property (nonatomic, strong) UITableView *tableView; 19 | @property (nonatomic, strong) NSArray *dataSource; 20 | @property (nonatomic, strong) UITableView *tableView2; 21 | @property (nonatomic, strong) NSArray *dataSource2; 22 | 23 | @end 24 | 25 | @implementation OYMultipleTableVC 26 | 27 | - (void)viewDidLoad { 28 | [super viewDidLoad]; 29 | // Do any additional setup after loading the view. 30 | self.title = @"多个列表倒计时"; 31 | self.view.backgroundColor = [UIColor grayColor]; 32 | 33 | [self.view addSubview:self.tableView]; 34 | [self.view addSubview:self.tableView2]; 35 | // 启动倒计时管理 36 | [kCountDownManager start]; 37 | // 增加倒计时源 38 | [kCountDownManager addSourceWithIdentifier:OYMultipleTableSource1]; 39 | [kCountDownManager addSourceWithIdentifier:OYMultipleTableSource2]; 40 | } 41 | 42 | #pragma mark - UITableViewDelegate, UITableViewDataSource 43 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 44 | if (tableView == self.tableView) { 45 | return self.dataSource.count; 46 | } 47 | return self.dataSource2.count; 48 | } 49 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 50 | NSArray *dataSource; 51 | if (tableView == self.tableView) { 52 | dataSource = self.dataSource; 53 | }else { 54 | dataSource = self.dataSource2; 55 | } 56 | OYTableViewCell *cell = (OYTableViewCell *)[tableView dequeueReusableCellWithIdentifier:OYTableViewCellID]; 57 | // 传递模型 58 | OYModel *model = dataSource[indexPath.row]; 59 | cell.model = model; 60 | [cell setCountDownZero:^(OYModel *timeOutModel){ 61 | // 回调 62 | if (!timeOutModel.timeOut) { 63 | NSLog(@"%@--%@--时间到了", timeOutModel.countDownSource, timeOutModel.title); 64 | } 65 | // 标志 66 | timeOutModel.timeOut = YES; 67 | }]; 68 | return cell; 69 | } 70 | 71 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { 72 | return 50; 73 | } 74 | 75 | #pragma mark - 刷新数据 76 | - (void)reloadData { 77 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 78 | // 模拟网络请求 79 | self.dataSource = nil; 80 | // 调用reload, 指定identifier 81 | [kCountDownManager reloadSourceWithIdentifier:OYMultipleTableSource1]; 82 | // 刷新 83 | [self.tableView reloadData]; 84 | // 停止刷新 85 | [self.tableView.refreshControl endRefreshing]; 86 | }); 87 | } 88 | 89 | - (void)reloadData2 { 90 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 91 | // 模拟网络请求 92 | self.dataSource2 = nil; 93 | // 调用reload, 指定identifier 94 | [kCountDownManager reloadSourceWithIdentifier:OYMultipleTableSource2]; 95 | // 刷新 96 | [self.tableView2 reloadData]; 97 | // 停止刷新 98 | [self.tableView2.refreshControl endRefreshing]; 99 | }); 100 | } 101 | 102 | #pragma mark - Getter 103 | - (UITableView *)tableView { 104 | if (!_tableView) { 105 | _tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height/2) style:UITableViewStylePlain]; 106 | _tableView.dataSource = self; 107 | _tableView.delegate = self; 108 | _tableView.refreshControl = [[UIRefreshControl alloc] init]; 109 | [_tableView.refreshControl addTarget:self action:@selector(reloadData) forControlEvents:UIControlEventValueChanged]; 110 | [_tableView registerClass:NSClassFromString(OYTableViewCellID) forCellReuseIdentifier:OYTableViewCellID]; 111 | } 112 | return _tableView; 113 | } 114 | 115 | - (NSArray *)dataSource { 116 | if (_dataSource == nil) { 117 | NSMutableArray *arrM = [NSMutableArray array]; 118 | for (NSInteger i=0; i<50; i++) { 119 | // 模拟从服务器取得数据 -- 例如:服务器返回的数据为剩余时间数 120 | NSInteger count = arc4random_uniform(100); //生成0-100之间的随机正整数 121 | OYModel *model = [[OYModel alloc]init]; 122 | model.count = count; 123 | model.title = [NSString stringWithFormat:@"第%zd条数据", i]; 124 | model.countDownSource = OYMultipleTableSource1; 125 | [arrM addObject:model]; 126 | } 127 | _dataSource = arrM.copy; 128 | } 129 | return _dataSource; 130 | } 131 | 132 | - (UITableView *)tableView2 { 133 | if (!_tableView2) { 134 | _tableView2 = [[UITableView alloc] initWithFrame:CGRectMake(0, self.view.bounds.size.height/2+50, self.view.bounds.size.width, self.view.bounds.size.height/2 - 50) style:UITableViewStylePlain]; 135 | _tableView2.dataSource = self; 136 | _tableView2.delegate = self; 137 | _tableView2.refreshControl = [[UIRefreshControl alloc] init]; 138 | [_tableView2.refreshControl addTarget:self action:@selector(reloadData2) forControlEvents:UIControlEventValueChanged]; 139 | [_tableView2 registerClass:NSClassFromString(OYTableViewCellID) forCellReuseIdentifier:OYTableViewCellID]; 140 | } 141 | return _tableView2; 142 | 143 | } 144 | 145 | - (NSArray *)dataSource2 { 146 | if (_dataSource2 == nil) { 147 | NSMutableArray *arrM = [NSMutableArray array]; 148 | for (NSInteger i=0; i<50; i++) { 149 | // 模拟从服务器取得数据 -- 例如:服务器返回的数据为剩余时间数 150 | NSInteger count = arc4random_uniform(100); //生成0-100之间的随机正整数 151 | OYModel *model = [[OYModel alloc]init]; 152 | model.count = count; 153 | model.title = [NSString stringWithFormat:@"第%zd条数据", i]; 154 | model.countDownSource = OYMultipleTableSource2; 155 | [arrM addObject:model]; 156 | } 157 | _dataSource2 = arrM.copy; 158 | } 159 | return _dataSource2; 160 | } 161 | 162 | - (void)dealloc { 163 | [kCountDownManager removeAllSource]; 164 | [kCountDownManager invalidate]; 165 | } 166 | 167 | @end 168 | -------------------------------------------------------------------------------- /CellCountDown/Classes/OYPagingTableVC.h: -------------------------------------------------------------------------------- 1 | // 2 | // OYPagingTableVC.h 3 | // CellCountDown 4 | // 5 | // Created by herobin on 2017/9/30. 6 | // Copyright © 2017年 herobin. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface OYPagingTableVC : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /CellCountDown/Classes/OYPagingTableVC.m: -------------------------------------------------------------------------------- 1 | // 2 | // OYPagingTableVC.m 3 | // CellCountDown 4 | // 5 | // Created by herobin on 2017/9/30. 6 | // Copyright © 2017年 herobin. All rights reserved. 7 | // 8 | 9 | #import "OYPagingTableVC.h" 10 | #import "OYCountDownManager.h" 11 | #import "OYTableViewCell.h" 12 | #import "MJRefresh.h" 13 | 14 | @interface OYPagingTableVC () 15 | 16 | @property (nonatomic, strong) UITableView *tableView; 17 | @property (nonatomic, strong) NSMutableArray *dataSource; 18 | 19 | @property (nonatomic, assign) NSInteger pageNumber; 20 | 21 | @end 22 | 23 | @implementation OYPagingTableVC 24 | 25 | - (void)viewDidLoad { 26 | [super viewDidLoad]; 27 | 28 | self.title = @"分页列表倒计时"; 29 | self.view.backgroundColor = [UIColor whiteColor]; 30 | [self.view addSubview:self.tableView]; 31 | 32 | [self setupRefresh]; 33 | 34 | // 启动倒计时管理 35 | [kCountDownManager start]; 36 | } 37 | 38 | #pragma mark - UITableViewDataSource, UITableViewDelegate 39 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 40 | return 1; 41 | } 42 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 43 | return self.dataSource.count; 44 | } 45 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 46 | OYTableViewCell *cell = (OYTableViewCell *)[tableView dequeueReusableCellWithIdentifier:OYTableViewCellID]; 47 | // 传递模型 48 | OYModel *model = self.dataSource[indexPath.row]; 49 | cell.model = model; 50 | [cell setCountDownZero:^(OYModel *timeOutModel){ 51 | // 回调 52 | if (!timeOutModel.timeOut) { 53 | NSLog(@"%@--%@--时间到了", timeOutModel.countDownSource, timeOutModel.title); 54 | } 55 | // 标志 56 | timeOutModel.timeOut = YES; 57 | }]; 58 | return cell; 59 | } 60 | 61 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { 62 | return 50; 63 | } 64 | 65 | #pragma mark - 刷新数据 66 | - (void)loadData { 67 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 68 | // 模拟网络请求 69 | if (self.pageNumber == 0) { 70 | [self.dataSource removeAllObjects]; 71 | } 72 | for (NSInteger i=0; i<10; i++) { 73 | // 模拟从服务器取得数据 -- 例如:服务器返回的数据为剩余时间数 74 | NSInteger count = arc4random_uniform(100); //生成0-100之间的随机正整数 75 | OYModel *model = [[OYModel alloc]init]; 76 | model.count = count; 77 | model.title = [NSString stringWithFormat:@"第%zd条数据", self.pageNumber*10+i]; 78 | model.countDownSource = [NSString stringWithFormat:@"OYPagingSource%zd", self.pageNumber]; 79 | [self.dataSource addObject:model]; 80 | } 81 | // 增加倒计时源 82 | [kCountDownManager addSourceWithIdentifier:[NSString stringWithFormat:@"OYPagingSource%zd", self.pageNumber]]; 83 | // 刷新 84 | [self.tableView reloadData]; 85 | // 停止刷新 86 | [self endRefreshing]; 87 | }); 88 | } 89 | 90 | #pragma mark - SetupRefresh 91 | - (void)setupRefresh { 92 | MJRefreshNormalHeader *header = [MJRefreshNormalHeader headerWithRefreshingTarget:self refreshingAction:@selector(headerRefresh)]; 93 | self.tableView.mj_header = header; 94 | 95 | MJRefreshAutoNormalFooter *footer = [MJRefreshAutoNormalFooter footerWithRefreshingTarget:self refreshingAction:@selector(footerRefresh)]; 96 | self.tableView.mj_footer = footer; 97 | 98 | // 马上刷新一次 99 | [header beginRefreshing]; 100 | } 101 | 102 | - (void)headerRefresh { 103 | self.pageNumber = 0; 104 | [self loadData]; 105 | } 106 | 107 | - (void)footerRefresh { 108 | self.pageNumber ++; 109 | [self loadData]; 110 | } 111 | 112 | - (void)endRefreshing { 113 | [self.tableView.mj_header endRefreshing]; 114 | [self.tableView.mj_footer endRefreshing]; 115 | } 116 | 117 | #pragma mark - Getter 118 | - (UITableView *)tableView { 119 | if (!_tableView) { 120 | _tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain]; 121 | _tableView.dataSource = self; 122 | _tableView.delegate = self; 123 | [_tableView registerClass:NSClassFromString(OYTableViewCellID) forCellReuseIdentifier:OYTableViewCellID]; 124 | } 125 | return _tableView; 126 | } 127 | 128 | - (NSArray *)dataSource { 129 | if (_dataSource == nil) { 130 | _dataSource = [NSMutableArray array]; 131 | } 132 | return _dataSource; 133 | } 134 | 135 | - (void)dealloc { 136 | [kCountDownManager removeAllSource]; 137 | [kCountDownManager invalidate]; 138 | } 139 | 140 | @end 141 | -------------------------------------------------------------------------------- /CellCountDown/Classes/OYSingleTableVC.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // CellCountDown 4 | // 5 | // Created by herobin on 16/9/11. 6 | // Copyright © 2016年 herobin. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface OYSingleTableVC : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /CellCountDown/Classes/OYSingleTableVC.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // CellCountDown 4 | // 5 | // Created by herobin on 16/9/11. 6 | // Copyright © 2016年 herobin. All rights reserved. 7 | // 8 | 9 | #import "OYSingleTableVC.h" 10 | #import "OYModel.h" 11 | #import "OYTableViewCell.h" 12 | #import "OYCountDownManager.h" 13 | 14 | @interface OYSingleTableVC () 15 | 16 | @property (nonatomic, strong) UITableView *tableView; 17 | @property (nonatomic, strong) NSArray *dataSource; 18 | 19 | @end 20 | 21 | @implementation OYSingleTableVC 22 | 23 | - (void)viewDidLoad { 24 | [super viewDidLoad]; 25 | 26 | self.title = @"单个列表倒计时"; 27 | self.view.backgroundColor = [UIColor whiteColor]; 28 | [self.view addSubview:self.tableView]; 29 | 30 | // 启动倒计时管理 31 | [kCountDownManager start]; 32 | } 33 | 34 | #pragma mark - UITableViewDataSource, UITableViewDelegate 35 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 36 | return 1; 37 | } 38 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 39 | return self.dataSource.count; 40 | } 41 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 42 | OYTableViewCell *cell = (OYTableViewCell *)[tableView dequeueReusableCellWithIdentifier:OYTableViewCellID]; 43 | // 传递模型 44 | OYModel *model = self.dataSource[indexPath.row]; 45 | cell.model = model; 46 | [cell setCountDownZero:^(OYModel *timeOutModel){ 47 | // 回调 48 | if (!timeOutModel.timeOut) { 49 | NSLog(@"SingleTableVC--%@--时间到了", timeOutModel.title); 50 | } 51 | // 标志 52 | timeOutModel.timeOut = YES; 53 | }]; 54 | return cell; 55 | } 56 | 57 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { 58 | return 50; 59 | } 60 | 61 | #pragma mark - 刷新数据 62 | - (void)reloadData { 63 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 64 | // 模拟网络请求 65 | self.dataSource = nil; 66 | // 调用reload 67 | [kCountDownManager reload]; 68 | // 刷新 69 | [self.tableView reloadData]; 70 | // 停止刷新 71 | [self.tableView.refreshControl endRefreshing]; 72 | }); 73 | } 74 | 75 | #pragma mark - Getter 76 | - (UITableView *)tableView { 77 | if (!_tableView) { 78 | _tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain]; 79 | _tableView.dataSource = self; 80 | _tableView.delegate = self; 81 | _tableView.refreshControl = [[UIRefreshControl alloc] init]; 82 | [_tableView.refreshControl addTarget:self action:@selector(reloadData) forControlEvents:UIControlEventValueChanged]; 83 | [_tableView registerClass:NSClassFromString(OYTableViewCellID) forCellReuseIdentifier:OYTableViewCellID]; 84 | } 85 | return _tableView; 86 | } 87 | 88 | - (NSArray *)dataSource { 89 | if (_dataSource == nil) { 90 | NSMutableArray *arrM = [NSMutableArray array]; 91 | for (NSInteger i=0; i<50; i++) { 92 | // 模拟从服务器取得数据 -- 例如:服务器返回的数据为剩余时间数 93 | NSInteger count = arc4random_uniform(100); //生成0-100之间的随机正整数 94 | OYModel *model = [[OYModel alloc]init]; 95 | model.count = count; 96 | model.title = [NSString stringWithFormat:@"第%zd条数据", i]; 97 | [arrM addObject:model]; 98 | } 99 | _dataSource = arrM.copy; 100 | } 101 | return _dataSource; 102 | } 103 | 104 | - (void)dealloc { 105 | // 废除定时器 106 | [kCountDownManager invalidate]; 107 | // 清空时间差 108 | [kCountDownManager reload]; 109 | } 110 | 111 | @end 112 | -------------------------------------------------------------------------------- /CellCountDown/Classes/OYTableViewCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // TableViewCell.h 3 | // CellCountDown 4 | // 5 | // Created by herobin on 16/9/11. 6 | // Copyright © 2016年 herobin. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "OYModel.h" 11 | extern NSString *const OYTableViewCellID; 12 | 13 | @interface OYTableViewCell : UITableViewCell 14 | 15 | @property (nonatomic, strong) OYModel *model; 16 | 17 | /// 倒计时到0时回调 18 | @property (nonatomic, copy) void(^countDownZero)(OYModel *); 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /CellCountDown/Classes/OYTableViewCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // TableViewCell.m 3 | // CellCountDown 4 | // 5 | // Created by herobin on 16/9/11. 6 | // Copyright © 2016年 herobin. All rights reserved. 7 | // 8 | 9 | #import "OYTableViewCell.h" 10 | #import "OYCountDownManager.h" 11 | #import "OYModel.h" 12 | NSString *const OYTableViewCellID = @"OYTableViewCell"; 13 | 14 | @interface OYTableViewCell () 15 | 16 | @end 17 | 18 | @implementation OYTableViewCell 19 | 20 | // 代码创建 21 | - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { 22 | if (self = [super initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:reuseIdentifier]) { 23 | // 监听通知 24 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(countDownNotification) name:OYCountDownNotification object:nil]; 25 | } 26 | return self; 27 | } 28 | 29 | // xib创建 30 | - (instancetype)initWithCoder:(NSCoder *)coder 31 | { 32 | self = [super initWithCoder:coder]; 33 | if (self) { 34 | // 监听通知 35 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(countDownNotification) name:OYCountDownNotification object:nil]; 36 | } 37 | return self; 38 | } 39 | 40 | #pragma mark - 倒计时通知回调 41 | - (void)countDownNotification { 42 | /// 判断是否需要倒计时 -- 可能有的cell不需要倒计时,根据真实需求来进行判断 43 | if (0) { 44 | return; 45 | } 46 | /// 计算倒计时 47 | OYModel *model = self.model; 48 | NSInteger timeInterval; 49 | if (model.countDownSource) { 50 | timeInterval = [kCountDownManager timeIntervalWithIdentifier:model.countDownSource]; 51 | }else { 52 | timeInterval = kCountDownManager.timeInterval; 53 | } 54 | NSInteger countDown = model.count - timeInterval; 55 | /// 当倒计时到了进行回调 56 | if (countDown <= 0) { 57 | self.detailTextLabel.text = @"活动开始"; 58 | // 回调给控制器 59 | if (self.countDownZero) { 60 | self.countDownZero(model); 61 | } 62 | return; 63 | } 64 | /// 重新赋值 65 | self.detailTextLabel.text = [NSString stringWithFormat:@"倒计时%02zd:%02zd:%02zd", countDown/3600, (countDown/60)%60, countDown%60]; 66 | } 67 | 68 | /// 重写setter方法 69 | - (void)setModel:(OYModel *)model { 70 | _model = model; 71 | 72 | self.textLabel.text = model.title; 73 | // 手动刷新数据 74 | [self countDownNotification]; 75 | } 76 | 77 | - (void)dealloc { 78 | [[NSNotificationCenter defaultCenter]removeObserver:self]; 79 | } 80 | 81 | @end 82 | -------------------------------------------------------------------------------- /CellCountDown/Classes/OYTopViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // OYTopViewController.h 3 | // CellCountDown 4 | // 5 | // Created by Gold on 2017/9/30. 6 | // Copyright © 2017年 herobin. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface OYTopViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /CellCountDown/Classes/OYTopViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // OYTopViewController.m 3 | // CellCountDown 4 | // 5 | // Created by Gold on 2017/9/30. 6 | // Copyright © 2017年 herobin. All rights reserved. 7 | // 8 | 9 | #import "OYTopViewController.h" 10 | #import "OYSingleTableVC.h" 11 | #import "OYMultipleTableVC.h" 12 | #import "OYPagingTableVC.h" 13 | 14 | @interface OYTopViewController () 15 | 16 | @end 17 | 18 | @implementation OYTopViewController 19 | 20 | - (void)viewDidLoad { 21 | [super viewDidLoad]; 22 | // Do any additional setup after loading the view. 23 | self.title = @"首页"; 24 | } 25 | 26 | - (IBAction)singleTableBtnClick:(id)sender { 27 | [self.navigationController pushViewController:[OYSingleTableVC new] animated:YES]; 28 | } 29 | 30 | - (IBAction)mutipleTableBtnClick:(id)sender { 31 | [self.navigationController pushViewController:[OYMultipleTableVC new] animated:YES]; 32 | } 33 | 34 | - (IBAction)pagingTableBtnClick:(id)sender { 35 | [self.navigationController pushViewController:[OYPagingTableVC new] animated:YES]; 36 | } 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /CellCountDown/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 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 | 2.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 201 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /CellCountDown/OYCountDownManager/OYCountDownManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // CountDownManager.h 3 | // CellCountDown 4 | // 5 | // Created by herobin on 16/9/11. 6 | // Copyright © 2016年 herobin. All rights reserved. 7 | // 8 | 9 | #import 10 | /** 宏: 使用单例 */ 11 | #define kCountDownManager [OYCountDownManager manager] 12 | /** 倒计时的通知名 */ 13 | extern NSString *const OYCountDownNotification; 14 | 15 | @interface OYCountDownManager : NSObject 16 | 17 | /** 使用单例 */ 18 | + (instancetype)manager; 19 | 20 | /** 开始倒计时 */ 21 | - (void)start; 22 | 23 | /** 停止倒计时 */ 24 | - (void)invalidate; 25 | 26 | 27 | 28 | // ======== v1.0 ======== 29 | // 如果只需要一个倒计时差, 可继续使用timeInterval属性 30 | // 增加后台模式, 后台状态下会继续计算时间差 31 | 32 | /** 时间差(单位:秒) */ 33 | @property (nonatomic, assign) NSInteger timeInterval; 34 | 35 | /** 刷新倒计时(兼容旧版本, 如使用identifier标识的时间差, 请调用reloadAllSource方法) */ 36 | - (void)reload; 37 | 38 | 39 | 40 | // ======== v2.0 ======== 41 | // 增加identifier:标识符, 一个identifier支持一个倒计时源, 有一个单独的时间差 42 | 43 | /** 添加倒计时源 */ 44 | - (void)addSourceWithIdentifier:(NSString *)identifier; 45 | 46 | /** 获取时间差 */ 47 | - (NSInteger)timeIntervalWithIdentifier:(NSString *)identifier; 48 | 49 | /** 刷新倒计时源 */ 50 | - (void)reloadSourceWithIdentifier:(NSString *)identifier; 51 | 52 | /** 刷新所有倒计时源 */ 53 | - (void)reloadAllSource; 54 | 55 | /** 清除倒计时源 */ 56 | - (void)removeSourceWithIdentifier:(NSString *)identifier; 57 | 58 | /** 清除所有倒计时源 */ 59 | - (void)removeAllSource; 60 | 61 | @end 62 | 63 | 64 | 65 | @interface OYTimeInterval : NSObject 66 | @end 67 | -------------------------------------------------------------------------------- /CellCountDown/OYCountDownManager/OYCountDownManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // CountDownManager.m 3 | // CellCountDown 4 | // 5 | // Created by herobin on 16/9/11. 6 | // Copyright © 2016年 herobin. All rights reserved. 7 | // 8 | 9 | #import "OYCountDownManager.h" 10 | #import 11 | 12 | @interface OYTimeInterval () 13 | 14 | @property (nonatomic, assign) NSInteger timeInterval; 15 | 16 | + (instancetype)timeInterval:(NSInteger)timeInterval; 17 | 18 | @end 19 | 20 | 21 | 22 | @interface OYCountDownManager () 23 | 24 | @property (nonatomic, strong) NSTimer *timer; 25 | 26 | /// 时间差字典(单位:秒)(使用字典来存放, 支持多列表或多页面使用) 27 | @property (nonatomic, strong) NSMutableDictionary *timeIntervalDict; 28 | 29 | /// 后台模式使用, 记录进入后台的绝对时间 30 | @property (nonatomic, assign) BOOL backgroudRecord; 31 | @property (nonatomic, assign) CFAbsoluteTime lastTime; 32 | 33 | @end 34 | 35 | @implementation OYCountDownManager 36 | 37 | + (instancetype)manager { 38 | static OYCountDownManager *manager = nil; 39 | static dispatch_once_t onceToken; 40 | dispatch_once(&onceToken, ^{ 41 | manager = [[OYCountDownManager alloc]init]; 42 | }); 43 | return manager; 44 | } 45 | 46 | - (instancetype)init { 47 | self = [super init]; 48 | if (self) { 49 | // 监听进入前台与进入后台的通知 50 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidEnterBackgroundNotification) name:UIApplicationDidEnterBackgroundNotification object:nil]; 51 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillEnterForegroundNotification) name:UIApplicationWillEnterForegroundNotification object:nil]; 52 | } 53 | return self; 54 | } 55 | 56 | - (void)start { 57 | // 启动定时器 58 | [self timer]; 59 | } 60 | 61 | - (void)reload { 62 | // 刷新只要让时间差为0即可 63 | _timeInterval = 0; 64 | } 65 | 66 | - (void)invalidate { 67 | [self.timer invalidate]; 68 | self.timer = nil; 69 | } 70 | 71 | - (void)timerAction { 72 | // 定时器每次加1 73 | [self timerActionWithTimeInterval:1]; 74 | } 75 | 76 | - (void)timerActionWithTimeInterval:(NSInteger)timeInterval { 77 | // 时间差+ 78 | self.timeInterval += timeInterval; 79 | [self.timeIntervalDict enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, OYTimeInterval * _Nonnull obj, BOOL * _Nonnull stop) { 80 | obj.timeInterval += timeInterval; 81 | }]; 82 | // 发出通知 83 | [[NSNotificationCenter defaultCenter] postNotificationName:OYCountDownNotification object:nil userInfo:nil]; 84 | } 85 | 86 | - (void)addSourceWithIdentifier:(NSString *)identifier { 87 | OYTimeInterval *timeInterval = self.timeIntervalDict[identifier]; 88 | if (timeInterval) { 89 | timeInterval.timeInterval = 0; 90 | }else { 91 | [self.timeIntervalDict setObject:[OYTimeInterval timeInterval:0] forKey:identifier]; 92 | } 93 | } 94 | 95 | - (NSInteger)timeIntervalWithIdentifier:(NSString *)identifier { 96 | return self.timeIntervalDict[identifier].timeInterval; 97 | } 98 | 99 | - (void)reloadSourceWithIdentifier:(NSString *)identifier { 100 | self.timeIntervalDict[identifier].timeInterval = 0; 101 | } 102 | 103 | - (void)reloadAllSource { 104 | [self.timeIntervalDict enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, OYTimeInterval * _Nonnull obj, BOOL * _Nonnull stop) { 105 | obj.timeInterval = 0; 106 | }]; 107 | } 108 | 109 | - (void)removeSourceWithIdentifier:(NSString *)identifier { 110 | [self.timeIntervalDict removeObjectForKey:identifier]; 111 | } 112 | 113 | - (void)removeAllSource { 114 | [self.timeIntervalDict removeAllObjects]; 115 | } 116 | 117 | - (void)applicationDidEnterBackgroundNotification { 118 | self.backgroudRecord = (_timer != nil); 119 | if (self.backgroudRecord) { 120 | self.lastTime = CFAbsoluteTimeGetCurrent(); 121 | [self invalidate]; 122 | } 123 | } 124 | 125 | - (void)applicationWillEnterForegroundNotification { 126 | if (self.backgroudRecord) { 127 | CFAbsoluteTime timeInterval = CFAbsoluteTimeGetCurrent() - self.lastTime; 128 | // 取整 129 | [self timerActionWithTimeInterval:(NSInteger)timeInterval]; 130 | [self start]; 131 | } 132 | } 133 | 134 | - (NSTimer *)timer { 135 | if (_timer == nil) { 136 | _timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timerAction) userInfo:nil repeats:YES]; 137 | [[NSRunLoop mainRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes]; 138 | } 139 | return _timer; 140 | } 141 | 142 | - (NSMutableDictionary *)timeIntervalDict { 143 | if (!_timeIntervalDict) { 144 | _timeIntervalDict = [NSMutableDictionary dictionary]; 145 | } 146 | return _timeIntervalDict; 147 | } 148 | 149 | NSString *const OYCountDownNotification = @"OYCountDownNotification"; 150 | 151 | @end 152 | 153 | 154 | @implementation OYTimeInterval 155 | 156 | + (instancetype)timeInterval:(NSInteger)timeInterval { 157 | OYTimeInterval *object = [OYTimeInterval new]; 158 | object.timeInterval = timeInterval; 159 | return object; 160 | } 161 | 162 | @end 163 | -------------------------------------------------------------------------------- /CellCountDown/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // CellCountDown 4 | // 5 | // Created by herobin on 16/9/11. 6 | // Copyright © 2016年 herobin. 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 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 herobin22 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /OYCountDownManager.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'OYCountDownManager' 3 | s.version = '2.0.3' 4 | s.authors = { 'herob' => '869765745@qq.com' } 5 | s.homepage = 'https://github.com/herobin22/OYCountDownManager' 6 | s.summary = 'iOS在cell中使用倒计时的处理方法' 7 | s.source = { :git => 'https://github.com/herobin22/OYCountDownManager.git', :tag => s.version } 8 | s.license = { :type => "MIT", :file => "LICENSE" } 9 | s.platform = :ios, '7.0' 10 | s.requires_arc = true 11 | s.source_files = 'CellCountDown/OYCountDownManager/*.{h,m}' 12 | 13 | end 14 | -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment the next line to define a global platform for your project 2 | # platform :ios, '9.0' 3 | 4 | target 'CellCountDown' do 5 | # Uncomment the next line if you're using Swift or would like to use dynamic frameworks 6 | # use_frameworks! 7 | 8 | # Pods for CellCountDown 9 | 10 | pod ‘MJRefresh’ 11 | 12 | end 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 一.OYCountDownManager描述 2 | iOS在cell中使用倒计时的处理方法, 全局使用一个NSTimer对象 3 | 4 | Swift版本: [OYCountDownManager-Swift](https://github.com/herobin22/OYCountDownManager-Swift) 5 | * 单个列表倒计时 6 | * 多个列表倒计时 7 | * 多个页面倒计时 8 | * 分页列表倒计时 9 | * 后台模式倒计时 10 | 11 | ![单个列表](https://github.com/herobin22/OYCountDownManager/raw/master/gif-single.gif)![多个列表.gif](https://github.com/herobin22/OYCountDownManager/raw/master/gif-multipleTable.gif)![多个页面.gif](https://github.com/herobin22/OYCountDownManager/raw/master/gif-multiplePage.gif)![分页列表.gif](https://github.com/herobin22/OYCountDownManager/raw/master/gif-paging.gif) 12 | 13 | ## 二.原理分析 14 | ![原理分析图.png](http://upload-images.jianshu.io/upload_images/1646270-622a49c3f6d9b4f3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 15 | 16 | ## 三.使用方法 17 | #### 1.1 第一种方法: 使用cocoapods自动安装 18 | ``` 19 | pod 'OYCountDownManager' 20 | ``` 21 | 22 | #### 1.2 第二种方法 23 | ``` 24 | 下载示例Demo, 把里面的OYCountDownManager文件夹拖到你的项目中 25 | ``` 26 | 27 | #### 2. 在第一次使用的地方调用[kCountDownManager start] 28 | ``` 29 | - (void)viewDidLoad { 30 | [super viewDidLoad]; 31 | 32 | // 启动倒计时管理 33 | [kCountDownManager start]; 34 | } 35 | ``` 36 | #### 3. 在Cell初始化中监听通知 kCountDownNotification 37 | ``` 38 | - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { 39 | if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) { 40 | // 监听通知 41 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(countDownNotification) name:kCountDownNotification object:nil]; 42 | } 43 | return self; 44 | } 45 | ``` 46 | #### 4. 在cell设置通知回调, 取得时间差, 根据时间差进行处理 47 | ``` 48 | - (void)countDownNotification { 49 | /// 计算倒计时 50 | NSInteger countDown = [self.model.count integerValue] - kCountDownManager.timeInterval; 51 | if (countDown <= 0) { 52 | // 倒计时结束时回调 53 | xxxx(使用代理或block) 54 | return; 55 | } 56 | /// 重新赋值 57 | self.timeLabel.text = [NSString stringWithFormat:@"倒计时%02zd:%02zd:%02zd", countDown/3600, (countDown/60)%60, countDown%60]; 58 | } 59 | ``` 60 | #### 5. 当刷新数据时,调用reload方法 61 | ``` 62 | - (void)reloadData { 63 | // 网络加载数据 64 | 65 | // 调用[kCountDownManager reload] 66 | [kCountDownManager reload]; 67 | // 刷新 68 | [self.tableView reloadData]; 69 | } 70 | ``` 71 | #### 6. 当不需要倒计时时, 废除定时器 72 | ``` 73 | [kCountDownManager invalidate]; 74 | ``` 75 | 76 | 77 | ## 四.高级使用(多列表.多页面.分页列表) 78 | 增加identifier:标识符, 一个identifier支持一个倒计时源, 有一个单独的时间差 79 | ``` 80 | /** 添加倒计时源 */ 81 | - (void)addSourceWithIdentifier:(NSString *)identifier; 82 | 83 | /** 获取时间差 */ 84 | - (NSInteger)timeIntervalWithIdentifier:(NSString *)identifier; 85 | 86 | /** 刷新倒计时源 */ 87 | - (void)reloadSourceWithIdentifier:(NSString *)identifier; 88 | 89 | /** 刷新所有倒计时源 */ 90 | - (void)reloadAllSource; 91 | 92 | /** 清除倒计时源 */ 93 | - (void)removeSourceWithIdentifier:(NSString *)identifier; 94 | 95 | /** 清除所有倒计时源 */ 96 | - (void)removeAllSource; 97 | ``` 98 | 以一个页面有两个独立的列表为例 99 | #### 1.定义identifier(常量) 100 | ``` 101 | NSString *const OYMultipleTableSource1 = @"OYMultipleTableSource1"; 102 | NSString *const OYMultipleTableSource2 = @"OYMultipleTableSource2"; 103 | ``` 104 | 105 | #### 2.增加倒计时源 106 | ``` 107 | // 增加倒计时源 108 | [kCountDownManager addSourceWithIdentifier:OYMultipleTableSource1]; 109 | [kCountDownManager addSourceWithIdentifier:OYMultipleTableSource2]; 110 | ``` 111 | #### 3.在cell通知回调中, 通过identifier取得时间差, 根据时间差进行处理 112 | ``` 113 | - (void)countDownNotification { 114 | /// 判断是否需要倒计时 -- 可能有的cell不需要倒计时,根据真实需求来进行判断 115 | if (0) { 116 | return; 117 | } 118 | /// 计算倒计时 119 | OYModel *model = self.model; 120 | /// 根据identifier取得时间差, 以OYMultipleTableSource1为例 121 | NSInteger timeInterval = timeInterval = [kCountDownManager timeIntervalWithIdentifier: OYMultipleTableSource1]; 122 | } 123 | NSInteger countDown = model.count - timeInterval; 124 | /// 当倒计时到了进行回调 125 | if (countDown <= 0) { 126 | self.detailTextLabel.text = @"活动开始"; 127 | // 倒计时结束时回调 128 | xxxx(使用代理或block) 129 | return; 130 | } 131 | /// 重新赋值 132 | self.detailTextLabel.text = [NSString stringWithFormat:@"倒计时%02zd:%02zd:%02zd", countDown/3600, (countDown/60)%60, countDown%60]; 133 | } 134 | ``` 135 | 136 | #### 4. 当刷新数据时,调用reloadSourceWithIdentifier:刷新时间差 137 | ``` 138 | - (void)reloadData { 139 | // 网络加载数据 140 | 141 | // 调用reloadSourceWithIdentifier:刷新时间差 142 | [kCountDownManager reloadSourceWithIdentifier:OYMultiplePageSource1]; 143 | // 刷新 144 | [self.tableView reloadData]; 145 | } 146 | ``` 147 | 148 | #### 5. 当页面销毁, 移除倒计时源, 或者不需要定时器, 废除定时器 149 | ``` 150 | // 移除所有倒计时源 151 | [kCountDownManager removeAllSource]; 152 | // 废除定时器 153 | [kCountDownManager invalidate]; 154 | ``` 155 | 156 | 157 | ## 五.注意事项 158 | > #### 误差分析 159 | * NSTimer可以精确到50-100毫秒,不是绝对准确的,所以你使用时间累加的方法时间久了有可能成为时间误差的来源 160 | * 以秒为单位触发定时器, 当reloadData后, 定时器也许刚好到达触发点, 时间差+1, 数据刚reload完就马上-1秒 161 | * 后台模式是以进入后台的绝对时间, 及进入前台的绝对时间做差值来计算的, 差值会进行取整, 导致一点点误差 162 | 163 | > #### 滚动cell时出去文字闪烁 164 | 在给cell的模型赋值后, 最好手动调用一下countDownNotification方法, 保证及时刷新 165 | ``` 166 | /// 重写setter方法 167 | - (void)setModel:(Model *)model { 168 | _model = model; 169 | self.titleLabel.text = model.title; 170 | // 手动调用通知的回调 171 | [self countDownNotification]; 172 | } 173 | ``` 174 | 175 | 176 | 177 | > #### 倒计时为0后出现复用问题 178 | 在倒计时为0后, 应该回调给控制器, 从后台请求一次数据, 保证倒计时没有出现误差 179 | ``` 180 | if (countDown <= 0) { 181 | // 倒计时结束时回调 182 | xxxx(使用代理或block) 183 | }return; 184 | ``` 185 | 186 | 187 | 188 | > #### 出现每秒倒计时减2的问题 189 | 1.查看定时器设置是否正确, 或者通知是否监听了两次 190 | 191 | 2.在countDownNotification方法中, 是否用[NSDate date]做了某些计算, 因为[NSDate date]为当前时间, 每一秒去取都会比上一秒大一秒, 再加上timeInterval也是一秒加一, 那么就会出现每秒倒计时减2的问题 192 | 193 | 194 | 195 | 196 | 197 | * 还有不懂的问题, 或者出现其它bug 198 | * 请查看Demo: [Demo](https://github.com/herobin22/OYCountDownManager) 199 | * 简书地址:http://www.jianshu.com/p/af62a56ef7e2 200 | * 或者给我留言, 喜欢的话, 就给作者一个star 201 | -------------------------------------------------------------------------------- /gif-multiplePage.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/herobin22/OYCountDownManager/ab76d5eb8344791a12d2395c1f99033b7fd44871/gif-multiplePage.gif -------------------------------------------------------------------------------- /gif-multipleTable.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/herobin22/OYCountDownManager/ab76d5eb8344791a12d2395c1f99033b7fd44871/gif-multipleTable.gif -------------------------------------------------------------------------------- /gif-paging.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/herobin22/OYCountDownManager/ab76d5eb8344791a12d2395c1f99033b7fd44871/gif-paging.gif -------------------------------------------------------------------------------- /gif-single.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/herobin22/OYCountDownManager/ab76d5eb8344791a12d2395c1f99033b7fd44871/gif-single.gif --------------------------------------------------------------------------------