gpt4 book ai didi

ios - Realm - 删除后无法使用对象

转载 作者:搜寻专家 更新时间:2023-10-31 19:37:04 25 4
gpt4 key购买 nike

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

问题是:当用户在 PlayerVC 中时,他们可以取消对 Video 的收藏。如果他们这样做,我会从 Realm 中删除 Video 对象。但是,这会导致:

由于未捕获的异常“RLMException”而终止应用程序,原因:“对象已被删除或无效。”

基本上,如果用户正在 PlayerVC 中观看视频并且取消了对视频的收藏,我希望他们暂时仍能观看该视频。 但是当他们离开 PlayerVC 时,FavoritesVC 中的 Collection View 应该更新并且不再显示 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...
}

这是我在 Collection View 中显示 Video 对象的代码(注意:我使用 RealmCollectionChange 更新 Collection View 以删除和插入单元格):

/// 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 副本的非托管副本,并使用该副本为 View Controller 的 UI 提供动力。

我认为这可能有效的方式是这样的:

  • PlayerVC 将收到两个 List,保存在 Realm 中的原始列表和此 List 的副本以驱动 UI .我们将列表称为 favoriteListcopyList

  • 所以在 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.
}
}

有什么想法吗?

最佳答案

由于许多架构原因,这绝对是棘手的。

您是对的,您可以简单地从 FavoriteList.videos 中删除对象,然后在关闭 Controller 时从 Realm 中正确删除它,但是您没错,如果用户单击主页按钮,或者应用程序在此之前崩溃,您最终会得到一个 headless 视频对象。您需要能够确保可以跟踪它。

您可以考虑几件事。

  • isDeleted 属性添加到 Video 类。当用户取消收藏视频时,从 FavoriteList.videos 中删除 Video 对象,将该属性设置为 true,但将其保留在 Realm 中。稍后(当应用程序退出或 View Controller 被关闭时),您可以对 isDeletedtrue 的所有对象进行一般查询,然后删除它们(这解决了 headless 问题)。
  • 由于您的体系结构需要一个依赖于可以从其下删除的模型的 View Controller ,具体取决于您从该 Video 对象中使用了多少信息,制作一个Video 副本的非托管副本,并使用该副本为 View Controller 的 UI 提供支持。您可以通过执行 let unmanagedVideo = Video(value: video) 创建现有 Realm 对象的新副本。

关于ios - Realm - 删除后无法使用对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43081852/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com