随着更多远程数据被加载并添加到 SwiftUI 中的屏幕,导航会滞后
Navigation lags as more remote data is loaded and added to the screen in SwiftUI
我正在开发我的应用程序中允许用户发表评论的屏幕。此外,他们可以通过点击按钮查看以前的评论。最近的评论总是在评论列表的末尾,最旧的在顶部。
当点击 view more
按钮时,我从数据库中获取了 10 条以前的评论。我的获取代码如下所示:
func fetchMoreComments(for gameId: Int, isLoadingMoreComments: Binding<Bool>) {
guard self.canLoadMoreComments else { return }
APIManager
.CommentsAPI
.getMoreComments(for: gameId, lastCommentId: self.lastCommentId!)
.sink(receiveCompletion: { completion in
print("load more comments completion:", completion)
},
receiveValue: {[weak self] response in
if response.statusCode == 200 {
// self?.comments.reserveCapacity((self?.comments.count)! + response.items.count)
let comments = response.items
if let lastCommentId = comments.map({ [=10=].id! }).min() {
self?.lastCommentId = lastCommentId
}
self?.comments.insert(contentsOf: comments.sorted(), at: 0)
isLoadingMoreComments.wrappedValue = false
self?.canLoadMoreComments = response.items.count >= 1
}
})
.store(in: &subscriptions)
}
另外,我应该提一下,当第一次加载屏幕时,我使用另一个函数来拉取 3 个最新评论,以便在用户第一次加载该特定屏幕时显示在屏幕上。
问题
随着加载更多评论,导航速度变慢。我的意思是,如果我点击后退按钮返回到上一个屏幕,在我实际返回到该屏幕之前会有大约 4-5 秒的延迟。反过来也有同样的问题。加载带有评论的屏幕大约需要 4-5 秒。
我试过的
1)
我花了好几天时间来解决内存泄漏问题并清理我的代码,试图找出问题所在。我发现,如果我注释掉从我的视图模型中读取数组的 forloop(我在上面粘贴的一个函数存在),那么滞后的导航问题就会消失。我在下面粘贴了 forloop。我已经尝试使用我的评论对象中的 .id 和 .self 来提高性能,但没有任何区别。
ForEach(self.liveGameViewModel.comments, id: \.self) { comment in
LiveGameCommentCell(comment: comment)
}
.id(UUID())
2)
我进一步将范围缩小到 LiveGameCommentCell
内的 NavigationLink
。该导航 link 是指向评论者个人资料屏幕的 link。我注意到,一旦我注释掉这个导航 link,导航延迟就得到了部分解决。我最多可以加载 100 条评论(一次 10 条),然后离开屏幕(仍然会有几秒钟的延迟),但是,一旦导航回带有评论的屏幕,延迟就会完全消失。
3)
因为我不能再使用导航,所以我决定使用 sheet 来显示用户的个人资料屏幕。这是我注意到另一个问题的地方,或者可能只是我一直遇到的同一个问题。我会在屏幕上加载评论,然后点击评论者的图片,然后 sheet 会毫无延迟地显示出来。然后我会关闭 sheet 并加载更多评论并点击另一个评论者的个人资料图片。我注意到,我加载的评论越多,sheet 出现的时间就越长。
4)
接下来,我决定调整最初从数据库中提取的评论数量。我将限制提高到 100。在没有加载更多评论的情况下,我再次点击了评论者的个人资料图片,但又出现了延迟。问题肯定和评论有关。
5)
我尝试在初始加载评论时将 Swift 数组的 reserveCapacity(_:)
设置为 10,然后每次加载更多评论时,我将容量设置为数组中的当前评论数 + 收到的评论数在响应中。这并没有太大的区别。
我似乎无法找到这个问题,但我知道它与屏幕上的评论数量直接相关。屏幕上的评论越多,sheet 显示所需的时间就越长,或者导航回上一屏幕所需的时间也就越长。
我重构了我的代码并修复了我遇到的内存泄漏问题。大多数与每个屏幕相关的视图模型仅在该屏幕的生命周期内有效。例如,当屏幕关闭时,视图模型被取消初始化。
Inside instruments,LiveGameCommentCell
的计数和总持续时间最高。当我加载更多评论时,计数会增加。
是什么导致了这个问题?我在其他屏幕上使用相同类型的功能,但没有遇到此问题。唯一的区别是,其他屏幕完全是包含 foreach 循环的列表,而这个有问题的屏幕由 2 个图像(主持人、挑战者)、一些游戏信息(例如简短的描述性句子、截止日期、评论)组成计数、类别,然后在所有这些下面,一个评论列表部分和 post 个新评论的文本视图。
我什至改变了一些事情,这样评论的 API 响应将提供我评论所需的所有信息,而不是使用外键并从应用程序发出多个请求。所需的一切都在 getMostRecentComments
和 getMoreComments
请求中提供。
有一些内存泄漏我没有解决,因为它们很可能与其他东西有关,因为无论访问显示评论的屏幕如何,它们都会显示。
此外,我注意到当我第一次到达显示评论的屏幕并点击评论者的个人资料图片时,没有任何错误。如果我点击下一组加载的 10 条评论,没有错误,但随着滞后增加,我注意到当我点击评论者的图像时开始显示错误。错误是:
[Common] _BSMachError: port 1c433; (os/kern) invalid capability (0x14) "Unable to insert COPY_SEND"
如果能提供一些线索可以帮助我解决此问题,我将不胜感激。目前,我还不清楚是什么导致了这个问题。
提前致谢
我在 ScrollView 中有一个 ForEach 循环,而不是在 List 中。用列表替换 ScrollView,并将我的 NavigationLinks 包装在 LazyView 中解决了这个问题。
我正在开发我的应用程序中允许用户发表评论的屏幕。此外,他们可以通过点击按钮查看以前的评论。最近的评论总是在评论列表的末尾,最旧的在顶部。
当点击 view more
按钮时,我从数据库中获取了 10 条以前的评论。我的获取代码如下所示:
func fetchMoreComments(for gameId: Int, isLoadingMoreComments: Binding<Bool>) {
guard self.canLoadMoreComments else { return }
APIManager
.CommentsAPI
.getMoreComments(for: gameId, lastCommentId: self.lastCommentId!)
.sink(receiveCompletion: { completion in
print("load more comments completion:", completion)
},
receiveValue: {[weak self] response in
if response.statusCode == 200 {
// self?.comments.reserveCapacity((self?.comments.count)! + response.items.count)
let comments = response.items
if let lastCommentId = comments.map({ [=10=].id! }).min() {
self?.lastCommentId = lastCommentId
}
self?.comments.insert(contentsOf: comments.sorted(), at: 0)
isLoadingMoreComments.wrappedValue = false
self?.canLoadMoreComments = response.items.count >= 1
}
})
.store(in: &subscriptions)
}
另外,我应该提一下,当第一次加载屏幕时,我使用另一个函数来拉取 3 个最新评论,以便在用户第一次加载该特定屏幕时显示在屏幕上。
问题
随着加载更多评论,导航速度变慢。我的意思是,如果我点击后退按钮返回到上一个屏幕,在我实际返回到该屏幕之前会有大约 4-5 秒的延迟。反过来也有同样的问题。加载带有评论的屏幕大约需要 4-5 秒。
我试过的
1) 我花了好几天时间来解决内存泄漏问题并清理我的代码,试图找出问题所在。我发现,如果我注释掉从我的视图模型中读取数组的 forloop(我在上面粘贴的一个函数存在),那么滞后的导航问题就会消失。我在下面粘贴了 forloop。我已经尝试使用我的评论对象中的 .id 和 .self 来提高性能,但没有任何区别。
ForEach(self.liveGameViewModel.comments, id: \.self) { comment in
LiveGameCommentCell(comment: comment)
}
.id(UUID())
2)
我进一步将范围缩小到 LiveGameCommentCell
内的 NavigationLink
。该导航 link 是指向评论者个人资料屏幕的 link。我注意到,一旦我注释掉这个导航 link,导航延迟就得到了部分解决。我最多可以加载 100 条评论(一次 10 条),然后离开屏幕(仍然会有几秒钟的延迟),但是,一旦导航回带有评论的屏幕,延迟就会完全消失。
3) 因为我不能再使用导航,所以我决定使用 sheet 来显示用户的个人资料屏幕。这是我注意到另一个问题的地方,或者可能只是我一直遇到的同一个问题。我会在屏幕上加载评论,然后点击评论者的图片,然后 sheet 会毫无延迟地显示出来。然后我会关闭 sheet 并加载更多评论并点击另一个评论者的个人资料图片。我注意到,我加载的评论越多,sheet 出现的时间就越长。
4) 接下来,我决定调整最初从数据库中提取的评论数量。我将限制提高到 100。在没有加载更多评论的情况下,我再次点击了评论者的个人资料图片,但又出现了延迟。问题肯定和评论有关。
5)
我尝试在初始加载评论时将 Swift 数组的 reserveCapacity(_:)
设置为 10,然后每次加载更多评论时,我将容量设置为数组中的当前评论数 + 收到的评论数在响应中。这并没有太大的区别。
我似乎无法找到这个问题,但我知道它与屏幕上的评论数量直接相关。屏幕上的评论越多,sheet 显示所需的时间就越长,或者导航回上一屏幕所需的时间也就越长。
我重构了我的代码并修复了我遇到的内存泄漏问题。大多数与每个屏幕相关的视图模型仅在该屏幕的生命周期内有效。例如,当屏幕关闭时,视图模型被取消初始化。
Inside instruments,LiveGameCommentCell
的计数和总持续时间最高。当我加载更多评论时,计数会增加。
是什么导致了这个问题?我在其他屏幕上使用相同类型的功能,但没有遇到此问题。唯一的区别是,其他屏幕完全是包含 foreach 循环的列表,而这个有问题的屏幕由 2 个图像(主持人、挑战者)、一些游戏信息(例如简短的描述性句子、截止日期、评论)组成计数、类别,然后在所有这些下面,一个评论列表部分和 post 个新评论的文本视图。
我什至改变了一些事情,这样评论的 API 响应将提供我评论所需的所有信息,而不是使用外键并从应用程序发出多个请求。所需的一切都在 getMostRecentComments
和 getMoreComments
请求中提供。
有一些内存泄漏我没有解决,因为它们很可能与其他东西有关,因为无论访问显示评论的屏幕如何,它们都会显示。
此外,我注意到当我第一次到达显示评论的屏幕并点击评论者的个人资料图片时,没有任何错误。如果我点击下一组加载的 10 条评论,没有错误,但随着滞后增加,我注意到当我点击评论者的图像时开始显示错误。错误是:
[Common] _BSMachError: port 1c433; (os/kern) invalid capability (0x14) "Unable to insert COPY_SEND"
如果能提供一些线索可以帮助我解决此问题,我将不胜感激。目前,我还不清楚是什么导致了这个问题。
提前致谢
我在 ScrollView 中有一个 ForEach 循环,而不是在 List 中。用列表替换 ScrollView,并将我的 NavigationLinks 包装在 LazyView 中解决了这个问题。