I am using this code to track and update slider value, then convert to string and show on label. The issue is that, This code works on the simulator, but crashed on the actual phone. With error "unexpectedly found nil while unwrapping an Optional value". I can't figure out what could cause this, any help would be appreciated.
func updateSlider () {
sliderBar.value = Float(CMTimeGetSeconds(self.audioPlayer.currentItem!.currentTime()))
let currentTime = Int((CMTimeGetSeconds(self.audioPlayer.currentItem!.currentTime())))
let duration = Int((CMTimeGetSeconds(self.audioPlayer.currentItem!.asset.duration)))
//let total = currentTime - duration
let minutes = currentTime/60
let seconds = currentTime - minutes * 60
let minutes2 = duration/60
let seconds2 = duration - minutes2 * 60
self.lblPastTime.text = NSString(format: " %02d:%02d / %02d:%02d ",minutes2,seconds2, minutes,seconds) as String
}
Avoiding force unwrapping variables is a good way to avoid errors like that:
func updateSlider () {
guard let currentItem = self.audioPlayer.currentItem else { return }
sliderBar.value = Float(CMTimeGetSeconds(currentItem.currentTime()))
let currentTime = Int((CMTimeGetSeconds(currentItem.currentTime())))
let duration = Int((CMTimeGetSeconds(currentItem.asset.duration)))
//let total = currentTime - duration
let minutes = currentTime/60
let seconds = currentTime - minutes * 60
let minutes2 = duration/60
let seconds2 = duration - minutes2 * 60
self.lblPastTime.text = NSString(format: " %02d:%02d / %02d:%02d ",minutes2,seconds2, minutes,seconds) as? String
}
Using guard let I safely unwrap the variable, so if it's nil, the function returns.
ANSWER
Had to use audioPlayer.currentTime()
Instead of audioPlayer.currentItem!.currentTime()
func updateSlider () {
sliderBar.value = Float(CMTimeGetSeconds(audioPlayer.currentTime()))
// sliderBar.value = Float(CMTimeGetSeconds(self.audioPlayer.currentItem!.currentTime()))
let currentTime = Int((CMTimeGetSeconds(self.audioPlayer.currentItem!.currentTime())))
let duration = Int((CMTimeGetSeconds(self.audioPlayer.currentItem!.asset.duration)))
//let total = currentTime - duration
let minutes = currentTime/60
let seconds = currentTime - minutes * 60
let minutes2 = duration/60
let seconds2 = duration - minutes2 * 60
self.lblPastTime.text = NSString(format: " %02d:%02d / %02d:%02d ",minutes2,seconds2, minutes,seconds) as String
}
Related
I try to check the speed of upload by sending an image to a server via FTP, I know it is not very sharp, but I have no alternative. Issue number one is to test time, this code is always giving me 0 seconds maybe it is right maybe not, but the main issue id that I cannot even divide the size in mb of image by time in seconds, since time elapsed is expressed in dateComponent, how to do it?
using this code
func pushfileUpload() {
print("uploading...")
let startDate = NSDate()
//*****************************************************************
//find file in app bundle
let imageChecked = findFileInBundle(nameWithNoEx: "image", extension: "jpg")
//convert to Data
let imageData = imageChecked.jpegData(compressionQuality: 1)
//instanziate the class
let ftpUploader = FTPUpload.init(baseUrl: Constants.kHostname, userName: Constants.kUsername, password: Constants.kPassword, directoryPath: Constants.kFolder)
ftpUploader.send(data: imageData!, with: "image") { (result) in
if result {
print("result is \(result)")
} else {
print("no result")
}
}
//*****************************************************************
print("...uploaded")
let endDate = NSDate()
let difference = timeDifference(date1: startDate as Date, date2: endDate as Date)
// print("Time difference is : \(difference)")
//1 converto to string
let differenceString = String(difference)
//2 pick first 3 ints
let array = differenceString.compactMap{Int(String($0))}
//3 create new int
let newInt = array[0...3]
var newString = ""
for i in newInt {
newString.append(i.description)
}
var fromIntToString = Int(newString)
fromIntToString = fromIntToString! * 1000
let speed = 1500 / fromIntToString!
print("speed: \(speed)")
}
func timeDifference(date1: Date, date2: Date) -> Int {
let calendar = NSCalendar.current
var compos:Set<Calendar.Component> = Set<Calendar.Component>()
// compos.insert(.second)
compos.insert(.nanosecond)
let difference = calendar.dateComponents(compos, from: date1, to: date2)
// print("diff in seconds= \(difference.second!)") // difference in seconds
print("diff in nanoseconds = \(difference.nanosecond!)") // difference in nanoseconds
let newValue = difference.nanosecond!
return newValue
}
//UPADTED code
func pushfileUpload() {
print("uploading...")
let startDate = Date()
//*****************************************************************
//find file in app bundle
let imageChecked = findFileInBundle(nameWithNoEx: "image", extension: "jpg")
//convert to Data
let imageData = imageChecked.jpegData(compressionQuality: 1)
//instanziate the class
let ftpUploader = FTPUpload.init(baseUrl: Constants.kHostname, userName: Constants.kUsername, password: Constants.kPassword, directoryPath: Constants.kFolder)
ftpUploader.send(data: imageData!, with: "image") { (result) in
if result {
print("result is \(result)")
//-----------------------------------------------------
//Your code to calculate elapsed time belongs here
let endDate = Date()
let elapsed = endDate.timeIntervalSinceReferenceDate -
startDate.timeIntervalSinceReferenceDate
print("The download took \(elapsed) seconds.")
print("speed is \(1500 / elapsed)")
//-----------------------------------------------------
} else {
print("no result")
}
}}
prints on console
The download took 1.281269907951355 seconds.
speed is 1170.7135168720042
As others have said, you need to move your code that calculates total time inside your closure:
func pushfileUpload() {
print("uploading...")
let startDate = Date()
//*****************************************************************
//find file in app bundle
let imageChecked = findFileInBundle(nameWithNoEx: "image", extension: "jpg")
//convert to Data
let imageData = imageChecked.jpegData(compressionQuality: 1)
//instanziate the class
let ftpUploader = FTPUpload.init(baseUrl: Constants.kHostname, userName: Constants.kUsername, password: Constants.kPassword, directoryPath: Constants.kFolder)
ftpUploader.send(data: imageData!, with: "image") { (result) in
if result {
print("result is \(result)")
//-----------------------------------------------------
//Your code to calculate elapsed time belongs here
let endDate = Date()
let elapsed = endDate.timeIntervalSinceReferenceDate -
startDate.timeIntervalSinceReferenceDate
print("The download took \(elasped) seconds."
//-----------------------------------------------------
} else {
print("no result")
}
}
...
As others have mentioned, there's no reason to deal with date components. The method timeIntervalSinceReferenceDate gives you a double precision count of seconds for a date, so it's easy to do math on dates to figure out the difference between them. You can evaluate the difference to as many decimal places as you want.
I have AVPlayer when I rewind an audio file, then the current time is longer than the total file duration. Who knows what the problem is, why is the current time wrong?
#objc func updateProgressBar(){
guard let value = AppDelegate.avPlayer.currentItem?.currentTime().seconds else { return }
let time = Func.getHoursMinutesSecondsFrom(seconds: value)
DispatchQueue.main.async {
self.startTime.text = time.fullTime
}
}
func durationAudio(){
// расчитывает время аудиозвука
guard let duration = AppDelegate.avPlayer.currentItem?.asset.duration else { return }
let time = Func.getHoursMinutesSecondsFrom(seconds: CMTimeGetSeconds(duration))
DispatchQueue.main.async {
self.endTime.text = time.fullTime
}
}
converts to hours, minutes, seconds
static func getHoursMinutesSecondsFrom(seconds: Double) -> (hours: Int, minutes: Int, seconds: Int, fullTime:String) {
let secs = Int(seconds)
let hours = secs / 3600
let minutes = (secs % 3600) / 60
let seconds = (secs % 3600) % 60
let duration:String!
if hours != 0 {
duration = String(format:"%02d:%02d:%02d", hours, minutes, seconds)
} else {
duration = String(format:"%02d:%02d", minutes, seconds)
}
return (hours, minutes, seconds, duration)
}
rewind audio
func seekTo(completion:Bool){
let duration = CMTimeGetSeconds(AppDelegate.avPlayer.currentItem!.asset.duration)
let value = self.sliderSong.value
let durationToSeek = Float(duration) * value
let timeScale = AppDelegate.avPlayer.currentItem!.duration.timescale
AppDelegate.avPlayer.seek(to: CMTimeMakeWithSeconds(Float64(durationToSeek), preferredTimescale: timeScale), toleranceBefore: CMTime.zero, toleranceAfter: CMTime.zero) { [weak self](bool) in
guard completion else { return }
self?.seeking = false
}
}
I have this function that calculate the amount of time from the current minute of the phone. I am trying to have a timer go off after this specific amount of time. The way this function is called is through a switch that the user flips in the app and the time should reset it self. Well Im having trouble with my NSDate object getting old values when the switch was flipped before. Is there a way to reset the NSDate object to zero?
Here is my code for the calculating the current time of the phone.
func GetInitialTime(){
finalTime = 0
firstTimeCounter = 0
timeInSeconds = 0
let calendar = NSCalendar.current
var minutes = calendar.component(.minute, from: date)
var timeDifference = Int()
if(minutes == 00 || minutes == 30) {
print("The minute hand is at zero or thirty.")
}
else {
print("The minute hand is NOT ar zero or thirty")
print("The minute hand ia at:")
if minutes < 30 {
while (!(minutes == 30)) {
minutes += 1
timeDifference += 1
}
print("Therefore we make the minute hand at zero or thiry: ", minutes)
print("The time difference we add to the minute is: ", timeDifference)
}
else {
var i = minutes
while i < 60 {
i += 1
minutes += 1
timeDifference += 1
}
print("Therefore we make the minute hand at zero or thirty: ", minutes)
print("The Time difference we add to the minute is: ", timeDifference)
}
}
finalTime = Double(timeDifference * 60)
print("The time difference in seconds is:", finalTime)
}
And I declare the Date() object here
let center = UNUserNotificationCenter.current()
let button = UIButton(type: UIButtonType.custom)
let date = Date()
var timeInSeconds = Int()
var finalTime = Double()
var halfHour = Double(1800)
var firstTimeCounter = Int()
var firstTimer = Timer()
var repeatingTimer = Timer()
var backgroundTask = BackgroundTask()
let dispatchGroup = DispatchGroup()
var urlWeb = "http://morrowrenewablesflowdata.com/iOSConnections/Notifications.php"
var downtimes = [String]()
var flows = [String]()
Your code is using an instance variable date that is a let constant. You don't show the context in which it's set, but I'm assuming it's an instance variable of your class. The fact that it's a let constant means it will never change in the scope in which it's declared. That's almost certainly your problem.
I tried to build an app to play the MP3 files. I want to get current time and duration to show it in 2 labels while playing.
I used this code:
let duration = Int((player1?.duration)!)
let minutes2 = duration/60
let seconds2 = duration - minutes2 * 60
durLabel.text = NSString(format: "%02d:%02d", minutes2,seconds2) as String
let currentTime1 = Int((player1?.currentTime)!)
let minutes = currentTime1/60
let seconds = currentTime1 - minutes * 60
curLabel.text = NSString(format: "%02d:%02d", minutes,seconds) as String
In duration it shows the half time of the song.
For example:
If the duration of the song is 20 minutes and 40 seconds, it shows the half like that 10:20. But it did not make progress in the case of current time, it shows 00:00
Thanks at all.
// this is to compute and show remaining time
let duration = Int((player1?.duration - (player1?.currentTime))!)
let minutes2 = duration/60
let seconds2 = duration - minutes2 * 60
durLabel.text = NSString(format: "%02d:%02d", minutes2,seconds2) as String
//This is to show and compute current time
let currentTime1 = Int((player1?.currentTime)!)
let minutes = currentTime1/60
let seconds = currentTime1 - minutes * 60
curLabel.text = NSString(format: "%02d:%02d", minutes,seconds) as String
The player's current time will not automatically update. Instead, you have to periodically update the current time using a timer. Take a look at the following thread if you want more details.
check avaudioplayer's current playback time
If you have Slider to seek on mp3 file, like this :
#IBOutlet weak var slidetOutlet: UISlider!
You can update your UILabel like this:
self.lblPlayerTime.text = self.secondsToHoursMinutesSeconds(seconds: Double( self.slidetOutlet.value ))
to initial your Player and Slider :
func playerInit() {
guard let url = URL(string: urlAudio) else {
return
}
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
print("AVAudioSession Category Playback OK")
do {
try AVAudioSession.sharedInstance().setActive(true)
print("AVAudioSession is Active")
playerItem = AVPlayerItem(url: url)
player = AVPlayer(playerItem: playerItem)
player!.addPeriodicTimeObserver(forInterval: CMTimeMakeWithSeconds(1, 1), queue: DispatchQueue.main) { (CMTime) -> Void in
if self.player!.currentItem?.status == .readyToPlay {
let time : Float64 = CMTimeGetSeconds(self.player!.currentTime());
self.slidetOutlet.value = Float ( time )
self.slidetOutlet.minimumValue = 0
let duration : CMTime = self.playerItem!.asset.duration
let seconds : Float64 = CMTimeGetSeconds(duration)
self.slidetOutlet.maximumValue = Float(seconds)
self.lblStartTimePlayer.text = self.secondsToHoursMinutesSeconds(seconds: seconds)
self.lblPlayerTime.text = self.secondsToHoursMinutesSeconds(seconds: Double( self.slidetOutlet.value ))
}
}
} catch let error as NSError {
print(error.localizedDescription)
}
} catch let error as NSError {
print(error.localizedDescription)
}
}
and for convert the time :
func secondsToHoursMinutesSeconds (seconds : Double) -> (String) {
let (hr, minf) = modf (seconds / 3600)
let (min, secf) = modf (60 * minf)
return ("\(Int(hr)):\(Int(min)):\(Int(60 * secf))")
}
This function gets current time and finds the next time in an array. When the current time is before midday and the next time is after midday, it returns the next time as am when it should be pm.
How can I change this? Would I need to use a 12 hour clock instead of a 24 hour clock?
import UIKit
import Foundation
let date = NSDate()
let calendar = NSCalendar.currentCalendar()
let components = calendar.components([.Hour, .Minute], fromDate: date)
let hour = components.hour
let minutes = components.minute
let currentTime = "\(hour)" + ":" + "\(minutes)" //output 10:47
let timesArray = ["5:45", "6:35", "7:00", "7:30", "7:50", "8:20", "8:40", "9:15", "10:10",
"12:40", "14:15", "14:50", "15:40", "16:10", "17:10", "17:40", "18:40", "19:25", "20:50"]
// create a method to convert your time to minutes
func stringToMinutes(input:String) -> Int {
let components = input.componentsSeparatedByString(":")
let hour = Int((components.first ?? "0")) ?? 0
let minute = Int((components.last ?? "0")) ?? 0
return hour*60 + minute
}
//create an array with the minutes from the original array
let timesMinutesArray:[Int] = timesArray.map { stringToMinutes($0) }
let dayMinute = stringToMinutes(currentTime)
// filter out the times that has already passed
let filteredTimesArray = timesMinutesArray.filter{$0 > dayMinute }
// get the first time in your array
if let firstTime = filteredTimesArray.first {
// find its position and extract it from the original array
let nextDeparture = timesArray[timesMinutesArray.indexOf(firstTime)!] // output "12:40"
let userCalendar = NSCalendar.currentCalendar()
let dateMakerFormatter = NSDateFormatter()
dateMakerFormatter.calendar = userCalendar
dateMakerFormatter.dateFormat = "yyyy/MM/dd"
// How many hours and minutes between current time and next departure?
dateMakerFormatter.dateFormat = "h:mm"
let startTime = dateMakerFormatter.dateFromString(currentTime)!
let endTime = dateMakerFormatter.dateFromString(nextDeparture)! //this comes back as 12:40 am not pm
let hourMinuteComponents: NSCalendarUnit = [.Hour, .Minute]
let timeDifference = userCalendar.components(
hourMinuteComponents,
fromDate: startTime,
toDate: endTime,
options: [])
let difference = (timeDifference.hour*60) + (timeDifference.minute)
}
Try a capital H in your dateFormat:
dateMakerFormatter.dateFormat = "H:mm"