如何在两个 类 之间传递 IBOutlet?
How to pass IBOutlet between two classes?
我有一个 class 用于管理 AVPlayer
和 ViewController
显示 AVPlayer
。在 ViewController
我有 3 IBOutlets
:
@IBOutlet weak var playButton: UIButton!
@IBOutlet weak var progressBar: UIProgressView!
@IBOutlet weak var timerLabel: UILabel!
问题是我不知道如何将 IBOutlets
从 ViewController
传递给我的玩家管理 class。我总是得到 nil
和
fatal error: unexpectedly found nil while unwrapping an Optional value
初始化时 progressBar
、timerLabel
或 playButton
。
这是我的播放器管理 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))
}
加载视图后立即建立出口连接 - 这通常会延迟到呈现视图时。
您可以通过调用 vc.loadViewIfNeeded()
(其中 vc
是您的视图控制器)来强制执行此操作
但不太确定您的 updateAudioProgressView
和 updateTime
的实现是否真的如您所愿:它们总是创建 new 视图控制器并更新它们的 subviews/outlets。这些新创建的视图控制器甚至不会显示(或者您只是跳过了演示代码)。如果您打算更新现有的视图控制器,则必须执行其他操作(例如,提交要更新的视图控制器)。
还有一点:强烈建议您不要按照自己的方式做事。视图控制器应该是唯一更新其出口的控制器。其他任何人都应该只更新视图控制器的属性(比如设置当前进度、时间值等),然后通知视图控制器更新自身。然后视图控制器将按照它想要的方式更新它的呈现插座。
在这种情况下,代表们是来救我们的。为您的 RecordsAudioPlayer
class 创建委托方法。并使用它们来更新进度条和计时器标签。
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
}
}
并在您的 ViewController
while/after 中创建 RecordsAudioPlayer
对象并将委托设置为 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()
}
}
我有一个 class 用于管理 AVPlayer
和 ViewController
显示 AVPlayer
。在 ViewController
我有 3 IBOutlets
:
@IBOutlet weak var playButton: UIButton!
@IBOutlet weak var progressBar: UIProgressView!
@IBOutlet weak var timerLabel: UILabel!
问题是我不知道如何将 IBOutlets
从 ViewController
传递给我的玩家管理 class。我总是得到 nil
和
fatal error: unexpectedly found nil while unwrapping an Optional value
初始化时 progressBar
、timerLabel
或 playButton
。
这是我的播放器管理 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))
}
加载视图后立即建立出口连接 - 这通常会延迟到呈现视图时。
您可以通过调用 vc.loadViewIfNeeded()
(其中 vc
是您的视图控制器)来强制执行此操作
但不太确定您的 updateAudioProgressView
和 updateTime
的实现是否真的如您所愿:它们总是创建 new 视图控制器并更新它们的 subviews/outlets。这些新创建的视图控制器甚至不会显示(或者您只是跳过了演示代码)。如果您打算更新现有的视图控制器,则必须执行其他操作(例如,提交要更新的视图控制器)。
还有一点:强烈建议您不要按照自己的方式做事。视图控制器应该是唯一更新其出口的控制器。其他任何人都应该只更新视图控制器的属性(比如设置当前进度、时间值等),然后通知视图控制器更新自身。然后视图控制器将按照它想要的方式更新它的呈现插座。
在这种情况下,代表们是来救我们的。为您的 RecordsAudioPlayer
class 创建委托方法。并使用它们来更新进度条和计时器标签。
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
}
}
并在您的 ViewController
while/after 中创建 RecordsAudioPlayer
对象并将委托设置为 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()
}
}