我不断重复使用相同的代码块。我如何巩固它?

时间:2018-10-09 21:21:33

标签: swift struct dry subclassing

作为我的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

这是我的扩展尝试。我简化并重构了代码,但像以前一样,这给了我一个错误。这次错误是“扩展名不得包含存储的属性”。那么如何访问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)
}
}

为什么这行不通?

3 个答案:

答案 0 :(得分:1)

我将从为您的功能定义协议开始,像这样:

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)

将其添加到协议中,并从实现中删除私有语句。

您的视频播放器没有显示,因为您将播放器的显示添加到了通知栏中。

此外,请考虑为块添加适当的自我处理。现在,我认为自己有可能陷入困境。

只是让您知道声明     哪里Self:UIViewController 将实现的访问限制为UIViewControllers,因此,如果将协议添加到UIView子类,则将无法访问默认实现。然后,您需要添加一个新的:),这可以防止在您不希望使用该协议的地方丢失该协议。

答案 1 :(得分:1)

您可以将所有重用的代码移到一个单独的类中

a

答案 2 :(得分:0)

您是否考虑过使用更传统的继承模型?

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
}