gpt4 book ai didi

swift - 在 SwiftUI 中从 BindableObject 调用 Debounce 方法

转载 作者:行者123 更新时间:2023-11-28 13:32:17 25 4
gpt4 key购买 nike

我是 Swift 的新手,对 SwiftUI 更是如此。我开始创建一个小的基本项目。我使用 Github API 来获取存储库列表。

所以我创建了一个“搜索栏”,因为 SwiftUI 没有 SearchBar 组件。每次更改我的文本字段内容时,我都想执行获取操作。

我不希望 fetch 方法被调用得太频繁。我决定去抖动它。我遇到了问题,我找不到/不理解示例。

我尝试实现去抖动解决方案,但它不起作用,我的应用程序崩溃了。

这是我的可绑定(bind)对象

import SwiftUI
import Combine

class ReposStore: BindableObject {

private var service: GithubService

let didChange = PassthroughSubject<Void, Never>()

@Published var searchText: String = ""

var repos: [Repository] = [] {
didSet {
didChange.send()
}
}

var error: String = "" {
didSet {
didChange.send()
}
}

var test: String = "" {
didSet {
didChange.send()
}
}

private var cancellable: AnyCancellable? = nil

init(service: GithubService) {
self.service = service


cancellable = AnyCancellable($searchText
.removeDuplicates()
.debounce(for: 2, scheduler: DispatchQueue.main)
.flatMap { self.fetch(matching: $0) }
.assign(to: \.test, on: self)
)
}

func fetch(matching query: String = "") {
print("### QUERY \(query)")
self.service.getUserRepositories(matching: query) { [weak self] result in
DispatchQueue.main.async {
print("### RESULT HERE \(result)")
switch result {
case .success(let repos): self?.repos = repos
case .failure(let error): self?.error = error.localizedDescription
}
}
}
}
}

这是我的观点

import SwiftUI

struct RepositoryList : View {
@EnvironmentObject var repoStore: ReposStore
@State private var userName: String = ""

var body: some View {

VStack {
NavigationView {
VStack(spacing: 0) {

HStack {
Image(systemName: "magnifyingglass").background(Color.blue).padding(.leading, 10.0)
TextField($repoStore.repoUser, placeholder: Text("Search")).background(Color.red)
.padding(.vertical, 4.0)
.padding(.trailing, 10.0)
}
.border(Color.secondary, width: 1, cornerRadius: 5)
.padding()

List {
ForEach(self.repoStore.repos) { repository in
NavigationLink(
destination: RepositoryDetail(repository: repository).environmentObject(self.repoStore)
) {
RepositoryRow(repository: repository)
}
}

}.navigationBarTitle(Text("Repositories"))
}
}
}
}

我尝试使用计时器并每 8 秒安排一次操作,但这种方法导致我的应用程序崩溃。

更多,我真的不知道用“@objc”注释声明一个函数是否是一个好习惯......

有人可以帮我实现一种正确的方法来对 BindableObject 中的方法进行去抖动吗?

提前谢谢你:)

最佳答案

我终于设法设置了去抖。

如果它可以帮助某人,这是我的实现:

import SwiftUI
import Combine

class Store : ObservableObject {
private var cancellable: AnyCancellable? = nil
@Published var searchText: String= ""
@Published var user: User? = nil

init() {
cancellable = AnyCancellable(
$searchText.removeDuplicates()
.debounce(for: 0.8, scheduler: DispatchQueue.main)
.sink { searchText in
self.searchUser()
})
}

func searchUser() {
var urlComponents = URLComponents(string: "https://api.github.com/users/\(searchText)")!

urlComponents.queryItems = [
URLQueryItem(name: "access_token", value: EnvironmentConfiguration.shared.github_token)
]

var request = URLRequest(url: urlComponents.url!)
request.addValue("application/json", forHTTPHeaderField: "Content-Type")

searchCancellable = URLSession.shared.send(request: request)
.decode(type: User.self, decoder: JSONDecoder())
.map { $0 }
.replaceError(with: nil)
.receive(on: DispatchQueue.main)
.assign(to: \.user, on: self)
}
}

extension URLSession {
func send(request: URLRequest) -> AnyPublisher<Data, URLSessionError> {
dataTaskPublisher(for: request)
.mapError { URLSessionError.urlError($0) }
.flatMap { data, response -> AnyPublisher<Data, URLSessionError> in
guard let response = response as? HTTPURLResponse else {
return .fail(.invalidResponse)
}

guard 200..<300 ~= response.statusCode else {
return .fail(.serverErrorMessage(statusCode: response.statusCode,
data: data))
}

return .just(data)
}.eraseToAnyPublisher()
}

enum URLSessionError: Error {
case invalidResponse
case serverErrorMessage(statusCode: Int, data: Data)
case urlError(URLError)
}
}

extension Publisher {

static func empty() -> AnyPublisher<Output, Failure> {
return Empty()
.eraseToAnyPublisher()
}

static func just(_ output: Output) -> AnyPublisher<Output, Failure> {
return Just(output)
.catch { _ in AnyPublisher<Output, Failure>.empty() }
.eraseToAnyPublisher()
}

static func fail(_ error: Failure) -> AnyPublisher<Output, Failure> {
return Fail(error: error)
.eraseToAnyPublisher()
}
}

struct User: Hashable, Identifiable, Decodable {
var id: Int
var login: String
var avatar_url: URL
var name: String?

enum CodingKeys: String, CodingKey {
case id, login, avatar_url, name
}
}

关于swift - 在 SwiftUI 中从 BindableObject 调用 Debounce 方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57168609/

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