Reputation: 475
I have a class for managing AVPlayer
and ViewController
showing AVPlayer
. In ViewController
I have 3 IBOutlets
:
@IBOutlet weak var playButton: UIButton!
@IBOutlet weak var progressBar: UIProgressView!
@IBOutlet weak var timerLabel: UILabel!
The problem is I can't figure out how to pass IBOutlets
from ViewController
to my player managing class. I always get nil
and
fatal error: unexpectedly found nil while unwrapping an Optional value
when initialising progressBar
, timerLabel
or playButton
.
Here is some code from my player managing class:
import UIKit
import AVFoundation
class RecordsAudioPlayer: NSObject
{
var player = AVPlayer()
var timerUpdateAudioProgressView = Timer()
var timerUpdateTime = Timer()
var isPlaying: Bool = false
...
func updateAudioProgressView()
{
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "callRecords") as! CallRecordsViewController
let progressBar = vc.progressBar!
print("method fired: updateAudioProgressView ", NSDate.init(timeIntervalSinceNow: 0).description)
if isPlaying
{
let currentPlayerItem = player.currentItem
let duration = Float((currentPlayerItem?.asset.duration.value)!)/Float((currentPlayerItem?.asset.duration.timescale)!)
let currentTime = Float(player.currentTime().value)/Float(player.currentTime().timescale)
progressBar.setProgress(Float(currentTime/duration), animated: false)
}
}
func updateTime()
{
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "callRecords") as! CallRecordsViewController
let timerLabel: UILabel! = vc.timerLabel! //***I get exception here
print("method fired: updateTime ", NSDate.init(timeIntervalSinceNow: 0).description)
let currentTime = Int64(player.currentTime().value)/Int64(player.currentTime().timescale)
let minutes = currentTime / 60
let seconds = currentTime - minutes * 60
timerLabel.text = String(format: "%02d : %02d", Int(minutes), Int(seconds))
}
Upvotes: 0
Views: 637
Reputation: 2451
In this case delegates came for our rescue. Create delegate methods for your RecordsAudioPlayer
class. And use them to update progress bar and timer label.
protocol RecordsAudioPlayerDelegate
{
func audioplayerProgressUpdated(time:CGFloat) // change the method as your wish
}
class RecordsAudioPlayer: NSObject
{
var delegate:RecordsAudioPlayerDelegate?
var player = AVPlayer()
var timerUpdateAudioProgressView = Timer()
var timerUpdateTime = Timer()
var isPlaying: Bool = false
...
...
...
//Call the delegate method from where you get the player current time
self.delegate.audioplayerProgressUpdated(playerTime)
//For controlling play/pause using play button
func playButtonClicked()
{
//play/pause player based on player status
}
}
And inside your ViewController
while/after creating RecordsAudioPlayer
object set delegate as self
class YourViewController : UIViewController, RecordsAudioPlayerDelegate
{
var recordsAudioPlayer : RecordsAudioPlayer!
// set delegate where you create object for RecordsAudioPlayer
self.recordsAudioPlayer.delegate = self
//Now implement the delegate function
func audioplayerProgressUpdated(time:CGFloat)
{
//update progress view and timer label
}
//And inside from the play button action method
@IBAction func playButtonClicked(sender: UIButton)
{
self.recordsAudioPlayer.playButtonClicked()
}
}
Upvotes: 1
Reputation: 10209
Outlet connections get established as soon as the view is loaded - and this is typically deferred until the view is being presented.
You can force this by calling vc.loadViewIfNeeded()
(where vc
is your view controller)
But not quite shure if your implementation of updateAudioProgressView
and updateTime
really do what you expect: They always create new view controllers and update their subviews/outlets. These newly created view controllers don't even get displayed (or you just skipped the presentation code). If your intention was to update an existing view controller, you would have to do something else (e.g. hand in the view controller to be updated).
And just a remark: It is highly recommended that you do not do the things the way you do it. The view controller should be the only one to update it's outlets. Anyone else should just update properties of the view controller (like setting the current progress, time value etc.) and then inform the view controller to update itself. The view controller will then update it's presenting outlets the way it wants.
Upvotes: 1