how to delay a execution? - ios

I am creating a small project such that after pressing a button which
will take me to the next view controller using the navigation controller - can i delay the function to execute the navigation controller after some time
i am using this code-
import UIKit
class ViewController: UIViewController
{
#IBAction func enterButtonPressed(_ sender: UIButton)
{
let vc = storyboard?.instantiateViewController(withIdentifier: "ViewController2") as! ViewController2
self.navigationController?.pushViewController(vc, animated: true)
}
override func viewDidLoad()
{
super.viewDidLoad()
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
}
}

Suppose sender.tag holds the duration which is 0 for proceed , 5 or 10
var playTimer:Timer?
//
#IBAction func btnClicked(_ sender:UIButton) {
playTimer?.invalidate()
playTimer = Timer.scheduledTimer(withTimeInterval: TimeInterval(sender.tag), repeats: false, block: { (T) in
// play the audio
})
}

Try this one
var timeLimit = 5.0
DispatchQueue.main.asyncAfter(deadline: .now() + timeLimit, execute: {
//Play your audio here
//Audio will play after 5 seconds here
})

Related

UIprogressView (progerssView) animation is not restarting

I am playing around to learn and implemented a progressView that is triggered using a function and reset using another one when buttons are clicked (and feed it with value). For some reason, after the first click, it works fine even though the functions are called also on the following clicks and the progressView is reset, its animation is not restarting (checked functions and values are all correct using print()...)
import UIKit
class ViewController: UIViewController {
let eggTimes = ["Soft" : 5, "Medium" : 7, "Hard": 12]
#IBOutlet weak var progressView: UIProgressView!
//reset the progress bar
func resetProgress(){
progressView.setProgress(0, animated: true)
print("function progress view reset fired")
}
//starts the prgress bar
func startProgressView(duration: Double) {
UIView.animate(withDuration: duration) {
print("progress bar has been initiated")
self.progressView.setProgress(1.0, animated: true)
}
}
#IBAction func hardnessSelected(_ sender: UIButton) {
resetProgress()
print("progress bar has been reset")
let hardness = sender.currentTitle!
var timerCounter = eggTimes[hardness]! * 10
let temp1: Double = Double(timerCounter)
print("temp 1 = \(temp1) ")
self.startProgressView(duration: temp1)
print(eggTimes[hardness]!)
let timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { (timer) in
if timerCounter > 0 {
timerCounter -= 1
// print(timerCounter)
}
else {
print("egg ready")
timer.invalidate()
}
}
}
}

viewWillDisappear error/stop playing sound when i change viewController

I have some ViewCotroller where i tapped a button - some audio file is playing. I want to stop playing audio when change/close this ViewController. How I can do this?
I try add some method to viewWillDisappear and it crashed if I don't tap any button. But if I tapped some button - it will works fine. 🙁
import UIKit
import AVFoundation
class BossViewController: UIViewController {
var audioPlayer = AVAudioPlayer()
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
//MARK: - Stop sound when we're change/close this viewController
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
audioPlayer.stop()
}
This is how my button is look like:
#IBAction func boss1(_ sender: AnyObject) {
let audioFile = NSURL(fileURLWithPath: Bundle.main.path(forResource: "shamp", ofType: "mp3")!)
do {
audioPlayer = try AVAudioPlayer(contentsOf: audioFile as URL)
audioPlayer.prepareToPlay()
} catch {
print("Problem in getting File")
}
audioPlayer.play()
}
You can check if the audio player is playing, as #SandeepBhandari mentioned, or you can use a Bool variable to keep track whether or not the user tapped the button:
var buttonTapped = false
#IBAction func boss1(_ sender: AnyObject) {
...
buttonTapped = true
}
Then, you can check the variable in your viewWillDisappear(_ animated: Bool) method:
override func viewWillDisappear(_ animated: Bool) {
if buttonTapped {
audioPlayer.stop()
}
}

Simple Timer in iOS

I'm trying to make a simple timer in iOS using Swift.
The program is working fine but whenever my START UIButton is pressed the function of timer starts and runs multiple time as much as the button is pressed.
I want to disable the START UIButton as soon as the timer function starts so that it does not run multiple times.
Please help me for the same.
This is my code of ViewController
import UIKit
class ViewController: UIViewController {
var time = 0.0
var timer = Timer()
#IBOutlet weak var lbl: UILabel!
#IBAction func start(_ sender: UIButton)
{
timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(ViewController.action), userInfo: nil, repeats: true)
}
#IBAction func pause(_ sender: UIButton)
{
timer.invalidate()
}
#IBAction func reset(_ sender: UIButton)
{
timer.invalidate()
time = 0.0
lbl.text = ("0")
}
func action()
{
time += 0.1
lbl.text = String(time)
}
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.
}
}
To disable your button you can just set it's isUserInteractionEnabled property in start function:
#IBOutlet weak var startButton: UIButton!
#IBAction func start(_ sender: UIButton) {
timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(ViewController.action), userInfo: nil, repeats: true)
startButton.isEnabled = false
}
Then set it back to true in pause and reset methods:
#IBAction func pause(_ sender: UIButton) {
timer.invalidate()
startButton.isEnabled = true
}
#IBAction func reset(_ sender: UIButton) {
timer.invalidate()
startButton.isEnabled = true
//the rest of your code
}
The most reliable way to ensure that the timer is only started and stopped once is writing two methods which check the current state (timer is not nil if it's currently running):
var timer : Timer?
func startTimer()
{
guard timer == nil else { return }
timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(ViewController.action), userInfo: nil, repeats: true)
// disable start button
}
func stopTimer()
{
guard timer != nil else { return }
timer!.invalidate()
timer = nil
// enable start button
}
In the methods you can enable/disable the button(s) accordingly.

Counting up/down numbers animation

I have an UIPageViewController with a number in the center of each VC in it.
I want that when I swipe from view to view, the number will begin at 0 and count up until it gets to the correct number (or if the number is negative - count down) like in this gif:
https://d13yacurqjgara.cloudfront.net/users/345970/screenshots/2126044/shot.gif
How can I do that?
Thank you!
You can use NSTimer to achieve this.
Here is example project I created for you.
Create layout like this:
Then in your ViewController do like so:
import UIKit
class ViewController: UIViewController {
#IBOutlet var countingLabel: UILabel!
var number = 0
var destinationNumber = 30
var timer: NSTimer!
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 startButtonTapped(sender: AnyObject) {
timer = NSTimer.scheduledTimerWithTimeInterval(0.1, target: self, selector: "countUp", userInfo: nil, repeats: true)
}
func countUp() {
if number < destinationNumber {
number += 1
countingLabel.text = "\(number)"
} else {
timer.invalidate()
}
}
}
It will work.
Do not overcomplicate with timers and invalidations, etc.
extension UILabel {
func countAnimation(upto: Double) {
let from: Double = text?.replace(string: ",", replacement: ".").components(separatedBy: CharacterSet.init(charactersIn: "-0123456789.").inverted).first.flatMap { Double($0) } ?? 0.0
let steps: Int = 20
let duration = 0.350
let delay = duration / Double(steps)
let diff = upto - from
for i in 0...steps {
DispatchQueue.main.asyncAfter(deadline: .now() + delay * Double(i)) {
self.text = "\(from + diff * (Double(i) / Double(delay)))"
}
}
}
}

How to pass an AVPlayer from Source VC to Destination VC using a custom segue?

I created a simple ViewController class that plays a livestream video using AVPlayer. The livestream is loaded in viewDidLoad and when the user presses play, it plays the livestream, simple enough.
The parent VC is set for portrait orientation only.
I have another button that segues to another ViewController using a custom segue.
How do I pass the AVPlayer and its "state" to the destination ViewController?......i.e. if the AVPlayer is currently playing, it should maintain its state when it's passed from parent VC to destination VC.
FYI: I'm not using prepareForSegue.
Here's the complete simple code:
ViewController.swift:
class ViewController: UIViewController {
#IBOutlet var playerView: UIView!
var player = AVPlayer()
var avPlayerLayer: AVPlayerLayer!
override func viewDidLoad()
{
super.viewDidLoad()
let url = "http://vevoplaylist-live.hls.adaptive.level3.net/vevo/ch1/appleman.m3u8" //"http://68.235.37.11:1935/vietmagazine/vietmagazine/playlist.m3u8"
let playerItem = AVPlayerItem( URL:NSURL( string:url )! )
player = AVPlayer(playerItem:playerItem)
avPlayerLayer = AVPlayerLayer(player: player)
// Add the layer to the view
playerView.layer.insertSublayer(avPlayerLayer, atIndex: 0)
}
#IBAction func playVIdeo(sender: AnyObject)
{
avPlayerLayer.player!.play()
}
#IBAction func change(sender: AnyObject)
{
avPlayerLayer.player!.pause()
self.performSegueWithIdentifier("CustomSegue", sender: self)
}
override func viewWillLayoutSubviews()
{
super.viewWillLayoutSubviews()
// Layout subviews manually
avPlayerLayer.frame = playerView.bounds
}
}
CustomSegue.swift:
class CustomSegue: UIStoryboardSegue
{
override func perform()
{
let sourceVC = self.sourceViewController
let destinationVC = self.destinationViewController
sourceVC.view.addSubview(destinationVC.view)
destinationVC.view.transform = CGAffineTransformMakeScale(0.05, 0.05)
UIView.animateWithDuration(0.5, delay: 0.0, options: .CurveEaseInOut, animations: { () -> Void in
destinationVC.view.transform = CGAffineTransformMakeScale(1.0, 1.0)
} ) { (finished) -> Void in
destinationVC.view.removeFromSuperview()
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(0.001 * Double(NSEC_PER_SEC)))
dispatch_after(time, dispatch_get_main_queue(), { () -> Void in
sourceVC.presentViewController(destinationVC, animated: false, completion: nil)
})
}
}
}
Thanks.
Would passing the AVPlayer instance be enough to pass the player and its state?
Not tested, but does this work? In the first view controller:
class ViewController: UIViewController {
var player = AVPlayer()
#IBAction func myAction(sender: AnyObject) {
performSegueWithIdentifier("TheSegue", sender: self)
}
}
class MySegue: UIStoryboardSegue {
override func perform() {
let viewController = sourceViewController as! ViewController
let secondViewController = destinationViewController as! SecondViewController
secondViewController.player = viewController.player
sourceViewController.presentViewController(destinationViewController, animated: true, completion: nil)
}
}
And in the second view controller:
class SecondViewController: UIViewController {
var player: AVPlayer!
override func viewDidLoad() {
// Do something with the player
}
}
Note, this answer show how to check an AVPlayer;'s state.

Resources