SwiftUI 异步数据获取
SwiftUI async Data fetch
我正在尝试学习 SwiftUI 并使用电影数据库创建电影搜索应用 API
我想在滚动到列表末尾时获取新数据。我在 List 中使用 ForEach 找到了一个可能的解决方案,并检查列表何时到达最后一项,然后执行 onAppear() 调用。
如何在第一个页面加载后从搜索中加载新页面?
你可以在这里找到这个项目,太大了 post
https://github.com/aspnet82/MovieSearch
SearchMovieManager -> 进行提取调用,我使用了 Dispatch.main.async
这里是应用程序应该做什么
- 从 API 获取数据并显示第一页 -> WORKING
- 当列表滚动到最后一项时,在下一页上发出另一个获取请求以加载更多数据 -> 这不起作用,它仅适用于请求的第二页。在第二次提取调用后,它始终显示相同的数据。
我认为问题出在 GCD 上,但我不知道如何排队使其自动运行
更新:我发现的解决方法:
List(searchMovieManager.allMovies) { movie in
Text(movie.title)
}
Text("load more").onTapGesture {
fetchNextPage(obs: self.searchMovieManager, page: self.searchMovieManager.pageTofetch)
}
我认为这个解决方案可能没问题,它会在我点击按钮后添加新页面,并且在控制数据下载方面也可以吗?
感谢您的帮助:)
尝试下一个,它使用锚点首选项和模仿异步操作的简单模型将一些记录添加到 ScrollView(或列表)
import SwiftUI
struct PositionData: Identifiable {
let id: Int
let center: Anchor<CGPoint>
}
struct Positions: PreferenceKey {
static var defaultValue: [PositionData] = []
static func reduce(value: inout [PositionData], nextValue: () -> [PositionData]) {
value.append(contentsOf: nextValue())
}
}
struct Data: Identifiable {
let id: Int
}
class Model: ObservableObject {
var _flag = false
var flag: Bool {
get {
_flag
}
set(newValue) {
if newValue == true {
_flag = newValue
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
self._flag = false
self.rows += 20
print("done")
}
}
}
}
@Published var rows = 20
}
struct ContentView: View {
@ObservedObject var model = Model()
var body: some View {
List {
ForEach(0 ..< model.rows, id:\.self) { i in
Text("row \(i)").font(.largeTitle).tag(i)
}
Rectangle().tag(model.rows).frame(height: 0).anchorPreference(key: Positions.self, value: .center) { (anchor) in
[PositionData(id: self.model.rows, center: anchor)]
}.id(model.rows)
}
.backgroundPreferenceValue(Positions.self) { (preferences) in
GeometryReader { proxy in
Rectangle().frame(width: 0, height: 0).position(self.getPosition(proxy: proxy, tag: self.model.rows, preferences: preferences))
}
}
}
func getPosition(proxy: GeometryProxy, tag: Int, preferences: [PositionData])->CGPoint {
let p = preferences.filter({ (p) -> Bool in
p.id == tag
})
if p.isEmpty { return .zero }
if proxy.size.height - proxy[p[0].center].y > 0 && model.flag == false {
self.model.flag.toggle()
print("fetch")
}
return .zero
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
这是它的样子...
我正在尝试学习 SwiftUI 并使用电影数据库创建电影搜索应用 API
我想在滚动到列表末尾时获取新数据。我在 List 中使用 ForEach 找到了一个可能的解决方案,并检查列表何时到达最后一项,然后执行 onAppear() 调用。
如何在第一个页面加载后从搜索中加载新页面?
你可以在这里找到这个项目,太大了 post https://github.com/aspnet82/MovieSearch
SearchMovieManager -> 进行提取调用,我使用了 Dispatch.main.async
这里是应用程序应该做什么
- 从 API 获取数据并显示第一页 -> WORKING
- 当列表滚动到最后一项时,在下一页上发出另一个获取请求以加载更多数据 -> 这不起作用,它仅适用于请求的第二页。在第二次提取调用后,它始终显示相同的数据。
我认为问题出在 GCD 上,但我不知道如何排队使其自动运行
更新:我发现的解决方法:
List(searchMovieManager.allMovies) { movie in
Text(movie.title)
}
Text("load more").onTapGesture {
fetchNextPage(obs: self.searchMovieManager, page: self.searchMovieManager.pageTofetch)
}
我认为这个解决方案可能没问题,它会在我点击按钮后添加新页面,并且在控制数据下载方面也可以吗?
感谢您的帮助:)
尝试下一个,它使用锚点首选项和模仿异步操作的简单模型将一些记录添加到 ScrollView(或列表)
import SwiftUI
struct PositionData: Identifiable {
let id: Int
let center: Anchor<CGPoint>
}
struct Positions: PreferenceKey {
static var defaultValue: [PositionData] = []
static func reduce(value: inout [PositionData], nextValue: () -> [PositionData]) {
value.append(contentsOf: nextValue())
}
}
struct Data: Identifiable {
let id: Int
}
class Model: ObservableObject {
var _flag = false
var flag: Bool {
get {
_flag
}
set(newValue) {
if newValue == true {
_flag = newValue
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
self._flag = false
self.rows += 20
print("done")
}
}
}
}
@Published var rows = 20
}
struct ContentView: View {
@ObservedObject var model = Model()
var body: some View {
List {
ForEach(0 ..< model.rows, id:\.self) { i in
Text("row \(i)").font(.largeTitle).tag(i)
}
Rectangle().tag(model.rows).frame(height: 0).anchorPreference(key: Positions.self, value: .center) { (anchor) in
[PositionData(id: self.model.rows, center: anchor)]
}.id(model.rows)
}
.backgroundPreferenceValue(Positions.self) { (preferences) in
GeometryReader { proxy in
Rectangle().frame(width: 0, height: 0).position(self.getPosition(proxy: proxy, tag: self.model.rows, preferences: preferences))
}
}
}
func getPosition(proxy: GeometryProxy, tag: Int, preferences: [PositionData])->CGPoint {
let p = preferences.filter({ (p) -> Bool in
p.id == tag
})
if p.isEmpty { return .zero }
if proxy.size.height - proxy[p[0].center].y > 0 && model.flag == false {
self.model.flag.toggle()
print("fetch")
}
return .zero
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
这是它的样子...