I am creating video player app in iOS i am use MpMoviePlayer. All are working good.
My problem is, i want to add now playing feature in my app same like musi app here is link
https://itunes.apple.com/in/app/musi-unlimited-free-music/id591560124?mt=8
I was implement now playing features in my app but it not work smoothly.
Can you help me ya suggest me how to do it???
nowPlaying click btn Action
#IBAction func nowPlaying(sender: AnyObject) {
dataVideoName2.removeAll()
dataAuthorName2.removeAll()
dataVideoId2.removeAll()
let vc = storyboard?.instantiateViewControllerWithIdentifier("player") as! SimpleplayerViewController
vc.videoID = dataVideoId2
vc.videoTitle = dataVideoName2
vc.artist = dataAuthorName2
vc.thumbURL = dataVideoThumb
vc.dismiss = 1
navigationController?.pushViewController(vc, animated: true)
}
Irshad,
You can add an NSTimer to your VIDEO to check the time on a regular basis.
func updateAVDTag() {
let currentPT:Float64 = CMTimeGetSeconds((self.streamPlayer.player?.currentTime())!)
let currentPlayerTString = String(currentPT)
currentPlayerTime = String(currentPlayerTString.characters.prefix(4))
}
self.playingAV = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: "updateAVDTag", userInfo: nil, repeats: true)
And a notification to tell you when it is finished.
NSNotificationCenter.defaultCenter().addObserver(self, selector: "finishedPlaying:", name: AVPlayerItemDidPlayToEndTimeNotification, object: playerItem)
func finishedPlaying(myNotification:NSNotification) {
self.streamPlayer.view.removeFromSuperview()
playingAV.invalidate()
playingAV = nil
print("VIDEO finished")
}
But be careful to make sure that any code to update the UI is running on the main thread and that your player is not a local variable. The code to ensure your running the UI update on the correct thread.
dispatch_async(dispatch_get_main_queue()) {
// Update UI
}
Related
This is what I try to do in code:
for i in 1...1000000000 {
print(i)
self.title = "\(i)"
}
on console it prints everything, but I can't see any updates in my navigation bar. Why?
Actually you could have a look at CADisplayLink which basically is a timer that is synchronized with the refresh of the display. At its most basic form it would be something like this:
func createDisplayLink() {
let displaylink = CADisplayLink(target: self, selector: #selector(step))
displaylink.add(to: .current, forMode: .defaultRunLoopMode)
}
#objc func step(displaylink: CADisplayLink) {
// Do the updates
}
Note: Please note that step will be called a lot, essentially on each screen update, which is 60-120 fps on current devices.
I'm learning how to create a Pomodoro app, and am able to send notifications. However, I am totally clueless as to how to allow my timer label to update itself on reloading the app. Which means the timer works only when the app is open and not when it's in the foreground/background. Hoping to find a tutorial to learn from or just a quick answer code. Thanks!
Edit: Just to clear some misunderstandings, my app's Notification works fine with the timer, for example if 30mins is selected, the app would notify the user after 30mins. However, the problem is that when the app reopens, it resumes for example 29:57 seconds left on the timer label while the 30mins should have passed already.
*Added in AppDelegate*
var seconds = 0 //Timer countdown seconds
var currentDate = NSDate()
var setDate: Int = 0
func pauseApp(){
viewC.timer.invalidate() //invalidate timer
UserDefaults.standard.set(seconds, forKey: "current") //error occurs here where "Cannot assign value of type NSDate to type Timer"
setDate = UserDefaults.standard.integer(forKey: "current")
}
func startApp(){
let difference = currentDate.timeIntervalSince(NSDate() as Date) as Double
seconds = Int(Double(setDate) - difference)
viewC.updateTimer()
}
What someone suggests from a different thread is cancel the timer and store a NSDate when the app goes to the background. He stated we can use this notification to detect the app going to the background:
NSNotificationCenter.defaultCenter().addObserver(self, selector: "pauseApp", name: UIApplicationDidEnterBackgroundNotification, object: nil)
Then cancel the timer and store the date:
func pauseApp(){
self.stop() //invalidate timer
self.currentBackgroundDate = NSDate()
}
Use this notification to detect the user coming back:
NSNotificationCenter.defaultCenter().addObserver(self, selector: "startApp", name: UIApplicationDidBecomeActiveNotification, object: nil)
Then calculate the difference from the stored date to the current date, update your counter and start the timer again:
func startApp(){
let difference = self.currentBackgroundDate.timeIntervalSinceDate(NSDate())
self.handler(difference) //update difference
self.start() //start timer }
However, I do not fully understand this code (namely, the difference between the "handler" and my own "seconds") as am new to programming... Hoping for an answer or helpful insight.
Solved: I managed to solve it myself from this video https://www.youtube.com/watch?v=V6ta24iBNBQ
Using this concept of timeDifference as well as UserDefaults.standard.set....
I managed to adapt it to my personal app with the code
You can call Timer to run the timmer when the view loads.
var runTimer : Timer?
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
runTimer = Timer.scheduledTimer(timeInterval: 3, target: self, selector: #selector(myFun), userInfo: nil, repeats: true)
}
func myFun(){
//do your logic
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
runTimer?.invalidate()
}
Is there any way to merge all UIView returned from function "snapshotViewAfterScreenUpdates" and create a video from them?
Currently i am taking screenshot of screen in Timer event using below code
timer = NSTimer.scheduledTimerWithTimeInterval(0.10, target: self, selector: NSSelectorFromString("screenshotTimerEvent"), userInfo: nil, repeats: true)
// Timer event function to capture screenshot and add in Array
func screenshotTimerEvent()
{
self.arrImagesScreenShots.addObject(self.view.snapshotViewAfterScreenUpdates(true))
}
Then after that when the recording is stopped i use below code to show all those screenshots as a video.
timer = NSTimer.scheduledTimerWithTimeInterval(0.10, target: self, selector: NSSelectorFromString("showImages"), userInfo: nil, repeats: true)
// In this function i am adding uiview from start to end so it shows like a video is playing
func showImages()
{
oldView.removeFromSuperview()
if(arrImagesScreenShots.count > count)
{
oldView = arrImagesScreenShots.objectAtIndex(count) as! UIView
self.view.addSubview(oldView)
count += 1
}
else
{
timer.invalidate()
count = 0
}
}
I am not sure if this is the best way to do it but for now its working.
Next thing i want is to merge these UIView into a video and upload to server.
Is there any way?
I'm trying to have avPlayer restart the current song when the skip back button is selected if it's after about 5 seconds into the song, and jump to times according to where the slider is moved to. Here's my code for these functions:
#IBAction func buttonBackTouchDown(sender: AnyObject) {
if (Float(CMTimeGetSeconds((avPlayerItem?.currentTime())!)) > 5) {
//restartSong = true
avPlayer.currentItem!.seekToTime(kCMTimeZero)
//self.loadSongValues()
//restartSongTimer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("setRestartSongToFalse"), userInfo: nil, repeats: false)
}
else if (Float(CMTimeGetSeconds((avPlayerItem?.currentTime())!)) < 5) {
self.previousSong()
}
}
#IBAction func sliderTouchDown(sender: AnyObject) {
self.sliderTimer.invalidate()
avPlayer.pause()
self.overlayOn()
}
#IBAction func sliderTouchUpInside(sender: AnyObject) {
//restartSongTimer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("setRestartSongToFalse"), userInfo: nil, repeats: false)
//NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("startSliderTimer"), userInfo: nil, repeats: false)
self.startLabelTimer()
avPlayer.play()
self.updateNowPlayingInfoCenter()
self.overlayOff()
}
The problem I'm having is that if the song is over 1 minute in, or it's almost finished and I move the slider too far back, it SOMETIMES triggers this observer:
NSNotificationCenter.defaultCenter().addObserver(self, selector: "skipSong", name: AVPlayerItemDidPlayToEndTimeNotification, object: avPlayerItem)
I tried looking in Apple's references and looked to other questions here on StackOverflow, but couldn't find anything.
Maybe I'm not understanding how to properly use CMTime, or something is weird with the files, but this is really weird to me.
Any help is appreciated. Thanks in advance!
I'm experiencing also a lot of Issues with the AVPlayer and particularly the SeekToTime method.
When you do
avPlayer.currentItem!.seekToTime(kCMTimeZero)
avPlayer is Jumping to the 0 Frame and not the First frame as it should. the Frame #0 and the last frame seem to be the Same for the AVPlayer. Try the Following: (like jumping to time 0.001 instead of 0)
let seekTime : CMTime = CMTimeMake(1, 1000)
avPlayer!.seekToTime(seekTime)
I am trying to use the NSTimer to increment the progress bar in my app when recording voice (see the screenshot)
let timedClock = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("Counting:"), userInfo: nil, repeats: true)
internal func Counting(timer: NSTimer!) {
if timeCount == 0 {
//self.timedClock = nil
stopRecording(self) //performs segue to another view controller
} else {
timeCount--;
self.timer.text = "\(timeCount)"
}
print("counting called!")
progressBar.progress += 0.2
}
The progress bar works only for the first time after I compile and run the project. When the recording is finished, the app performs segue to another view controller to play the recorded audio. However, when I go back to the view for recording, the timer/progress bar automatically runs. I suspect the NSTimer object is still alive on the NSRunLoop. So I was wondering how to prevent the NSTimer from automatically running.
Inspired by the answer in this SO thread, I tried the following, but the NSTimer still automatically runs.
let timedClock = NSTimer(timeInterval: 1, target: self, selector: "Counting:", userInfo: nil, repeats: true)
NSRunLoop.currentRunLoop().addTimer(timedClock, forMode: NSRunLoopCommonModes)
This happens because when your controller created it's properties are automatically initialized. According to Apple Docs (and method's name) scheduledTimerWithTimeInterval create and return scheduled timer. So if you only want create your timer and call it by trigger function use it like this:
class MyClass {
var timer: NSTimer?
...
func enableTimer() {
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("Counting:"), userInfo: nil, repeats: true)
}
func disableTimer() {
timer?.invalidate()
timer = nil
}
...
}
Sorry for the quick self-answer, as I just found out that I can use the invalidate() method to prevent the timer from automatically firing:
timedClock.invalidate()
Hope it helps someone in the future!