У меня есть видеоплеер в моем приложении. В представлении коллекции есть список видео. Если вы нажмете на одну из ячеек, появится новый контроллер представления для воспроизведения выбранного видео. Кроме того, вы можете перебирать все видео из представления коллекции в этом новом контроллере представления, поскольку передается весь список.
Проблема в том, что когда пользователь находится в PlayerVC
, он может удалить из избранного Video
. Если они это сделают, я удалю объект Video
из Realm. Однако это вызывает:
Terminating app due to uncaught exception 'RLMException', reason: 'Object has been deleted or invalidated.'
По сути, если пользователь просматривает видео в PlayerVC
и удаляет его из избранного, я хочу, чтобы он какое-то время все еще мог смотреть это видео. Но когда они оставьте PlayerVC
, представление коллекции в FavoritesVC
должно быть обновлено и больше не будет показывать этот Video
.
Когда я удаляю объект Video
, я использую метод Realm delete
.
Это мой код для хранения списка объектов Video
:
/// 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"
}
}
Это мой класс Video
, который имеет свойство isFavorite
:
final class Video: Object {
// MARK: - Properties
dynamic var title = ""
dynamic var descriptionText = ""
dynamic var date = ""
dynamic var videoId = ""
dynamic var category = ""
dynamic var duration = 0
dynamic var fullURL = ""
dynamic var creatorSite = ""
dynamic var creatorName = ""
dynamic var creatorURL = ""
// MARK: FileManager Properties (Files are stored on disk for `Video` object).
/*
These are file names (e.g., myFile.mp4, myFile.jpg)
*/
dynamic var previewLocalFileName: String?
dynamic var stitchedImageLocalFileName: String?
dynamic var placeholderLocalFileName: String?
/*
These are partial paths (e.g., bundleID/Feed/myFile.mp4, bundleID/Favorites/myFile.mp4)
They are used to build the full path/URL at runtime.
*/
dynamic var previewLocalFilePath: String?
dynamic var stitchedImageLocalFilePath: String?
dynamic var placeholderLocalFilePath: String?
// Other code...
}
Это мой код для отображения объектов Video
в представлении коллекции (Примечание: я использую RealmCollectionChange
для обновления представления коллекции для удаления и вставки ячеек):
/// This view controller has a `collectioView` to show the favorites.
class FavoriteCollectionViewController: UIViewController {
// MARK: Properties
let favoriteList: FavoriteList = {
let realm = try! Realm()
return realm.objects(FavoriteList.self).first!
}()
// Realm notification token to update collection view.
var notificationToken: NotificationToken?
// MARK: Collection View
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return favoriteList.videos.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: FavoritesCollectionViewCell.reuseIdentifier, for: indexPath) as! FavoritesCollectionViewCell
cell.video = favoriteList.videos[indexPath.item]
return cell
}
// I pass this lst forward to the PlayerVC
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if let playerVC = self.storyboard?.instantiateViewController(withIdentifier: "PlayerViewController") as? PlayerViewController {
// I pass the videos here.
playerVC.videos = favoriteList.videos
self.parent?.present(playerVC, animated: true, completion: nil)
}
}
// MARK: Realm Notifications
func updateUI(with changes: RealmCollectionChange<List<Video>>) {
// This is code to update the collection view.
}
}
Наконец, это код, позволяющий пользователю воспроизводить и переключаться между всеми Video
объектами:
/// This view controller uses `AVFoundation` to play the videos from `FavoriteCollectionViewController`.
class PlayerViewControllerr: UIViewController {
/// This `videos` is passed from `FavoriteCollectionViewController`
var videos = List<Video>()
// HELP: The app crashes here if I unfavorite a `Video`.
@IBAction func didToggleStarButton(_ sender: UIButton) {
let realm = try! Realm()
try! realm.write {
let videoToDelete = videos[currentIndexInVideosList] /// Get the video that is currently playing
realm.delete(videoToDelete)
}
}
}
В конечном итоге я хочу, чтобы объект Video
, который не добавлен в избранное, был полностью удален из Realm. Просто не уверен, как/когда это сделать в этом случае.
Какие-нибудь мысли?
Обновление 1
Вариант решения этой проблемы заключается в следующем:
- Сделайте неуправляемую копию копии
Video
и используйте ее для питания пользовательского интерфейса контроллера представления.
То, как я вижу, что это, возможно, работает, таково:
PlayerVC
получит дваList
: исходный, сохраненный в Realm, и копию этогоList
для питания пользовательского интерфейса. Назовем спискиfavoriteList
иcopyList
.Итак, внутри
didToggleStarButton
мы бы сделали что-то вроде этого:
Код:
/// This view controller uses `AVFoundation` to play the videos from `FavoriteCollectionViewController`.
class PlayerViewControllerr: UIViewController {
/// A button to allow the user to favorite and unfavorite a `Video`
@IBOutlet weak var starButton: UIButton!
/// This is passed from `FavoriteCollectionViewController`
var favoriteList: FavoriteList!
/// A copy of the `FavoriteList` videos to power the UI.
var copiedList: List<Video>!
var currentIndexOfVideoInCopiedList: Int!
override func viewDidLoad() {
super viewDidLoad()
// Make a copy of the favoriteList to power the UI.
var copiedVideos = [Video]()
for video in favoriteList.videos {
let unmanagedVideo = Video(value: video)
copiedVideos.append(unmanagedVideo)
}
self.copiedList.append(copiedVideos)
}
// HELP: The app crashes here if I unfavorite a `Video`.
@IBAction func didToggleStarButton(_ sender: UIButton) {
// Do the unfavoriting and favoriting here.
// An example of unfavoriting:
let realm = try! Realm()
try! realm.write {
let videoToDeleteFromFavoriteList = favoriteList.videos[currentIndexOfVideoInCopiedList] /// Get the video that is currently playing
realm.delete(videoToDeleteFromOriginalList)
}
// Update star button to a new image depending on if the `Video` is favorited or not.
starButton.isSelected = //... update based on if the `Video` in the `FavoriteList` or not.
}
}
Какие-нибудь мысли?