How can I make an iPhone vibrate indefinitely? I know I can do this:
while true {
AudioServicesPlayAlertSound(SystemSoundID(kSystemSoundID_Vibrate))
}
Is there any way to play the vibration for a certain number of seconds, or something with a similar result that is cleaner? Also, is there a way to make the vibration more intense?
I think you should use Timer.
var timer: Timer?
var numberRepeat = 0
var maxNumberRepeat = 20
func startTimer() {
//
timer = Timer.scheduledTimer(timeInterval: 2, target: self, selector: #selector(self.timerHandler), userInfo: nil, repeats: true)
}
func stopTimer() {
timer?.invalidate()
timer = nil
}
#objc func timerHandler() {
if numberRepeat <= maxNumberRepeat {
numberRepeat += 1
vibrateDevice()
} else {
stopTimer()
}
}
func vibrateDevice() {
AudioServicesPlayAlertSound(SystemSoundID(kSystemSoundID_Vibrate))
}
Related
I can not stop the timer NSTimer created to perform secondary operations.
I have read and tried all sorts of possible Web guides but none have worked and the timer continues to run even when the Controller is destroyed. Below is the code in question:
/* Copy banner in a temp array and change order to random value */
private func getBanners(){
let realm = try! Realm()
let banners = self.synchronizer.getAllBanners()?.sorted("ordine")
if let banners = banners {
for banner in banners {
let random = Double.random(0.0, 1.0)
let currentOrderValue = banner.ordine
self.banners.append(banner)
do {
try realm.write({
self.banners.last!.ordine = currentOrderValue + random
})
} catch let error as NSError {
print(error)
}
}
}
}
/*Update index of banner to show */
func updateIndex(timer : NSTimer) {
if self.index+1 < self.banners.count {
for banner in self.banners{
print(banner.name + " \(banner.ordine)")
}
self.index+=1
} else {
self.index = 0
}
self.setImageBanner()
}
/* Set image of banner to show*/
private func setImageBanner() {
if self.banners.count > 0 {
self.bannerImage.hidden = false
let banner = self.banners[self.index]
let file = banner.images[0]
self.synchronizer.loadImageURL(file.link, imageView: self.bannerImage)
} else {
self.bannerImage.hidden = true
}
}
/* Start Timer */
func startTimerForBanners() {
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.getBanners()
})
self.timer = NSTimer(timeInterval: 5, target: self, selector: #selector(self.updateIndex(_:)), userInfo: nil, repeats: true)
NSRunLoop.currentRunLoop().addTimer(self.timer!, forMode: NSRunLoopCommonModes)
}
/* Open link on banner click */
func openLink(sender : UITapGestureRecognizer){
if self.index >= 0 && self.index < self.banners.count {
let banner = self.banners[self.index]
print(banner.name)
self.synchronizer.openLink(banner.url)
}
}
func trialLesson(sender : UITapGestureRecognizer){
performSegueWithIdentifier("trial_lesson_segue", sender: nil)
}
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
if let timer = self.timer {
timer.invalidate()
}
}
you need to invalidate the timer before starting a new timer. Currently I believe you are calling "startTimerForBanners" many times may be, so many timer thread has been initiated. One approach is to invlidate all timer one by one or just invalidate before starting new one like this
/* Start Timer */
func startTimerForBanners() {
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.getBanners()
})
**self.timer.invalidate()**
self.timer = NSTimer(timeInterval: 5, target: self, selector: #selector(self.updateIndex(_:)), userInfo: nil, repeats: true)
NSRunLoop.currentRunLoop().addTimer(self.timer!, forMode: NSRunLoopCommonModes)
}
Are you sure that your controller is really deallocated?
There is one thing you should be always aware about NSTimer: it retains it's target.
I would suggest to:
Start your timer in viewWillAppear
Invalidate and set timer to nil in viewDidDisappear
Also try replacing your start timer code with this (Swift 3):
timer = Timer.scheduledTimer(timeInterval: 5, target: self, selector: #selector(self.updateIndex(_:)), userInfo: nil, repeats: true)
I'm trying to get output like so:
1 (then a one second delay)
Hello
2 (then a one second delay)
Hello
3 (then a one second delay)
Hello
But instead I get
1
2
3 (then a one second delay)
Hello
Hello
Hello
Here's my for loop invoking the NSTimer
var timer = NSTimer()
for i in 1...3 {
print("\(i)");
timer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: #selector(MainVPScreenViewController.printTest), userInfo: nil, repeats: false)
}
And here's the selector method:
func printTest() {
print("Hello")
}
Thanks in advance for any help you can provide
Try this solution without NSTimer:
var i = 1
func printHello() {
print(i)
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(1 * Double(NSEC_PER_SEC))), dispatch_get_main_queue()) {
print("Hello")
i +=1
if i <= 3 {
printHello()
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
printHello()
}
I need 2 NSTimers to do this, this is my approach
class ViewController: UIViewController {
var i = 1
override func viewDidLoad() {
super.viewDidLoad()
beginPrinting()
}
func beginPrinting() {
var timer2 = NSTimer()
if(i <= 100)
{
timer2 = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: #selector(self.printWithDelay), userInfo: nil, repeats: false)
}
}
func printWithDelay()
{
var timer = NSTimer()
print("\(i)");
i += 1
timer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: #selector(self.printTest), userInfo: nil, repeats: false)
}
func printTest() {
print("Hello")
beginPrinting()
}
}
Hope this helps you
Use timer with repeat to true. So in your view controller would be like this
var timer = NSTimer()
var counter = 0
var max = 10
let delay = 1 // in second
override func viewDidLoad() {
super.viewDidLoad()
timer = NSTimer.scheduledTimerWithTimeInterval(delay, target: self,
selector: #selector(self.printTest), userInfo: nil, repeats: true)
}
func printTest() {
counter += 1
print(counter)
print(hello)
if counter == maxNumber {
timer.invalidate()
}
}
This does it with repeat false, and is set up to be in a playground:
import XCPlayground
XCPlaygroundPage.currentPage.needsIndefiniteExecution = true
#objc class Foo: NSObject {
static var timer = NSTimer()
var i:Int
override init() {
Foo.timer = NSTimer()
i = 1
}
func schedule() {
print("\n\(i)");
i += 1
Foo.timer = NSTimer.scheduledTimerWithTimeInterval(1.0,
target: self,
selector: #selector(printTest),
userInfo: nil,
repeats: false)
}
#objc func printTest() {
print("Hello")
if i < 5 {
schedule()
}
}
}
let bar = Foo()
bar.schedule()
I am attempting to make a countdown timer that counts down from 60 seconds and then stops when it gets to 0. But for the timer keeps going into negative seconds. Any advice is appreciated. Code:
#IBOutlet var timeCounter: UILabel!
var second = 60
var timer = NSTimer()
var timerRunning = true
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
setTimer()
timerCounting()
}
func setTimer(){
second -= 1
timeCounter.text = "\(second)"
}
func timerCounting(){
if(timerRunning == true){
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("setTimer"), userInfo: nil, repeats: true)
timerRunning = true
if second == 0 {
timerRunning = false
timer.invalidate()
}
}
}
You have to move the invalidation into the setTimer function since at its current location will never be triggered because timerCounting is only called once - in the beginning.
func setTimer(){
second -= 1
timeCounter.text = "\(second)"
if second == 0 {
timerRunning = false
timer.invalidate()
}
}
play with this in playground
import XCPlayground
XCPlaygroundPage.currentPage.needsIndefiniteExecution = true
import Foundation
#objc class C:NSObject {
var timer: NSTimer?
var second = 5
func setTimer(){
if c.second < 0 {
print("the timer fires the last time here ...")
timer?.invalidate()
} else {
print(second)
second -= 1
}
}
}
let c = C()
func timerCounting(){
c.timer = NSTimer.scheduledTimerWithTimeInterval(1, target: c, selector: Selector("setTimer"), userInfo: nil, repeats: true)
}
timerCounting()
I made a stopwatch in swift. It has three buttons- play, stop, reset. it has a display in the middle where I display the seconds passed.
My code runs fine. But the watch runs very fast after the stop or reset.
I am not able to figure out what is the fuss.
please help!
var time = 0
var timer = NSTimer()
var pause = Bool(false)
#IBOutlet var result: UILabel!
func displayResult() {
if pause != true
{
time++
result.text = String(time)
}
}
#IBAction func reset(sender: AnyObject) {
time = 0
result.text = String(time)
}
#IBAction func pause(sender: AnyObject) {
pause = true
}
#IBAction func play(sender: AnyObject) {
pause = false
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("displayResult") , userInfo: nil, repeats: true)
}
Your pause action should be:
#IBAction func pause(sender: AnyObject) {
timer.invalidate()
pause = true
}
UPD:
var time = 0
var timer = NSTimer()
var pause = true // 1
func displayResult() {
if pause != true
{
time++
label.text = String(time)
}
}
#IBAction func reset(sender: AnyObject) {
time = 0
label.text = String(time)
timer.invalidate() // 2
pause = true // 3
}
#IBAction func pause(sender: AnyObject) {
timer.invalidate() // 4
pause = true
}
#IBAction func play(sender: AnyObject) {
// 5
if pause == true {
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("displayResult") , userInfo: nil, repeats: true)
pause = false
}
}
I have the next function:
override func textViewDidChange(textView: UITextView) {
super.textViewDidChange(textView)
if textView.text.characters.count == 0 {
print("stopped")
} else {
print("typing")
}
}
So, I want the next:
For example, user is typing something and stopped in the middle of text. I want to check, if user wrote something and stopped in the middle of typing for 4 seconds to run the function stopped().
I did this:
override func textViewDidChange(textView: UITextView) {
super.textViewDidChange(textView)
if textView.text.characters.count == 0 {
print("stopped")
} else {
print("typing")
let timer = NSTimer.scheduledTimerWithTimeInterval(4.0, target: self, selector: "stopped", userInfo: nil, repeats: false)
}
}
func stopped() {
print("stopped typing")
}
but it runs my NSTimer every time. That's not what I want.
How can I run it just one time? For example to check if user didn't write anything in 4 seconds to run stopped(). Just one time.
You need to stop the previous timer with invalidate
var timer
override func textViewDidChange(textView: UITextView) {
super.textViewDidChange(textView)
if textView.text.characters.count == 0 {
print("stopped")
} else {
timer.invalidate()
print("typing")
timer = NSTimer.scheduledTimerWithTimeInterval(4.0, target: self, selector: "stopped", userInfo: nil, repeats: false)
}
}
You'll have to keep a reference on your timer and invalidate it whenever textViewDidChange is called, something like that :
var textViewTimer : NSTimer?
override func textViewDidChange(textView: UITextView) {
super.textViewDidChange(textView)
textViewTimer.invalidate()
if textView.text.characters.count == 0 {
print("stopped")
} else {
print("typing")
textViewTimer = NSTimer.scheduledTimerWithTimeInterval(4.0, target: self, selector: "stopped", userInfo: nil, repeats: false)
}
}
func stopped() {
print("stopped typing")
}
Here is a solution for Swift 5
var textViewTimer: Timer?
override func textViewDidChange(textView: UITextView) {
textViewTimer.invalidate()
print("typing")
textViewTimer = Timer.scheduledTimer(timeInterval: 4.0, target: self, selector: #selector(typingStopped), userInfo: nil, repeats: false)
}
}
#objc func typingStopped() {
print("stopped")
}