一个更完善的Swift倒计时按钮(附后台权限申请)
如今越来越多app使用手机号码作为用户名,其中总是要涉及到验证码的发送。
倒计时按钮实现关键点:
- 当前视图控制器销毁后倒计时计数的再恢复
- 不同页面可能使用同一个倒计时计数
- app进入后台后的倒计时
明确了上面几个问题,接下来代码编写就简单了
符合设计模式,我们将倒计时按钮实现拆分为两个类:
WynCountdownButton
: 继承UIButton,对外开放
WynCountdownController
: 倒计时控制模块,与WynCountdownButton
一一对应。对外不可见
下面针对3个实现关键点做实现设计
1. 当前视图控制器销毁后倒计时计数的再恢复
- 按钮、控制器分离。按钮生命周期随所处的视图控制器。控制器随倒计时的开始与结束,做初始化与销毁。
- 按钮与控制器一一对应
class WynCountdownButton: UIButton {
private weak var controller: WynCountdownController
...
}
/// 全局的常量或变量都是延迟计算的,跟延迟存储属性相似,但全局的常量或变量不需要标记‘lazy’特性。
/// 全局变量持有控制器
private var wynCountdownControllers: [String: WynCountdownController] = [:]
2.不同页面可能使用同一个倒计时计数
class WynCountdownController {
/// 通过identifier来取得控制器实例
static func shared(withIdentifier identifier: String) -> WynCountdownController {
if let c = wynCountdownControllers[identifier] {
return c
} else {
let c = WynCountdownController()
c.identifier = identifier
objc_sync_enter(wynCountdownControllers)
wynCountdownControllers[identifier] = c
objc_sync_exit(wynCountdownControllers)
return c
}
}
/// 限制只能通过shared(withIdentifier:)方法来实例化Controller
private init() {
}
...
}
3. app进入后台后的倒计时
这点就和我们的倒计时按钮没有关系了。有两种实现方案
- 记录进入后台与回到前台的间隔时间
- 申请后台运行权限
本文介绍一下2,申请后台运行权限的方法。 只需在AppDelegate
中添加以下代码
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
...
var backgroundTaskId: UIBackgroundTaskIdentifier?
func applicationDidEnterBackground(_ application: UIApplication) {
let sharedApp = UIApplication.shared
backgroundTaskId = sharedApp.beginBackgroundTask(expirationHandler: {
[unowned sharedApp] in
sharedApp.endBackgroundTask(self.backgroundTaskId!)
self.backgroundTaskId = UIBackgroundTaskIdentifier.invalid
})
}
...
}
若采用此方案,推荐加入一个标识,判断当前是否需要申请后台运行权
下面是完整代码,暂未传到Github
使用方法
let cBtn = WynCountdownButton(sec: 30, type: .system, identifier: "HistoryAndFavoriteBtn")
cBtn.frame = CGRect(x: