I try to create a socket as shown below:
socket = GCDAsyncSocket(delegate: self, delegateQueue: dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0))
and I implement the func:
func socket(socket : GCDAsyncSocket, didConnectToHost host:String, port p:UInt16){
pingTimer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: "sendPing:", userInfo: nil, repeats: true)
}
func sendPing(){
print("will send ping...")
}
But the sendPing will never be called, and if I try this:
socket = GCDAsyncSocket(delegate: self, delegateQueue: dispatch_get_main_queue())
the deletegateQueue is socket = GCDAsyncSocket(delegate: self, delegateQueue: dispatch_get_main_queue()), it will work fine.
The UI updating is use main queue, so I want to do socket connection with another type queue, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0) seems to be a good one.
How can I make it work well?
Related
I am creating an app where a timer is set by the user. When the app goes to the background, the timer.invalidate(). Now I want the timer to start again when the app comes back to the foreground. I am creating another instance of timer to do it when the app sends notification that app is in the foreground. However, it's not firing the function.
In Viewdidload() I am creating a timer:
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(handleCountdown), userInfo: nil, repeats: true)
RunLoop.current.add(self.timer!, forMode: RunLoop.Mode.common)
And then I have notifications that check if the app is in background or in foreground:
When it enters background I am invalidating the timer.
#objc func applicationDidEnterBackground() {
let defaults = UserDefaults.standard
let quitTime = Date()
defaults.set(quitTime, forKey: "quitTimeKey") //Storing the time of quit in UserDefaults
timer?.invalidate()
}
When the app gets back out, I first check if the timer is isValid or not, and then create a new timer. But this timer doesn't seem to work.
#objc func appEntersForeground() {
calculateTimeLeft()
if let timer = timer {
if (!timer.isValid)
{
Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(handleCountdown), userInfo: nil, repeats: true)
}
}
}
Some help here will be appreciated!
Declare your timer property as weak:
weak var timer: Timer?
Then it will be set to nil when the timer is invalidated. Then just check if timer is nil before creating a new one:
#objc func appEntersForeground() {
calculateTimeLeft()
if timer == nil {
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(handleCountdown), userInfo: nil, repeats: true)
}
}
I want to call the method func adjustmentBestSongBpmHeartRate() every 1.1 second. I used Timer, but it doesn't work. I have read the document and found a lot of sample code, it still does work! Is there anything I missed?
timer = Timer.scheduledTimer(timeInterval: 1.1, target: self, selector: #selector(self.adjustmentBestSongBpmHeartRate), userInfo: nil, repeats: false)
timer.fire()
func adjustmentBestSongBpmHeartRate() {
print("frr")
}
I found that creating the timer in an OperationQueue Operation did not work. I assume this is because there is no runloop.
Therefore, the following code fixed my problem:
DispatchQueue.main.async {
// timer needs a runloop?
self.timeoutTimer = Timer.scheduledTimer(timeInterval: self.timeout, target: self, selector: #selector(self.onTimeout(_:)), userInfo: nil, repeats: false)
}
Timer methods with a selector are supposed to have one parameter: The timer itself. Thus your code should really look like this: 1
Timer.scheduledTimer(timeInterval: 1.1,
target: self,
selector: #selector(self.adjustmentBestSongBpmHeartRate(_:),
userInfo: nil,
repeats: false)
#objc func adjustmentBestSongBpmHeartRate(_ timer: Timer) {
print("frr")
}
Note that if your app only runs on iOS >= 10, you can use the new method that takes a block to invoke rather than a target/selector. Much cleaner and more type-safe:
class func scheduledTimer(withTimeInterval interval: TimeInterval,
repeats: Bool,
block: #escaping (Timer) -> Void) -> Timer
That code would look like this:
timer = Timer.scheduledTimer(withTimeInterval: 1.1,
repeats: false) {
timer in
//Put the code that be called by the timer here.
print("frr")
}
Note that if your timer block/closure needs access to instance variables from your class you have to take special care with self. Here's a good pattern for that sort of code:
timer = Timer.scheduledTimer(withTimeInterval: 1.1,
repeats: false) {
//"[weak self]" creates a "capture group" for timer
[weak self] timer in
//Add a guard statement to bail out of the timer code
//if the object has been freed.
guard let strongSelf = self else {
return
}
//Put the code that be called by the timer here.
print(strongSelf.someProperty)
strongSelf.someOtherProperty = someValue
}
Edit (updated 15 December)
1: I should add that the method you use in the selector has to use Objective-C dynamic dispatch. In Swift 4 and later, the individual methods you reference must be tagged with the #objc tag. In previous versions of Swift you could also declare the entire class that defines the selector with the #objc qualifier, or you could make the class that defined the selector a subclass of NSObject or any class that inherits from NSOBject. (It's quite common to define the method the timer calls inside a UIViewController, which is a subclass of NSObject, so it used to "just work".
Swift 3
In my case it worked after I added to my method the #obj prefix
Class TestClass {
private var timer: Timer?
func start() {
guard timer == nil else { return }
timer = Timer.scheduledTimer(timeInterval: 60, target: self, selector: #selector(handleMyFunction), userInfo: nil, repeats: false)
}
func stop() {
guard timer != nil else { return }
timer?.invalidate()
timer = nil
}
#objc func handleMyFunction() {
// Code here
}
}
Try this -
if #available(iOS 10.0, *) {
self.timer = Timer.scheduledTimer(withTimeInterval: 0.2, repeats: false, block: { _ in
self.update()
})
} else {
self.timer = Timer.scheduledTimer(timeInterval: 0.2, target: self, selector: #selector(self.update), userInfo: nil, repeats: false)
}
Mostly the problem must have been because of iOS version of mobile.
Swift 5, Swift 4 Simple way only call with Dispatch Queue Async
DispatchQueue.main.async
{
self.andicator.stopAnimating()
self.bgv.isHidden = true
Timer.scheduledTimer(withTimeInterval: 1.0, repeats: false, block: { _ in
obj.showAlert(title: "Successfully!", message: "Video save successfully to Library directory.", viewController: self)
})
}
I have solved the question asked by myself.
I'm using apple watch to control my iphone app.
I try to press a button on apple watch to present a new viewcontroller on iphone.
When I write Timer in override func viewDidLoad(), Timer doesn't work. I move Timer to override func viewWillAppear() it works.
I think maybe there's something wrong with controlling by apple watch
I found that if you try to initialize the timer directly at the class-level, it won't work if you're targeting a selector in that same class. When it fires, it can't find the selector.
To get around this, I only initialize the timer after the object containing the selector has been initialized. If it's in the same class, put the initialization code in the ViewDidLoad or similar. Just not in the initializer. Then it will work. No dispatch queue needed.
Also, you do not need to use a selector that accepts the timer as a parameter. You can, but contrary to the answer with a ton of votes, that's not actually true, or more specifically, it works fine for me without it, just as you have it without it.
By the way, I think the reason the dispatch queue worked is because you're forcing the timer to be created after the object was initializing, confirming my above statement.
let timer:Timer?
override func viewDidLoad(){
super.viewDidLoad()
timer = Timer.scheduledTimer(timeInterval: 1.1, target: self, selector: #selector(adjustmentBestSongBpmHeartRate), userInfo: nil, repeats: false)
timer.fire()
}
func adjustmentBestSongBpmHeartRate() {
print("frr")
}
Note: This is code typed from memory, not copied from Xcode so it may not compile, but hopefully you get the idea.
Swift3
var timer = Timer()
timer = Timer.scheduledTimer(timeInterval: 5, target: self, selector: #selector(self.compruebaConexion), userInfo: nil, repeats: true)
my two cents.
I read about "didLoad" and when invoking it.
so we can use a delay:
class ViewController: UIViewController {
var timer: Timer?
override func viewDidLoad() {
super.viewDidLoad()
startTimer()
}
final func killTimer(){
self.timer?.invalidate()
self.timer = nil
}
final private func startTimer() {
// make it re-entrant:
// if timer is running, kill it and start from scratch
self.killTimer()
let fire = Date().addingTimeInterval(1)
let deltaT : TimeInterval = 1.0
self.timer = Timer(fire: fire, interval: deltaT, repeats: true, block: { (t: Timer) in
print("hello")
})
RunLoop.main.add(self.timer!, forMode: RunLoopMode.commonModes)
}
I have tried many approaches that I have found in other questions and any of them are working. My problem is that the timer is not calling selector
class MyViewController: UIViewController{
var progressBarTimer = NSTimer()
#IBOutlet weak var progress_bar: UIProgressView!
override func viewDidLoad() {
self.progress_bar.progress = 0
self.progressBarTimer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: #selector(MyViewController.updateProgress(_:)), userInfo: nil, repeats: true)
//also tried and redefining the updateProgress without timer parameter:
/*
*self.progressBarTimer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: #selector(MyViewController.updateProgress), userInfo: nil, repeats: true)
*/
}
func updateProgress(timer:NSTimer!) {
progress_bar.progress += 0.1
if (progress_bar.progress >= 1) {
progressBarTimer.invalidate()
}
}
}
I have tried to do
progressBarTimer.fire()
and it just executes once the updateProgress function.
Could anyone shed light on? I would really appreciate
You can call your function like this:
let postes = ["1","2","3"]
let timer = NSTimer.scheduledTimerWithTimeInterval(0.1, target: self, selector: "playProgressBar:", userInfo: postes, repeats: true)
and function must like this:
func playProgressBar(timerSender : NSTimer) {
//Do Somethings
}
Replying to myself, I have found the problem. In the previous ViewController I am performing a segue after doing a http connection. In order to make it work, I have embedded the performSegue inside the dispatch:
dispatch_async(dispatch_get_main_queue(), {
self.performSegueWithIdentifier("goMySecondController", sender: nil)
})
In that second Controller is where I have the Timer that was not working. However, after this change is working properly.
Thanks for replies!
I have a problem with delaying computer's move in a game.
I've found some solutions but they don't work in my case, e.g.
var delay = NSTimer.scheduledTimerWithTimeInterval(4, target: self, selector: nil, userInfo: nil, repeats: false)
I tried to use this with function fire but also to no effects.
What other possibilities there are?
Swift 3
With GCD:
let delayInSeconds = 4.0
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + delayInSeconds) {
// here code perfomed with delay
}
or with a timer:
func myPerformeCode() {
// here code to perform
}
let myTimer : Timer = Timer.scheduledTimer(timeInterval: 4, target: self, selector: #selector(self.myPerformeCode), userInfo: nil, repeats: false)
Swift 2
With GCD:
let seconds = 4.0
let delay = seconds * Double(NSEC_PER_SEC) // nanoseconds per seconds
let dispatchTime = dispatch_time(DISPATCH_TIME_NOW, Int64(delay))
dispatch_after(dispatchTime, dispatch_get_main_queue(), {
// here code perfomed with delay
})
or with a timer:
func myPerformeCode(timer : NSTimer) {
// here code to perform
}
let myTimer : NSTimer = NSTimer.scheduledTimerWithTimeInterval(4, target: self, selector: Selector("myPerformeCode:"), userInfo: nil, repeats: false)
With Swift 4.2
With Timer You can avoid using a selector, using a closure instead:
Timer.scheduledTimer(withTimeInterval: 1.0, repeats: false) { (nil) in
// Your code here
}
Keep in mind that Timer is toll-free bridged with CFRunLoopTimer, and that run loops and GCD are two completely different approaches.... e
In swift we can delay by using Dispatch_after.
SWift 3.0 :-
DispatchQueue.main.asyncAfter(deadline: .now()+4.0) {
alert.dismiss(animated: true, completion: nil)
}
How about using Grand Central Dispatch?
https://developer.apple.com/library/ios/documentation/Performance/Reference/GCD_libdispatch_Ref/index.html
Valfer has shown you how
I'm trying to use an NSTimer in my app, and was wondering if it's possible to call two methods when the timer fires.
Here's the code:
gameTimer = NSTimer.scheduledTimerWithTimeInterval(0.01, target: self, selector:
Selector("gameMovement" && "fireBullet"), userInfo: nil, repeats: true)
I'm getting an error saying there are two arguments in the Selector.
Nope. You would call just one method that delegates to all the things you want.
func someFunc() {
gameTimer = NSTimer.scheduledTimerWithTimeInterval(
0.01,
target: self,
selector: Selector("timerFired"),
userInfo: nil,
repeats: true
)
}
func timerFired() {
gameMovement()
fireBullet()
}
This is a more maintainable pattern anyway, as it's easier to see how your code flows.