Realm – удаление и добавление объектов из списка
Это продолжение этого вопроса, поскольку я могу делать что-то неправильно.
У меня есть видеопроигрыватель в моем приложении. В виде коллекции под названием FavoritesVC
есть список видео. Если вы нажмете на одну из ячеек, появится новый контроллер вида PlayerVC
, который воспроизводит выбранное видео. Кроме того, вы можете просматривать все видео из коллекции в этом новом контроллере PlayerVC
потому что весь список передан.
Здесь все отлично.
- Правильный синтаксис этого оператора JSON для передачи полей массива в переменные в Swift?
- iOS coreData Повторение данных и добавление чего-то, что я не хранил
- Выполнить код на экране запуска ОБНОВЛЕНО
- Обновление обеих сторон контроллера UISplitView
- Как сохранить контакт в приложении «Контакты» в iOS - Swift
Проблема в том, когда я хочу любимого / непривлекательного видео. Из вопроса, который я написал выше, я решил использовать это из ответа:
Добавьте свойство isDeleted в класс Video. Когда пользователь отключил видео, удалите объект Video из FavoriteList.videos, установите для этого свойства значение true, но оставьте его в Realm. Позже (либо когда приложение закрывается, либо диспетчер представлений отклоняется), вы можете затем выполнить общий запрос для всех объектов, где isDeleted является истинным, и затем удалить их (это решает проблему без головы).
Я могу заставить это работать только в том случае, если в FavoritesVC
когда ячейка прослушивается, я конвертирую List
PlayerVC
array
Swift и использую этот array
для включения PlayerVC
. Если я этого не сделаю, и я удаляю объект из List
и я пытаюсь перебирать List
, я получаю Index out of range error...
Решение, которое я должен преобразовать List
в array
Swift и передать его в 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 } } }
Есть предположения?
- Swift - проблема с последовательностью SKAction
- Быстрая ошибка: фатальная ошибка: нельзя индексировать пустой буфер
- Swift: конвертировать Int в UInt32 и как развернуть необязательный
- Swift 2.2 #selector для ошибки компиляции делегата / протокола
- Как передавать данные из всех TableViewCell в CollectionView в Swift3
- Представитель CALayer иногда вызывается только при использовании Swift
- Как я могу сделать фон представления UICollection прозрачным, не делая прозрачные ячейки в Swift
- Как найти идентификатор навигационного контроллера из ViewController?
Это все еще трудно ответить кратко, так как я все еще не уверен, что вы хотите, когда пользователь «незаметен» видео.
Для лучшего удобства пользователей я бы предположил, что нежелательное видео по-прежнему позволяет воспроизводить его на экране, но после того, как диспетчер представлений отклонен или начнется следующее видео, видео было полностью удалено из объекта favoriteList
. Это означает, что даже когда он удаляется из videos
, объект Video
необходимо придерживаться, пока пользователь явно не отклонит его.
Я предполагаю, почему преобразование 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] } }
Это работает в предположении, что пользователь «может» удалять currentVideo
videos
из videos
, но пользователь не может удалить nextVideo
или previousVideo
videos
, пока они не станут currentVideo
. В любом случае, теперь, когда сам контроллер представления сильно ссылается на этот видеообъект, отдельно от индекса, мы надеемся сделать ненужным скопирование videos
в массив Swift.