2017-04-12 28 views
2

由于我可能做错了事,这是对此question的后续处理。Realm - 从列表中删除和添加对象

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

这里的一切正常。

问题是,当我想要最喜欢/不喜欢的视频。从我上面发布的问题中,我决定从答案中使用它:

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

我只能得到当细胞被窃听这个工作,如果在FavoritesVC,我的境界List转换为雨燕array并使用此arrayPlayerVC供电。如果我不这样做,并且我从List中删除了一个对象,并且我试图循环访问List,我得到一个Index out of range error...

的解决方案,我必须将List转换为雨燕array并传递至PlayerVC作品,但使用时境界好像不对。最佳做法是永远不会做这种转换,但在这种情况下,我不知道如何简单地使用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" 
    } 
} 

我的列表转换为数组并创建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 
     } 
    } 
} 

有什么想法?

回答

1

这仍然很难简明扼要地回答,因为我仍然不确定当用户“不喜欢”某个视频时想要发生什么。

为了获得最佳的用户体验,我认为不合理的视频仍然会让它在屏幕上播放,但一旦视图控制器被解散,或者下一个视频开始播放,视频就会从favoriteList中完全删除目的。这意味着即使将其从videos中删除,对象也需要坚持到用户明确将其解除为止。

我猜为什么转换videos到斯威夫特阵列的工作原理是,因为即使视频从videos删除,其引用保持雨燕阵列中的原因,所以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] 
    } 
} 

这工作,前提是用户“可能”最终从videos删除currentVideo,但用户不能删除nextVideopreviousVideo,直到他们也成为currentVideo。在任何情况下,现在视图控制器本身强烈引用这些视频对象,与索引分开,这应该有希望使videos复制到Swift数组是不必要的。

+0

感谢您的回答!这修复了崩溃!然而,经验与Swift数组不同(除非我做错了什么)。现在发生了什么:假设'PlayerVC'有2个视频。如果你不喜欢其中的一个,那么它会从'favoriteList' - >中移除,但是现在当你执行'playNextVideo'后,你不能在'PlayerVC'中循环回去,因为它不再在'List'中。 Swift'array'的用户体验是:即使视频不合适,即使它不在'PlayerVC'中的'favoriteList'中,您仍然可以循环并再次看到它。 – JEL

+0

抱歉,如果解释有限题。但最终如果Swift'array'是一个不错的选择,那么如果这很好,我也可以使用它呢? – JEL

+0

不用担心!是的,这是有意的。就像我上面写的那样,我假设一旦它不合适,一旦用户导航,它就会完全移除。啊,所以你真的希望视频留在视频播放器的播放列表中,直到他们解散它为止?好的。是的,制作'videos'对象的静态副本对于那个很有用。 – TiM