如何有效地从SwiftUI中加载大量数据?
我一直在尝试从后端服务器加载一些数据,并且每页的页面大小为10个元素。
我正在使用联合收割机,问题是我也从服务器中恢复了视频和图像。
如何正确加载它们?我尝试添加重新加载功能,但这一切都大大减慢了该应用程序。这是我的代码:
class ProductDataService: ObservableObject {
@Published var count = 1
@Published var countPage = 0
@Published var allProducts: [ListedItem] = []
var productSubscription: AnyCancellable?
init() {
getProducts()
}
func getProducts() {
guard let url = URL(string: "myBackendURL-api/product/?page=\(count)") else{return}
productSubscription = NetworkingManager.download(url: url)
.decode(type: Product.self, decoder: JSONDecoder())
.sink(receiveCompletion: NetworkingManager.handleCompletion, receiveValue: { [weak self] returnedProducts in
self?.allProducts = returnedProducts.results
self?.countPage = returnedProducts.count
self?.nextPageView = returnedProducts.next
self?.productSubscription?.cancel()
})
}
}
我还将在下面添加用于网络管理器的代码,这并不是什么不合理的,这是
我的后端返回这样的JSON:
"count": 33,
"next": "http://backend/product/?page=2",
"previous": null,
"results": [
{
"id": 79,
"productName": "Mango",
"producDescription": "Banana",
"product_image1": "https:something.png",
},
现在,我尝试在每个调用中使用下一个参数以替换我的URL属性功能,但无法正确执行。
目前,我正在使用总产品的数量,然后在我使用的家庭视图模型中:
private let dataService = ProductDataService()
private var cancellables = Set<AnyCancellable>()
@Published var allProducts: [ListedItem] = []
@Published var tempArray: [ListedItem] = [] // listeditem is one product
init() {
addSubscribers()
}
func addSubscribers() {
dataService.$allProducts
.sink { [weak self] (returnedProducts) in
self?.allProducts += returnedProducts
}
.store(in: &cancellables)
}
然后我使用scrollview读取器来阅读是否到达屏幕的末端以加载更多项目。
我从我的视图中称之为此功能:
func loadMoreData() {
if allProducts.count < dataService.countPage {
if dataService.count < Int(dataService.countPage/10) {
print("our comparing value is \(Int(dataService.countPage/10))")
dataService.count += 1
dataService.getProducts()
}
else {
dataService.count -= 1
}
print("value of count is : \(dataService.count)")
}
else {
print("our product count is more ")
}
}
但是它并不能完全奏效我希望它的样子。
- 首先,它只是跳过第2页IDK为什么并直接加载第3页。现在,我有33个项目,直到第1页。 4但是由于我的支票,我可以在我的if conditon上写+1,但它会起作用,但
- 在加载时仍将屏幕悬挂2秒。
- 当时我该如何显示一些进度观点?
- 我在哪里,但是布尔值?
- 还有一种更好的方法来加载从GET API而不是此的项目吗?
现在,我将添加我的图像问题:
现在在我的产品图像视图中正在处理视频和图像:
var body: some View {
if vm.image != nil {
if let image = vm.image {
Image(uiImage: image)
}
else if vm.isloading {
ProgressView()
}
}
else if let stringUrl = Optional(vm.product.product_image1) {
ZStack {
customVideoPlayer(player: player)
.onAppear {
player.isMuted = isVideoMuted
if player.currentItem == nil {
let item = AVPlayerItem(url: URL(string: stringUrl) !)
player.replaceCurrentItem(with: item)
}
}
}
}
}
这里的问题是,在将其拍摄的任何图像加载到视频框架中之前。然后它作为图像加载,但是为什么呢?我一点都不明白。我希望它可以显示加载屏幕,但不要显示空白的视频屏幕。
I have been trying to load some data from a backend server and it comes in page size of 10 elements per page.
I am using combine and the issue is i am getting back videos and images from the server as well.
How do i load them properly? I have tried adding reloading functionality but it all just slows down the app massively. This is my code right now:
class ProductDataService: ObservableObject {
@Published var count = 1
@Published var countPage = 0
@Published var allProducts: [ListedItem] = []
var productSubscription: AnyCancellable?
init() {
getProducts()
}
func getProducts() {
guard let url = URL(string: "myBackendURL-api/product/?page=\(count)") else{return}
productSubscription = NetworkingManager.download(url: url)
.decode(type: Product.self, decoder: JSONDecoder())
.sink(receiveCompletion: NetworkingManager.handleCompletion, receiveValue: { [weak self] returnedProducts in
self?.allProducts = returnedProducts.results
self?.countPage = returnedProducts.count
self?.nextPageView = returnedProducts.next
self?.productSubscription?.cancel()
})
}
}
i would add the code for networking manager below as well, it's nothing unsual tho
my backend returns a json like this:
"count": 33,
"next": "http://backend/product/?page=2",
"previous": null,
"results": [
{
"id": 79,
"productName": "Mango",
"producDescription": "Banana",
"product_image1": "https:something.png",
},
For now I tried using the next parameter in every call to replace with the url property of my function but couldn't do it properly.
Right now am using the count of the total products and then inside my home view model i use:
private let dataService = ProductDataService()
private var cancellables = Set<AnyCancellable>()
@Published var allProducts: [ListedItem] = []
@Published var tempArray: [ListedItem] = [] // listeditem is one product
init() {
addSubscribers()
}
func addSubscribers() {
dataService.$allProducts
.sink { [weak self] (returnedProducts) in
self?.allProducts += returnedProducts
}
.store(in: &cancellables)
}
And then i use a scrollview reader to read if the person reached the end of the screen to load more items.
I call this function from my view:
func loadMoreData() {
if allProducts.count < dataService.countPage {
if dataService.count < Int(dataService.countPage/10) {
print("our comparing value is \(Int(dataService.countPage/10))")
dataService.count += 1
dataService.getProducts()
}
else {
dataService.count -= 1
}
print("value of count is : \(dataService.count)")
}
else {
print("our product count is more ")
}
}
But it doesn't work exactly how i want it to be.
- First it just skips page 2 idk why and directly loads page 3 items. and now i have 33 items that is till page no. 4 but it never goes there due to my checks tho i can write +1 in my if conditon and it would work but still
- It also hangs the screen for 2 secs when loading.
- How do i show some progress view at that moment?
- Where do i but the boolean for that?
- Also is there a better way to load items from a GET Api rather than this?
Now I would add my image problem:
Now inside my product image view am dealing with videos and images like this:
var body: some View {
if vm.image != nil {
if let image = vm.image {
Image(uiImage: image)
}
else if vm.isloading {
ProgressView()
}
}
else if let stringUrl = Optional(vm.product.product_image1) {
ZStack {
customVideoPlayer(player: player)
.onAppear {
player.isMuted = isVideoMuted
if player.currentItem == nil {
let item = AVPlayerItem(url: URL(string: stringUrl) !)
player.replaceCurrentItem(with: item)
}
}
}
}
}
The issue here is that before loading any image it takes in the frame of a video. And then it loads as an image but why so? I don't understand at all. I want it to either show a loading screen but not blank video screens.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论