作为 Swift 菜鸟,我发现自己在复制和粘贴代码。我知道我应该使用 DRY 方法而不是这样做,但是这段特殊的代码让我感到难过。我尝试创建一个结构来保存它,但该结构抛出了各种错误。我不太了解类以及如何对其进行子类化,所以也许这就是解决方案。我只是不知道该怎么做?或者可能是扩展?
无论如何,这是我在每个新 View Controller 中不断复制和粘贴的代码:
import UIKit
import AVKit
class Step3JobSummaryVC: UIViewController, UITableViewDataSource, UITableViewDelegate {
...
var sourceVCIdentity = "setup"
var initialLaunch = true
let playerVC = AVPlayerViewController()
let video = Video.step3JobsSummary
...
// ------------------------
// Autoplay Video Functions
// ------------------------
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if initialLaunch == true {
showUnplayedVideo()
initialLaunch = false
}
Video.updatePlaybackTime(playerVC: playerVC, videoURL: video.url, firebaseVideoID: video.firebaseID)
}
func showUnplayedVideo() {
// 1. get current video data
Video.getFirebaseData(firebaseVideoID: video.firebaseID) { (playbackTime, watched) in
if !watched {
// 2. show setup video popup on first load
guard let videoURL = URL(string: self.video.url) else { print("url error"); return }
let player = AVPlayer(url: videoURL)
self.playerVC.player = player
// 3. fast forward to where user left off (if applicable)
player.seek(to: CMTimeMakeWithSeconds(playbackTime, 1))
// 4. dismiss the player once the video is over and update Firebase
NotificationCenter.default.addObserver(self,
selector: #selector(self.playerDidFinishPlaying),
name: NSNotification.Name.AVPlayerItemDidPlayToEndTime,
object: self.playerVC.player?.currentItem)
self.present(self.playerVC, animated: true) {
self.playerVC.player?.play()
}
}
}
}
@objc func playerDidFinishPlaying(note: NSNotification) {
self.playerVC.dismiss(animated: true)
Video.updateFirebase(firebaseVideoID: video.firebaseID)
}
任何帮助都会很棒。我只是想学习 :-)
编辑#1
这是我对扩展的尝试。我简化并重构了我的代码,但和以前一样,它给了我一个错误。这次错误是“扩展不能包含存储的属性”。那么如何访问 AVPlayerController?!?
extension UIViewController {
let playerVC = AVPlayerViewController()
func showUnplayedVideo(video: Video) {
// 1. get current video data
Video.getFirebaseData(firebaseVideoID: video.firebaseID) { (playbackTime, watched) in
if !watched {
// 2. show setup video popup on first load
guard let videoURL = URL(string: video.url) else { print("url error"); return }
let player = AVPlayer(url: videoURL)
self.playerVC.player = player
// 3. fast forward to where user left off (if applicable)
player.seek(to: CMTimeMakeWithSeconds(playbackTime, 1))
// 4. dismiss the player once the video is over and update Firebase
NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime,
object: playerVC.player?.currentItem,
queue: .main) { (notification) in
self.playerDidFinishPlaying(note: notification as NSNotification)
self.present(self.playerVC, animated: true) {
self.playerVC.player?.play()
}
}
}
}
func playerDidFinishPlaying(note: NSNotification, video: Video) {
self.playerVC.dismiss(animated: true)
Video.updateFirebase(firebaseVideoID: video.firebaseID)
}
}
编辑 #2
所以我得到了编译代码,没有任何错误,但现在它没有触发。啊。
extension UIViewController {
func showUnplayedVideo(playerVC: AVPlayerViewController, video: Video) {
print("does this code even fire?")
// 1. get current video data
Video.getFirebaseData(firebaseVideoID: video.firebaseID) { (playbackTime, watched) in
if !watched {
// 2. show setup video popup on first load
guard let videoURL = URL(string: video.url) else { print("url error"); return }
let player = AVPlayer(url: videoURL)
playerVC.player = player
// 3. fast forward to where user left off (if applicable)
player.seek(to: CMTimeMakeWithSeconds(playbackTime, 1))
// 4. dismiss the player once the video is over and update Firebase
NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime,
object: playerVC.player?.currentItem,
queue: .main) { (notification) in
self.playerDidFinishPlaying(playerVC: playerVC, note: notification as NSNotification, video: video)
self.present(playerVC, animated: true) {
playerVC.player?.play()
}
}
}
}
}
func playerDidFinishPlaying(playerVC: AVPlayerViewController, note: NSNotification, video: Video) {
playerVC.dismiss(animated: true)
Video.updateFirebase(firebaseVideoID: video.firebaseID)
}
}
为什么这行不通?
最佳答案
我将从为您的功能定义协议(protocol)开始,如下所示:
protocol VideoPlayable {
func showUnplayedVideo(playerVC: AVPlayerViewController, video: Video)
}
然后给它添加一个默认的实现
extension VideoPlayable where Self: UIViewController {
func showUnplayedVideo(playerVC: AVPlayerViewController, video: Video) {
print("does this code even fire?")
// 1. get current video data
Video.getFirebaseData(firebaseVideoID: video.firebaseID) { (playbackTime, watched) in
if !watched {
// 2. show setup video popup on first load
guard let videoURL = URL(string: video.url) else { print("url error"); return }
let player = AVPlayer(url: videoURL)
playerVC.player = player
// 3. fast forward to where user left off (if applicable)
player.seek(to: CMTimeMakeWithSeconds(playbackTime, 1))
// 4. dismiss the player once the video is over and update Firebase
NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime,
object: playerVC.player?.currentItem,
queue: .main) { (notification) in
self.playerDidFinishPlaying(playerVC: playerVC, note: notification as NSNotification, video: video)
}
self.present(playerVC, animated: true) {
playerVC.player?.play()
}
}
}
}
private func playerDidFinishPlaying(playerVC: AVPlayerViewController, note: NSNotification, video: Video) {
playerVC.dismiss(animated: true)
Video.updateFirebase(firebaseVideoID: video.firebaseID)
}
}
多亏了这一点,当您将 VideoPlayable 协议(protocol)添加到 Controller 时,您将拥有可用的自定义功能,而其他不应具有该功能的 Controller 将无法访问此方法。 另外,如果您真的想访问该方法
func playerDidFinishPlaying(playerVC: AVPlayerViewController, note: NSNotification, video: Video)
将其添加到协议(protocol)中并从实现中删除私有(private)语句。
并且您的视频播放器没有显示,因为您将播放器的显示添加到通知 block 中。
此外,请考虑为您的 block 添加适当的 self 处理。现在我认为 self 可能会陷入困境。
只是让你知道声明 其中 self :UIViewController 将实现的访问限制为 UIViewControllers,因此如果将协议(protocol)添加到 UIView 子类,您将无法访问默认实现。然后您需要添加一个新的 :) 这可以防止在您不希望使用它的地方丢失该协议(protocol)。
关于swift - 我一遍又一遍地使用相同的代码块。我如何巩固它?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52729507/