2

这是这个问题的后续行动,因为我可能做错了什么。

我的应用程序中有一个视频播放器。在名为 的集合视图中有一个视频列表FavoritesVC。如果您点击其中一个单元格,则会出现一个名为的新视图控制器PlayerVC来播放选定的视频。此外,您可以在这个新视图控制器中循环浏览集合视图中的所有视频,PlayerVC因为整个列表都已传递。

这里一切正常。

问题是当我想收藏/取消收藏视频时。根据我上面发布的问题,我决定从答案中使用它:

将 isDeleted 属性添加到 Video 类。当用户取消收藏视频时,从 FavoriteList.videos 中删除 Video 对象,将该属性设置为 true,但将其保留在 Realm 中。稍后(当应用程序退出或视图控制器被关闭时),您可以对所有 isDeleted 为 true 的对象进行一般查询,然后删除它们(这解决了无头问题)。

只有在FavoritesVC点击单元格时,我才能让它工作,我将领域转换List为 Swiftarray并使用它array来为PlayerVC. 如果我不这样做,我从 中删除一个对象,List然后我尝试在 中循环List,我得到一个Index out of range error....

我必须将其转换List为 Swiftarray并将其传递给PlayerVC工作但在使用 Realm 时似乎错误的解决方案。最佳做法是永远不要进行这种转换,但在这种情况下,我不知道如何简单地使用List

这是我的列表代码:

/// Model class that manages the ordering of `Video` objects.
final class FavoriteList: Object {
    // MARK: - Properties

    /// `objectId` is set to a static value so that only
    /// one `FavoriteList` object could be saved into Realm.
    dynamic var objectId = 0

    let videos = List<Video>()

    // MARK: - Realm Meta Information

    override class func primaryKey() -> String? {
        return "objectId"
    }
}

我将 List 转换为数组并像这样创建 PlayerVC:

class FavoritesViewController: UIViewController {

    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {

        if let playerVC = self.storyboard?.instantiateViewController(withIdentifier: "playerVC") as? PlayerViewController {

            // I convert the `List` to a Swift `array` here.
            playerVC.videos = Array(favoritesManager.favoriteList.videos)
            playerVC.currentVideoIndex = indexPath.row
            self.parent?.present(playerVC, animated: true, completion: nil)
        }
    }
}

这是一个片段PlayerVC。这会在点击单元格时创建FavoritesVC

class PlayerViewControllerr: UIViewController {
    // Array passed from `FavoritesVC`. I converted this from the `List`.
    var videos = [Video]()

    var currentVideoIndex: Int!
    var currentVideo: Video {
        return videos[currentVideoIndex]
    }

    // HELP
    // Example of how to cycle through videos. This cause crash if I use the `List` instead of Swift `array`.
    func playNextVideo() {
        if (currentVideoIndex + 1) >= videos.count {
            currentVideoIndex = 0
        } else {
            currentVideoIndex = currentVideoIndex + 1
        }

        videoPlaybackManager.video = currentVideo
    }

    // This is where I add and remove videos from the `List`
    @IBAction func didToggleFavoriteButton(_ sender: UIButton) {
        favoritesManager.handleFavoriting(currentVideo, from: location)     { [weak self] error in
            if let error = error {
            self?.present(UIAlertController.handleErrorWithMessage(error.localizedDescription, error: error), animated: true, completion: nil)
            }
        }
    }
}

最后,添加和删除对象的代码List

class FavoritesManager {
    let favoriteList: FavoriteList

    init(favoriteList: FavoriteList) {
        self.favoriteList = favoriteList
    }

    /// Adds or removes a `Video` from the `FavoriteList`.
    private func handleAddingAndRemovingVideoFromFavoriteList(_ video: Video) {
        if isFavorite(video) {
            removeVideoFromFavoriteList(video)
        } else {
            addVideoToFavoriteList(video)
        }
    }

    /// Adds a `Video` to the `FavoriteList`.
    ///
    /// Modifies `Video` `isDeleted` property to false so no garbage collection is needed.
    private func addVideoToFavoriteList(_ video: Video) {
        let realm = try! Realm()
        try! realm.write {
            favoriteList.videos.append(video)
            video.isDeleted = false
        }
    }

    /// Removes a `Video` from the `FavoriteList`.
    ///
    /// Modifies `Video` `isDeleted` property to true so garbage collection is needed.
    /// Does not delete the `Video` from Realm or delete it's files.
    private func removeVideoFromFavoriteList(_ video: Video) {
        let predicate = NSPredicate(format: "objectId = %@", video.objectId)
        guard let index = favoriteList.videos.index(matching: predicate) else { return }

        let realm = try! Realm()
        try! realm.write {
            favoriteList.videos.remove(objectAtIndex: index)
            video.isDeleted = true
        }
    }
}

有什么想法吗?

4

1 回答 1

1

这仍然很难简明扼要地回答,因为我仍然不确定当用户“取消收藏”视频时您想要发生什么。

为了获得最佳的用户体验,我假设取消收藏视频仍会让它在屏幕上播放,但是一旦视图控制器被关闭,或者下一个视频开始播放,视频就会从favoriteList对象中完全删除。这意味着即使它被从 中移除videosVideo对象也需要一直存在,直到用户明确地解除它。

我猜测转换videos为 Swift 数组有效的原因是因为即使从 中删除视频videos,它的引用仍保留在 Swift 数组中,因此currentVideoIndex值保持同步。

应该可以直接使用该videos对象,但是由于您在用户点击“不喜欢”按钮时对其进行了变异,因此您无法可靠地存储“currentIndex”,因为这显然会改变。

在这种情况下,最好提前确定要播放哪些视频,然后存储对它们的强引用。这样,即使videos发生变异,我们仍然可以智能地计算出我们在播放列表中的位置以及我们将播放的即将播放和之前播放的视频。

播放器视图控制器只需要收藏夹管理器和用户点击的当前视频

class FavoritesViewController: UIViewController {

    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {

        if let playerVC = self.storyboard?.instantiateViewController(withIdentifier: "playerVC") as? PlayerViewController {
            playerVC.favoritesManager = favoritesManager
            playerVC.currentVideo = favoritesManager.favoritesList.videos[indexPath.row]
            self.parent?.present(playerVC, animated: true, completion: nil)
        }
    }
}

即使videos稍后从列表中删除,播放器也会从逻辑上计算出要排队的视频:

class PlayerViewControllerr: UIViewController {
    var favoritesManager: FavoriteManager

    var currentVideo: Video? {
        didSet { setUpVideos() }
    }
    var nextVideo: Video?
    var previousVideo: Video?

    func playNextVideo() {
        currentVideo = nextVideo
        videoPlaybackManager.video = currentVideo
    }

    func playPreviousVideo() {
        currentVideo = previousVideo
        videoPlaybackManager.video = currentVideo
    }

    func setUpVideos() {
        let videos = favoritesManager.favoritesList.videos
        let index = videos.index(of: currentVideo)

        var previousIndex = index - 1
        if previousIndex < 0 { previousIndex = videos.count - 1 }
        previousVideo = videos[previousIndex]

        var nextIndex = index + 1
        if nextIndex >= videos.count { nextIndex = 0 }
        nextVideo = videos[nextIndex]
    }
}

这是在假设用户“可能”最终从 中删除currentVideovideos但用户不能删除nextVideopreviousVideo直到他们也删除的假设下起作用currentVideo。无论如何,既然视图控制器本身强烈引用这些视频对象,与索引分开,这应该有望使复制videos到 Swift 数组变得不必要。

于 2017-04-13T01:25:35.163 回答