Error in NSTimer (Swift: Xcode) - ios

I am making a timer that will call a function repeatedly with swift 2, Xcode 7. This function sends a local push notification. My timer variable is declared outside the viewDidLoad() in ViewController.swift.
var timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self , selector: Selector("notification"), userInfo: nil, repeats: true)
I am getting an error:
Argument Type 'NSObject -> () -> ViewController does not conform to expected type 'AnyObject'
It seems there is some problem with the target self as it is highlighted in red.
Here is my full code if needed:
import UIKit
class ViewController: UIViewController {
var time = 10
var timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self , selector: Selector("notification"), userInfo: nil, repeats: true)
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func btnPressed(sender: AnyObject) {
let alertView = UIAlertController(title: "You won!", message: "Press Go to continue!", preferredStyle: UIAlertControllerStyle.Alert)
self.presentViewController(alertView, animated: true, completion: nil)
alertView.addAction(UIAlertAction(title: "Go", style: UIAlertActionStyle.Default, handler: nil))
}
func notification(){
time--
if (time == 0){
let notification = UILocalNotification()
notification.alertAction = "Go back to App!"
notification.alertBody = "Pls Go back to my App!"
notification.fireDate = NSDate(timeIntervalSinceNow: 0)
UIApplication.sharedApplication().scheduleLocalNotification(notification)
timer.invalidate()
}
}
}
Thanks in advance:)

Try to declare the var timer only setting as NSTimer.init() like:
var timer = NSTimer.init()
And then, put the initialization with scheduledTimerWithInterval inside viewDidLoad():
override func viewDidLoad() {
super.viewDidLoad()
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "notification", userInfo: nil, repeats: true)
}

Related

How to record not only the app's screen but everything on the screen, including other apps

I'm trying to implement screen recording app using ReplayKit(Swift). It seems when I'm going outside the app, stops background record. After trying some documents, so far I understand I need to implement Broadcast Extension. If my understanding is right, then So please give me some programming guide about that.
Try this library
Screen capture
OR this one:
Vid recorder
import ScreenCapture
let recorder = ScreenCapture.recordScreen("/path/to/save/to.mp4")
recorder.start()
...
recorder.stop()
let movieUrl = recorder.destination
Otherwise you could do:
import ReplayKit
import UIKit
class ViewController: UIViewController, RPPreviewViewControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Start", style: .plain, target: self, action: #selector(startRecording))
}
#objc func startRecording() {
let recorder = RPScreenRecorder.shared()
recorder.startRecording{ [unowned self] (error) in
if let unwrappedError = error {
print(unwrappedError.localizedDescription)
} else {
self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Stop", style: .plain, target: self, action: #selector(self.stopRecording))
}
}
}
#objc func stopRecording() {
let recorder = RPScreenRecorder.shared()
recorder.stopRecording { [unowned self] (preview, error) in
self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Start", style: .plain, target: self, action: #selector(self.startRecording))
if let unwrappedPreview = preview {
unwrappedPreview.previewControllerDelegate = self
self.present(unwrappedPreview, animated: true)
}
}
}
func previewControllerDidFinish(_ previewController: RPPreviewViewController) {
dismiss(animated: true)
}
}
Replay Kit only record it's current app screen, whenever the app becomes background, the recording will be stopped and that's by-design.

How do I fix this code to allow for the timer to begin as a result of the user clicking on the UIAlert?

Trying to make a timer start as a result of the UIAlert being clicked on. But I keep getting this error indicating the instances isTimerRunning and runTimer cannot be used on the thirdViewController.
We have been trying to move it around, thinking it is a scope issue, but cannot seem to get it to be ok with those functions.
When we adjusted it to use alert.copyAction, rather than let.. the error changes to "expected declaration".
var seconds = 60
var timer = Timer()
var isTimerRunning = false
var resumeTapped = false
let alert = UIAlertController(title: "Your wing was damaged! There is also a dust storm incoming! You need to repair the wing and escape to the next planet.", message: nil, preferredStyle: .alert)
let copyAction = UIAlertAction(title: "Copy that mission control!", style: .default, handler: { action in
if isTimerRunning == false {
runTimer()
}
})
func runTimer() {
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: (#selector(thirdViewController.updateTimer)), userInfo: nil, repeats: true)
}
#objc func updateTimer() {
if seconds < 1 {
timer.invalidate()
} else {
seconds -= 1
timeLabel.text = timeString(time: TimeInterval(seconds))
}
}
func timeString(time:TimeInterval) -> String {
let hours = Int(time) / 3600
let minutes = Int(time) / 60 % 60
let seconds = Int(time) % 60
return String(format:"%02i:%02i:%02i”, hours, minutes, seconds")
}
override func viewDidLoad() {
super.viewDidLoad()
Timer.scheduledTimer(withTimeInterval: 0.0, repeats: false) { (timer) in
self.alert.addAction(self.copyAction)
self.present(self.alert,animated: true, completion: nil)
}
}
//use run timer method in alert controller).so you can start timer with open alert
override func viewDidLoad() {
super.viewDidLoad()
Timer.scheduledTimer(withTimeInterval: 0.0, repeats: false) { (timer) in
runtimer()
self.alert.addAction(self.copyAction)
self.present(self.alert,animated: true, completion: nil)
}
}

Getting : "Attempt to dismiss from view controller while a presentation or dismiss is in progress"

A Swift 4 quiz app.
First view - select num of questions to solve. (use segue to second view)
Second view - start quiz ->checked answer and send "correct" or "wrong" msg to third view. (use segue way to third view)
When the third view appears I get the error:
Attempt to dismiss from view controller <XXX.StartQuizViewController: 0x7fc893f09770> while a presentation or dismiss is in progress!
I've tried using:
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0, execute:....
The warning message goes away but the problem is that I have no access to all the variables that I obtained from the second view for use in the third view.
override func viewDidLoad() {
super.viewDidLoad()
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0, execute: {
if self.answerStatus == "Correct!" {
self.correctWrongStatusLabel.text = self.answerStatus
self.praiseLabel.text = "Good job!"
self.correctAnswerIsLabel.text = ""
let timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(self.fireTimer), userInfo: nil, repeats: false)
self.fireTimer()
} else if self.answerStatus == "Wrong!" {
self.correctWrongStatusLabel.text = self.answerStatus
self.praiseLabel.text = "Maybe next time!"
self.correctAnswerIsLabel.text = "回答 : \(self.correctAnswerIs)"
let timer = Timer.scheduledTimer(timeInterval: 3.0, target: self, selector: #selector(self.fireTimer), userInfo: nil, repeats: false)
self.fireTimer()
}
})
#objc func fireTimer() {
delegate?.answerStatusReceived(answerStatusString: answerStatusString)
self.dismiss(animated: true, completion: nil)
}
After the second view appear with the quiz, when the user select an answer, it will checked it against the correct answer and display a response saying the answer is correct or wrong. the response view must automatically closes after displaying for XX seconds.
I think you can't dismiss VC while in load, even if you add delay but no guarantee. Try add timer in viewDidAppear. Also, your self.fireTimer() doesn't necessary.
override func viewDidLoad() {
super.viewDidLoad()
if self.answerStatus == "Correct!" {
self.correctWrongStatusLabel.text = self.answerStatus
self.praiseLabel.text = "Good job!"
self.correctAnswerIsLabel.text = ""
} else if self.answerStatus == "Wrong!" {
self.correctWrongStatusLabel.text = self.answerStatus
self.praiseLabel.text = "Maybe next time!"
self.correctAnswerIsLabel.text = "回答 : \(self.correctAnswerIs)"
}
}
override func viewDidAppear() {
super.viewDidAppear()
if self.answerStatus == "Correct!" {
let timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(self.fireTimer), userInfo: nil, repeats: false)
} else if self.answerStatus == "Wrong!" {
let timer = Timer.scheduledTimer(timeInterval: 3.0, target: self, selector: #selector(self.fireTimer), userInfo: nil, repeats: false)
}
}
#objc func fireTimer() {
delegate?.answerStatusReceived(answerStatusString: answerStatusString)
self.dismiss(animated: true, completion: nil)
}
Have you tried removing the DispatchQueue method?
I would do it like this:
override func viewDidLoad() {
super.viewDidLoad()
if self.answerStatus == "Correct!" {
self.correctWrongStatusLabel.text = self.answerStatus
self.praiseLabel.text = "Good job!"
self.correctAnswerIsLabel.text = ""
let timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(self.fireTimer), userInfo: nil, repeats: false)
self.fireTimer()
} else if self.answerStatus == "Wrong!" {
self.correctWrongStatusLabel.text = self.answerStatus
self.praiseLabel.text = "Maybe next time!"
self.correctAnswerIsLabel.text = "回答 : \(self.correctAnswerIs)"
let timer = Timer.scheduledTimer(timeInterval: 3.0, target: self, selector: #selector(self.fireTimer), userInfo: nil, repeats: false)
self.fireTimer()
}
}
#objc func fireTimer() {
delegate?.answerStatusReceived(answerStatusString: answerStatusString)
dismiss(animated: true, completion: nil)
}
I think you included the function FireTimer() inside the viewDidLoad method, so I would add a bracket "}" in the line before the function.
Let me know if it works! :)
simply use:-- dismiss(animated: true, completion: nil) and omit self

Countdown timer shown inside of button in UIAlertController then enable button swift update

This is a previous post. As I am new I can not comment.
Thanks to Muhammad Zeeshan as his aswer worked for me until...
Since the latest swift the code changed. Now you click the cancel button and get the error Unexpectedly found nil while unwrapping an Optional value on line
let alertController = presentedViewController as! UIAlertController
Actual updated code
var timer = Timer()
var timerCount: Int = 5
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
#IBAction func okButton(_ sender: Any) {
showAlertView()
}
func showAlertView() {
let alertController = UIAlertController(title: "Title", message: "Message of alert", preferredStyle: .alert)
let okAction = UIAlertAction(title: "Ok", style: .default, handler: nil)
okAction.isEnabled = false
alertController.addAction(okAction)
alertController.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
present(alertController, animated: true) {
timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(self.countDownTimer), userInfo: nil, repeats: true)
}
}
#objc func countDownTimer() {
timerCount -= 1
let alertController = presentedViewController as! UIAlertController
let okAction = alertController.actions.first
if timerCount == 0 {
timer.invalidate()
okAction?.setValue("Ok", forKey: "title")
okAction?.isEnabled = true
} else {
okAction?.setValue("Ok \(timerCount)", forKey: "title")
}
}}
So I am wondering how to kill it without the error.
Once I figured out unwrapping an optional it was easy.
Just before
let alertController = presentedViewController as! UIAlertController
Do
if presentedViewController == nil {
timer.invalidate()
return
}
Also I had to add
timerCount = 5
before
showAlertView()
To reset the counter.

How can I display a popup message in Swift that disappears after 3 seconds or can be cancelled by user immediatelly?

In my swift app I have a UIViewController with a single button.
This button invokes a function that calls a popup that disappears after 3 seconds. Also, after that time it prints a message to the console. The code of this function is as follows:
func showAlertMsg(title: String, message: String){
let alertController = UIAlertController(title: title, message: message, preferredStyle: .Alert)
self.presentViewController(alertController, animated: true, completion: nil)
let delay = 3.0 * Double(NSEC_PER_SEC)
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(delay))
dispatch_after(time, dispatch_get_main_queue(), {
alertController.dismissViewControllerAnimated(true, completion: nil)
print("popup disappeared")
})
}
That works fine, but I wanted to introduce some improvement. I wanted to add there a button that will cancel this popup immediately and then avoid displaying the message in the console. Is there a way of displaying such popup to the user? Also - is there a way of showing in this popup message the counter with number of seconds running out that shows how much time is left until the popup disappears?
You can use an NSTimer to decrement a counter, update the alert view and dismiss the alert view when the counter reaches 0. This code is adapted from my Objective-C answer
class ViewController: UIViewController {
var alertController: UIAlertController?
var alertTimer: NSTimer?
var remainingTime = 0
var baseMessage: String?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
self.showAlertMsg("Test Alert", message: "This will disappear in ", time: 5)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func showAlertMsg(title: String, message: String, time: Int) {
guard (self.alertController == nil) else {
print("Alert already displayed")
return
}
self.baseMessage = message
self.remainingTime = time
self.alertController = UIAlertController(title: title, message: self.alertMessage(), preferredStyle: .Alert)
let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel) { (action) in
print("Alert was cancelled")
self.alertController=nil;
self.alertTimer?.invalidate()
self.alertTimer=nil
}
self.alertController!.addAction(cancelAction)
self.alertTimer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: #selector(ViewController.countDown), userInfo: nil, repeats: true)
self.presentViewController(self.alertController!, animated: true, completion: nil)
}
func countDown() {
self.remainingTime -= 1
if (self.remainingTime < 0) {
self.alertTimer?.invalidate()
self.alertTimer = nil
self.alertController!.dismissViewControllerAnimated(true, completion: {
self.alertController = nil
})
} else {
self.alertController!.message = self.alertMessage()
}
}
func alertMessage() -> String {
var message=""
if let baseMessage=self.baseMessage {
message=baseMessage+" "
}
return(message+"\(self.remainingTime)")
}
}
Just in case someone needs it, this is a Swift 4 version of the #Paulw11 solution
import UIKit
class ViewController: UIViewController {
var alertController: UIAlertController?
var alertTimer: Timer?
var remainingTime = 0
var baseMessage: String?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.showAlertMsg(title: "Test Alert", message: "This will disappear in ", time: 5)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func showAlertMsg(title: String, message: String, time: Int) {
guard (self.alertController == nil) else {
print("Alert already displayed")
return
}
self.baseMessage = message
self.remainingTime = time
self.alertController = UIAlertController(title: title, message: self.alertMessage(), preferredStyle: .alert)
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { (action) in
print("Alert was cancelled")
self.alertController=nil;
self.alertTimer?.invalidate()
self.alertTimer=nil
}
self.alertController!.addAction(cancelAction)
self.alertTimer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(ViewController.countDown), userInfo: nil, repeats: true)
self.present(self.alertController!, animated: true, completion: nil)
}
#objc func countDown() {
self.remainingTime -= 1
if (self.remainingTime < 0) {
self.alertTimer?.invalidate()
self.alertTimer = nil
self.alertController!.dismiss(animated: true, completion: {
self.alertController = nil
})
} else {
self.alertController!.message = self.alertMessage()
}
}
func alertMessage() -> String {
var message=""
if let baseMessage=self.baseMessage {
message=baseMessage+" "
}
return(message+"\(self.remainingTime)")
}
}
I know this directly doesn't answer your question, but have you considered using MBProgressHUD SCLAlertView? They both offer functions that allow you to display an alert that disappears after a set amount of time. SCLAlertView allows the user to cancel immediately where as MBProgressHUD does not. If you want more info on how to implement these, let me know so I can add more info!

Resources