领域 - 从列表中删除和添加对象
Realm - Removing and adding objects from List
这是的后续,因为我可能做错了什么。
我的应用程序中有一个视频播放器。在名为 FavoritesVC
的集合视图中有一个视频列表。如果您点击其中一个单元格,则会出现一个名为 PlayerVC
的新视图控制器来播放所选视频。此外,您可以在这个新的视图控制器中循环浏览集合视图中的所有视频 PlayerVC
,因为整个列表都已传递。
这里一切正常。
问题是当我想要 favorite/unfavorite 视频时。从我上面发布的问题来看,我决定从答案中使用这个:
Add an isDeleted property to the Video class. When the user
unfavorites the video, remove the Video object from
FavoriteList.videos, set that property to true, but leave it in Realm.
Later on (either when the app quits or the view controller is
dismissed), you can then do a general query for all objects where
isDeleted is true and delete them then (This solves the headless
problem).
只有在 FavoritesVC
中点击一个单元格时,我才能将领域 List
转换为 Swift array
并使用此 array
为 PlayerVC
供电。如果我不这样做,我从 List
中删除了一个对象,然后我尝试在 List
中循环,我得到一个 Index out of range error...
.
我必须将 List
转换为 Swift array
并将其传递给 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"
}
}
我将列表转换为数组并创建 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
}
}
}
有什么想法吗?
这仍然很难简洁地回答,因为我仍然不确定当用户 'unfavorites' 视频时您想发生什么。
为了最好的用户体验,我认为取消收藏视频仍会让它在屏幕上播放,但是一旦视图控制器被关闭,或者下一个视频开始播放,视频就会完全从favoriteList
object。这意味着即使它从 videos
中删除,Video
object 也需要保留,直到用户明确将其关闭。
我猜测将 videos
转换为 Swift 数组的原因是因为即使视频从 videos
中删除,其引用仍保留在 Swift 数组,因此 currentVideoIndex
值保持同步。
应该可以直接使用 videos
object,但是由于当用户点击 'unfavorite' 按钮时你正在改变它,你不能可靠地存储'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]
}
}
假设用户 'may' 最终从 videos
中删除了 currentVideo
,但用户无法删除 nextVideo
或 previousVideo
] 直到他们也变成了 currentVideo
。在任何情况下,既然视图控制器本身正在强烈引用这些视频 object,与索引分开,这应该有希望使将 videos
复制到 Swift 数组变得不必要。
这是
我的应用程序中有一个视频播放器。在名为 FavoritesVC
的集合视图中有一个视频列表。如果您点击其中一个单元格,则会出现一个名为 PlayerVC
的新视图控制器来播放所选视频。此外,您可以在这个新的视图控制器中循环浏览集合视图中的所有视频 PlayerVC
,因为整个列表都已传递。
这里一切正常。
问题是当我想要 favorite/unfavorite 视频时。从我上面发布的问题来看,我决定从答案中使用这个:
Add an isDeleted property to the Video class. When the user unfavorites the video, remove the Video object from FavoriteList.videos, set that property to true, but leave it in Realm. Later on (either when the app quits or the view controller is dismissed), you can then do a general query for all objects where isDeleted is true and delete them then (This solves the headless problem).
只有在 FavoritesVC
中点击一个单元格时,我才能将领域 List
转换为 Swift array
并使用此 array
为 PlayerVC
供电。如果我不这样做,我从 List
中删除了一个对象,然后我尝试在 List
中循环,我得到一个 Index out of range error...
.
我必须将 List
转换为 Swift array
并将其传递给 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"
}
}
我将列表转换为数组并创建 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
}
}
}
有什么想法吗?
这仍然很难简洁地回答,因为我仍然不确定当用户 'unfavorites' 视频时您想发生什么。
为了最好的用户体验,我认为取消收藏视频仍会让它在屏幕上播放,但是一旦视图控制器被关闭,或者下一个视频开始播放,视频就会完全从favoriteList
object。这意味着即使它从 videos
中删除,Video
object 也需要保留,直到用户明确将其关闭。
我猜测将 videos
转换为 Swift 数组的原因是因为即使视频从 videos
中删除,其引用仍保留在 Swift 数组,因此 currentVideoIndex
值保持同步。
应该可以直接使用 videos
object,但是由于当用户点击 'unfavorite' 按钮时你正在改变它,你不能可靠地存储'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]
}
}
假设用户 'may' 最终从 videos
中删除了 currentVideo
,但用户无法删除 nextVideo
或 previousVideo
] 直到他们也变成了 currentVideo
。在任何情况下,既然视图控制器本身正在强烈引用这些视频 object,与索引分开,这应该有希望使将 videos
复制到 Swift 数组变得不必要。