如何将plotehandler的结果用于Swift中的导航链接的目的地?

发布于 2025-01-26 19:04:39 字数 2276 浏览 4 评论 0原文

我有一个函数调用REST API,并通过完整的Handler返回结果。

按下导航链接时,我想调用此功能,但将结果当作为对象传递到目标时使用。无法完全弄清楚如何做到这一点,或者是否可能。这是我当前的代码:

剩下的函数

   func postProgramme(programmeName: String, programmeDays: Int, programmeDescription: String, completeionHandler: @escaping ProgrammeCompletionHandler) {
        struct PostRoutineData: Codable {
            let programmeName: String
            let programmeDays: Int
            let programmeDescription: String
        }
        
        let postProgrammeData = PostRoutineData(programmeName: programmeName, programmeDays: programmeDays, programmeDescription: programmeDescription)
        
        do {
            let jsonData = try JSONEncoder().encode(postProgrammeData)
            let jsonString = String(data: jsonData, encoding: .utf8)!
            let request = RESTRequest(path: "/workout/programme", body: jsonString.data(using: .utf8))
            Amplify.API.post(request: request) { result in
                switch result {
                case .success(let data):
                    do {
                        //let str = String(decoding: data, as: UTF8.self)
                        let programme = try self.decoder.decode(Programme.self, from: data)
                        completeionHandler(programme)
                    } catch {
                        print("[ERROR] Error within postProgrammes()", error)
                    }
                case .failure(let error):
                    print("[ERROR] Error within postProgrammes()", error)
                }
            }
        } catch {
            print("[ERROR] Error within postProgramme()", error)
        }
    }

导航链接,我试图解决问题:

NavigationLink(destination: ProgrammeDetailView(), isActive: $shouldTransit) {
    Text("Create Programme")
         .onTapGesture {
              self.createNewProgramme()
              self.shouldTransit = true
    }
}
func createNewProgramme() -> ProgrammeDetailView {
        sessionManager.postProgramme(programmeName: programmeName, programmeDays: programmeDays, programmeDescription: programmeDescription, completeionHandler: {(programme) -> ProgrammeDetailView in
            return ProgrammeDetailView(programme: programme)}
    }

I have a function which calls a REST API and returns the result via a completionHandler.

I want to call this function when pressing a NavigationLink but use the result as the object passed into the destination. Can't quite figure out how to do this, or if it's even possible. Here's my current code:

The REST function

   func postProgramme(programmeName: String, programmeDays: Int, programmeDescription: String, completeionHandler: @escaping ProgrammeCompletionHandler) {
        struct PostRoutineData: Codable {
            let programmeName: String
            let programmeDays: Int
            let programmeDescription: String
        }
        
        let postProgrammeData = PostRoutineData(programmeName: programmeName, programmeDays: programmeDays, programmeDescription: programmeDescription)
        
        do {
            let jsonData = try JSONEncoder().encode(postProgrammeData)
            let jsonString = String(data: jsonData, encoding: .utf8)!
            let request = RESTRequest(path: "/workout/programme", body: jsonString.data(using: .utf8))
            Amplify.API.post(request: request) { result in
                switch result {
                case .success(let data):
                    do {
                        //let str = String(decoding: data, as: UTF8.self)
                        let programme = try self.decoder.decode(Programme.self, from: data)
                        completeionHandler(programme)
                    } catch {
                        print("[ERROR] Error within postProgrammes()", error)
                    }
                case .failure(let error):
                    print("[ERROR] Error within postProgrammes()", error)
                }
            }
        } catch {
            print("[ERROR] Error within postProgramme()", error)
        }
    }

The NavigationLink, and my attempt to figure the problem out:

NavigationLink(destination: ProgrammeDetailView(), isActive: $shouldTransit) {
    Text("Create Programme")
         .onTapGesture {
              self.createNewProgramme()
              self.shouldTransit = true
    }
}
func createNewProgramme() -> ProgrammeDetailView {
        sessionManager.postProgramme(programmeName: programmeName, programmeDays: programmeDays, programmeDescription: programmeDescription, completeionHandler: {(programme) -> ProgrammeDetailView in
            return ProgrammeDetailView(programme: programme)}
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

我还不会笑 2025-02-02 19:04:39

假设这是一个iOS应用,如果您可以为iOS 15部署,则可以使用async函数并返回program ,而不是使用完成处理程序,可以使用最近的异步/等待环境。

  1. 将您的函数变成异步并返回program
   func postProgramme(programmeName: String, programmeDays: Int, programmeDescription: String) async -> Programme? {

        // ...
        
                case .success(let data):
                    do {
                        let programme = try self.decoder.decode(Programme.self, from: data)

                        // No completion handler: return a Programme
                        // completionHandler(programme)
                        return programme
                    } catch {
                        print("[ERROR] Error within postProgrammes()", error)

                        // Return nil everywhere else
                        return nil
                    }
  1. 在您的主视图中,使用@State type program的var?,它将被绑定到programMedEtailView中的另一个变量。

函数createNewprogramme()将更新状态变量。

@State private var programme: Programme? = nil

var body: some View {
    NavigationView {

        // Pass the binding to ProgrammeDetailView
        NavigationLink(destination: ProgrammeDetailView(programme: $programme, content: { programme in
                  // A customised view
                  Text(programme?.name ?? "")
            }), isActive: $shouldTransit) {
            Text("Create Programme")
                 .onTapGesture {
                     self.createNewProgramme()
                     self.shouldTransit = true
                 }
        }
    }

func createNewProgramme() {

    // Task will allow working with async functions
    Task {
        let programme = await sessionManager.postProgramme(programmeName: programmeName, programmeDays: programmeDays, programmeDescription: programmeDescription)

        // Back to main thread to update the UI
        DispatchQueue.main.async {
             self.programme = programme
        }
    }
}
  1. 请记住,在programMedEtailView中创建@binding变量。下面的示例可以将任何视图作为参数接收,但是由于REST API需要一些时间来响应,因此您需要处理program == nil
struct ProgrammeDetailView<V: View> : View {

    // The binding with the parent view
    @Binding var programme: Programme?

    // Your customised view that receives a Programme as a parameter
    let content: (Programme)->V

    var body: some View {
        if programme == nil {
             ProgressView()
        } else {
             content(programme!)
        }
    }
}

Assuming it's an iOS app, if you can deploy for iOS 15, you can use the recent async/ await environment, by using an async function and returning a Programme, instead of using a completion handler.

  1. Turn your function into async and return a Programme:
   func postProgramme(programmeName: String, programmeDays: Int, programmeDescription: String) async -> Programme? {

        // ...
        
                case .success(let data):
                    do {
                        let programme = try self.decoder.decode(Programme.self, from: data)

                        // No completion handler: return a Programme
                        // completionHandler(programme)
                        return programme
                    } catch {
                        print("[ERROR] Error within postProgrammes()", error)

                        // Return nil everywhere else
                        return nil
                    }
  1. In your main view, use a @State var of type Programme?, that will be binding to another variable in ProgrammeDetailView.

The function createNewProgramme() will update the state variable.

@State private var programme: Programme? = nil

var body: some View {
    NavigationView {

        // Pass the binding to ProgrammeDetailView
        NavigationLink(destination: ProgrammeDetailView(programme: $programme, content: { programme in
                  // A customised view
                  Text(programme?.name ?? "")
            }), isActive: $shouldTransit) {
            Text("Create Programme")
                 .onTapGesture {
                     self.createNewProgramme()
                     self.shouldTransit = true
                 }
        }
    }

func createNewProgramme() {

    // Task will allow working with async functions
    Task {
        let programme = await sessionManager.postProgramme(programmeName: programmeName, programmeDays: programmeDays, programmeDescription: programmeDescription)

        // Back to main thread to update the UI
        DispatchQueue.main.async {
             self.programme = programme
        }
    }
}
  1. Remember to create the @Binding variable in ProgrammeDetailView. The example below can receive any view as a parameter, but because the REST API will take some time to respond, you need to handle the case where programme == nil:
struct ProgrammeDetailView<V: View> : View {

    // The binding with the parent view
    @Binding var programme: Programme?

    // Your customised view that receives a Programme as a parameter
    let content: (Programme)->V

    var body: some View {
        if programme == nil {
             ProgressView()
        } else {
             content(programme!)
        }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文