我一遍又一遍地使用相同的代码块。我如何巩固它?
I keep using this same chunk of code over and over. How do I consolidate it?
作为 Swift 菜鸟,我发现自己在复制和粘贴代码。我知道我应该使用 DRY 方法而不是这样做,但是这段特殊的代码让我感到难过。我尝试创建一个结构来保存它,但该结构抛出了各种错误。我不太了解 类 以及我将如何对其进行子类化,所以也许这就是解决方案。我只是不知道该怎么做?或者可能是延期?
无论如何,这是我在每个新视图控制器中不断复制和粘贴的代码:
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
这是我对扩展的尝试。我简化并重构了我的代码,但和以前一样,它给了我一个错误。这次错误是 'extensions must not contain stored properties'。那么如何访问 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)
}
}
为什么这行不通?
您是否考虑过使用更传统的继承模型?
class VideoPlayingBaseController: : UIViewController, UITableViewDataSource, UITableViewDelegate {
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)
}
}
然后让你的 类 使用它:
class Step3JobSummaryVC: VideoPlayingBaseController {
//more code here
}
我将从为您的功能定义协议开始,如下所示:
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 协议添加到控制器时,您将可以使用您的自定义功能,而其他不应具有该功能的控制器将无法访问此方法。
另外,如果您真的想访问该方法
func playerDidFinishPlaying(playerVC: AVPlayerViewController, note: NSNotification, video: Video)
将其添加到协议中并从实现中删除私有语句。
并且您的视频播放器没有显示,因为您将播放器的显示添加到通知块中。
此外,请考虑为您的块添加适当的自我处理。现在我觉得有可能是自己被卡住了。
只是为了让你知道声明
其中自我:UIViewController
将实现的访问限制为 UIViewControllers,因此如果将协议添加到 UIView 子类,您将无法访问默认实现。然后您将需要添加一个新的 :) 这可以防止在您不希望使用它的地方丢失协议。
您可以将所有重复使用的代码移动到一个单独的 class:
class Step3JobSummaryVC: UIViewController {
let videoPlayer = VideoPlayer(video: Video.step3JobsSummary)
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
videoPlayer.start(on: self)
}
}
final
class VideoPlayer {
private var initialLaunch: Bool = true
private let playerVC = AVPlayerViewController()
private let video: Video
init(video: Video) {
self.video = video
}
func start(on viewController: UIViewController) {
if initialLaunch == true {
showUnplayedVideo(on: viewController)
initialLaunch = false
}
Video.updatePlaybackTime(playerVC: playerVC, videoURL: video.url, firebaseVideoID: video.firebaseID)
}
func showUnplayedVideo(on viewController: UIViewController) {
// 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, preferredTimescale: 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)
viewController.present(self.playerVC, animated: true) {
self.playerVC.player?.play()
}
}
}
}
@objc func playerDidFinishPlaying(note: NSNotification) {
self.playerVC.dismiss(animated: true)
Video.updateFirebase(firebaseVideoID: video.firebaseID)
}
}
作为 Swift 菜鸟,我发现自己在复制和粘贴代码。我知道我应该使用 DRY 方法而不是这样做,但是这段特殊的代码让我感到难过。我尝试创建一个结构来保存它,但该结构抛出了各种错误。我不太了解 类 以及我将如何对其进行子类化,所以也许这就是解决方案。我只是不知道该怎么做?或者可能是延期?
无论如何,这是我在每个新视图控制器中不断复制和粘贴的代码:
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
这是我对扩展的尝试。我简化并重构了我的代码,但和以前一样,它给了我一个错误。这次错误是 'extensions must not contain stored properties'。那么如何访问 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)
}
}
为什么这行不通?
您是否考虑过使用更传统的继承模型?
class VideoPlayingBaseController: : UIViewController, UITableViewDataSource, UITableViewDelegate {
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)
}
}
然后让你的 类 使用它:
class Step3JobSummaryVC: VideoPlayingBaseController {
//more code here
}
我将从为您的功能定义协议开始,如下所示:
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 协议添加到控制器时,您将可以使用您的自定义功能,而其他不应具有该功能的控制器将无法访问此方法。 另外,如果您真的想访问该方法
func playerDidFinishPlaying(playerVC: AVPlayerViewController, note: NSNotification, video: Video)
将其添加到协议中并从实现中删除私有语句。
并且您的视频播放器没有显示,因为您将播放器的显示添加到通知块中。
此外,请考虑为您的块添加适当的自我处理。现在我觉得有可能是自己被卡住了。
只是为了让你知道声明 其中自我:UIViewController 将实现的访问限制为 UIViewControllers,因此如果将协议添加到 UIView 子类,您将无法访问默认实现。然后您将需要添加一个新的 :) 这可以防止在您不希望使用它的地方丢失协议。
您可以将所有重复使用的代码移动到一个单独的 class:
class Step3JobSummaryVC: UIViewController {
let videoPlayer = VideoPlayer(video: Video.step3JobsSummary)
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
videoPlayer.start(on: self)
}
}
final
class VideoPlayer {
private var initialLaunch: Bool = true
private let playerVC = AVPlayerViewController()
private let video: Video
init(video: Video) {
self.video = video
}
func start(on viewController: UIViewController) {
if initialLaunch == true {
showUnplayedVideo(on: viewController)
initialLaunch = false
}
Video.updatePlaybackTime(playerVC: playerVC, videoURL: video.url, firebaseVideoID: video.firebaseID)
}
func showUnplayedVideo(on viewController: UIViewController) {
// 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, preferredTimescale: 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)
viewController.present(self.playerVC, animated: true) {
self.playerVC.player?.play()
}
}
}
}
@objc func playerDidFinishPlaying(note: NSNotification) {
self.playerVC.dismiss(animated: true)
Video.updateFirebase(firebaseVideoID: video.firebaseID)
}
}