我试图重复执行函数pepe(),我没有错误,但它不起作用。
这是我的代码:
public class MyClass {
var timer = Timer()
@objc func pepe() -> String {
let hola = "hola"
return hola
}
func startTimer(){
let seconds = 1.0
timer = Timer.scheduledTimer(timeInterval: seconds, target: ().self, selector: #selector(pepe), userInfo: nil, repeats: false)
}
func stopTimer() {
timer.invalidate()
}
init() {
self.startTimer()
self.stopTimer()
}
}
var pepe = MyClass()
pepe.stopTimer()
pepe.startTimer()
答案 0 :(得分:8)
我建议:
不要实例化空Timer
。考虑:
var timer = Timer()
即创建一个空白计时器实例。我们不想这样做。你应该使用:
weak var timer: Timer?
实现了一些目标:
Timer?
语法表示它是“可选的”,您将在稍后实例化其值。
安排Timer
后,runloop会对其进行强有力的引用。因此,与大多数其他对象不同,您个人不需要对预定的计时器进行强有力的引用。当计时器失效时,您可能希望timer
变量自动设置为nil
。因此,weak
限定符表示当计时器失效时,timer
变量将自动设置为nil
。
pepe
方法签名不太正确:
它不应该返回任何内容;
你应该给它Timer
参数。进入是一个很好的习惯。您可能不需要它,但它使方法的意图更加清晰,您最终可能会发现使用Timer
参数很有用;以及
我可能会给它一个更具描述性的名称,以避免任何歧义;我倾向于使用像timerHandler
这样的名字。
在init
开始和停止计时器是没有意义的。
().self
中对target
的引用应为self
。
在您的操场上,您正在停止计时器(尚未安排的计时器),然后启动计时器。
您可能还希望在一段时间后停止播放,这样您就有机会看到Timer
正在运行。
但是,作为一般规则,在编写启动计时器的方法时,谨慎的做法是确保您没有(意外地)已经启动它。如果你不这样做,并且意外地两次调用startTimer
,你最终可能会同时进行多个定时器(最糟糕的是,丢失了对早期定时器的引用)。一个常见的解决方案是典型的解决方案是查看是否已有计时器,如果是,则在创建下一个计时器之前使其无效。使用可选的链接模式很容易实现:
func startTimer() {
timer?.invalidate() // stops previous timer, if any
// now proceed with scheduling of new timer
}
因此:
import UIKit
// if doing this in playground, include the following two lines
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
// MyClass
public class MyClass {
weak var timer: Timer?
@objc func timerHandler(_ timer: Timer) {
let hola = "hola"
print(">>>> \(hola)")
}
func startTimer() {
timer?.invalidate() // stops previous timer, if any
let seconds = 1.0
timer = Timer.scheduledTimer(timeInterval: seconds, target: self, selector: #selector(timerHandler(_:)), userInfo: nil, repeats: true)
}
func stopTimer() {
timer?.invalidate()
}
}
var object = MyClass()
object.startTimer()
// stop it 10 seconds later
DispatchQueue.main.asyncAfter(deadline: .now() + 10) {
object.stopTimer()
}
但应该认识到,您最终可能会得到类似于强参考周期的东西:
target
; MyClass
(target
)可能是最终使该计时器无效的原因。因此,在MyClass
无效之前,无法取消分配Timer
。而且,就目前情况而言,您不能只invalidate
Timer
deinit
MyClass
中的deinit
,因为MyClass
在计时器到来之前不会被调用无效。
实际效果是,如果您将此MyClass
作为视图控制器的属性并启动计时器然后关闭视图控制器,则计时器将继续运行[weak self]
不会被解除分配。
要解决此问题,您可能希望使用基于闭包的计时器和MyClass
引用,从而消除计时器与MyClass
之间的强引用。然后,您还可以在取消分配public class MyClass {
weak var timer: Timer?
deinit {
timer?.invalidate()
}
func timerHandler(_ timer: Timer) {
let hola = "hola"
print(">>>> \(hola)")
}
func startTimer() {
timer?.invalidate() // stops previous timer, if any
let seconds = 1.0
timer = Timer.scheduledTimer(withTimeInterval: seconds, repeats: true) { [weak self] timer in
self?.timerHandler(timer)
}
}
func stopTimer() {
timer?.invalidate()
}
}
时自动使计时器失效:
<div id="div">
<!-- acuity -->
<div id="booking-div">
<div id="booking-left"></div>
<div id="booking-right">
<a><img id="close-image" src="{% static "img/close-button.svg" %}" alt="My image"></a>
{% for BarberProfile in queryset_list %}
<iframe class="iframe" id="{{BarberProfile.id}}-iframe" src="" frameBorder="0"></iframe><script src="https://d3gxy7nm8y4yjr.cloudfront.net/js/embed.js" type="text/javascript"></script>
{% endfor %}
</div>
</div>
<!-- acuity -->
<!-- profile -->
{% for BarberProfile in queryset_list %}
<a class="profile-div" id="{{BarberProfile.id}}" target="{{BarberProfile.booking_link}}" onClick="toggle_content(this.id)">
<div id="image" style="background-image: url({{BarberProfile.image.url}})">
<div id="image-structure"></div>
</div>
<h4 id="name"> {{BarberProfile.first_name}} </h4>
<p id="bio"> {{BarberProfile.bio}} </p>
<img id="experience-image" src="{% static "img/experience.svg" %}" alt=""><p id="experience">{{BarberProfile.years_of_experience}} experience</p>
<img id="ideal-image" src="{% static "img/speciality.svg" %}" alt=""><p id="ideal">Ideal for {{BarberProfile.ideal_for}} </p>
</a>
{% endfor %}
<!-- profile -->
</div>
答案 1 :(得分:0)
设置repeats = true
,将其设为self
而不是().self
,我尝试了这个并且它可以正常工作,您也错误地尝试在init
中启动和停止计时器
public class MyClass {
var timer = Timer()
@objc func pepe() {
let hola = "hola"
print("\(hola)")
}
func startTimer(){
let seconds = 1.0
timer = Timer.scheduledTimer(timeInterval: seconds, target:self, selector: #selector(pepe), userInfo: nil, repeats: true)
}
func stopTimer() {
timer.invalidate()
}
init() {
}
}
答案 2 :(得分:0)
尝试
import UIKit
import AVFoundation
class PeopleViewController: UIViewController {
var countdownTimer: Timer!
var totalTime = 0
let timerLbl: UILabel = {
let lbl = UILabel()
lbl.translatesAutoresizingMaskIntoConstraints = false
lbl.font = .boldSystemFont(ofSize: 22)
lbl.text = "HH:MM:SS"
return lbl
}()
override func viewDidLoad() {
super.viewDidLoad()
totalTime = defaults.integer(forKey: "time")
view.backgroundColor = .white
view.addSubview(timerLbl)
NSLayoutConstraint.activate([
timerLbl.centerXAnchor.constraint(equalTo: view.centerXAnchor),
timerLbl.centerYAnchor.constraint(equalTo: view.centerYAnchor),
timerLbl.heightAnchor.constraint(equalToConstant: 30)
])
// startTimer()
// doBackgroundTask()
UIApplication.shared.runInBackground({
self.startTimer()
}) {
// task after expiration.
}
// DispatchQueue.main.async(execute: {
//
// NotificationCenter.default.addObserver(self, selector:#selector(self.startTimer), name:UIApplication.willEnterForegroundNotification, object: nil)
//
// })
}
// deinit {
// NotificationCenter.default.removeObserver(self)
// }
// var backgroundUpdateTask: UIBackgroundTaskIdentifier?
//
// func doBackgroundTask() {
//
// DispatchQueue.main.async {
//
// self.beginBackgroundUpdateTask()
//
// self.StartupdateLocation()
//
// self.endBackgroundUpdateTask()
//
// }
// }
// func beginBackgroundUpdateTask() {
// self.backgroundUpdateTask = UIApplication.shared.beginBackgroundTask(expirationHandler: {
// self.endBackgroundUpdateTask()
// })
// }
//
// func endBackgroundUpdateTask() {
// if let bgTask = self.backgroundUpdateTask {
// UIApplication.shared.endBackgroundTask(bgTask)
// self.backgroundUpdateTask = UIBackgroundTaskIdentifier.invalid
// }
// }
//
// func StartupdateLocation() {
// startTimer()
// }
let defaults = UserDefaults.standard
@objc func startTimer() {
print(countdownTimer)
countdownTimer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(updateTime), userInfo: nil, repeats: true)
}
@objc func updateTime() {
print(timerLbl.text as Any)
defaults.set(totalTime, forKey: "time")
let updateTime = defaults.integer(forKey: "time")
timerLbl.text = "\(timeFormatted(updateTime))"
totalTime += 1
defaults.set(totalTime, forKey: "time")
// if totalTime != 0 {
// totalTime += 1
// } else {
// endTimer()
// }
}
func endTimer() {
countdownTimer.invalidate()
}
func timeFormatted(_ totalSeconds: Int) -> String {
let seconds: Int = totalSeconds % 60
let minutes: Int = (totalSeconds / 60) % 60
let hours: Int = totalSeconds / 3600
return String(format: "%02d:%02d:%02d", hours,minutes, seconds)
}
}
extension UIApplication {
/// Run a block in background after app resigns activity
public func runInBackground(_ closure: @escaping () -> Void, expirationHandler: (() -> Void)? = nil) {
DispatchQueue.main.async {
let taskID: UIBackgroundTaskIdentifier
if let expirationHandler = expirationHandler {
taskID = self.beginBackgroundTask(expirationHandler: expirationHandler)
} else {
taskID = self.beginBackgroundTask(expirationHandler: { })
}
closure()
self.endBackgroundTask(taskID)
}
}
}