无法访问视图中的变量值

Unable to access variable values in view

正在尝试从我的 iOS 应用发送电子邮件。它已经设置好了,可以开始了,但是我似乎无法将文本传递到发送电子邮件时显示的视图。当我传递要发送的文本时,它总是空的。

我知道这可能与无法访问它的视图有关,但我正在摸索要更改什么或添加什么才能使其正常工作。我试过 @bindingObservableObject,但我对 Swift 和 SwiftUI 还是个新手,所以我弄得一团糟。

这是代码,如何将列表项中的文本传递到显示的新视图?

struct ContentView: View {

    @FetchRequest(entity: Jot.entity(), sortDescriptors: [NSSortDescriptor(keyPath: \Jot.date, ascending: false)])
    var jots: FetchedResults<Jot>
    @State var result: Result<MFMailComposeResult, Error>? = nil
    @State var isShowingMailView = false

    // added this to try to force the text to go, since passing jot.text was giving me always
    // the first item in the list
    @State private var emailText: String = "" 

    var body: some View {
        NavigationView {
            List(jots) { jot in
                Text(jot.text!)
                .contextMenu {
                    if MFMailComposeViewController.canSendMail() {
                        Button(action: {
                            emailText = jot.text! // try to force the text to be passed
                            self.isShowingMailView.toggle()
                        }) {
                            Text("Email jot")
                            Image(systemName: "envelope")
                        }
                    }
                }
                .sheet(isPresented: $isShowingMailView) {
                    MailView(result: $result) { composer in
                        composer.setSubject("Jot!")
                        // in here, if I pass jot.text! then it's always the first item in the list
                        // if I pass emailText then it's always empty
                        composer.setMessageBody(emailText, isHTML: false)
                    }
                }
            }
            .listStyle(.plain)
        }
    }

}

以及发送电子邮件的支持代码:

import SwiftUI
import UIKit
import MessageUI


public struct MailView: UIViewControllerRepresentable {

    @Environment(\.presentationMode) var presentation
    @Binding var result: Result<MFMailComposeResult, Error>?
    public var configure: ((MFMailComposeViewController) -> Void)?

    public class Coordinator: NSObject, MFMailComposeViewControllerDelegate {

        @Binding var presentation: PresentationMode
        @Binding var result: Result<MFMailComposeResult, Error>?

        init(presentation: Binding<PresentationMode>,
             result: Binding<Result<MFMailComposeResult, Error>?>) {
            _presentation = presentation
            _result = result
        }

        public func mailComposeController(_ controller: MFMailComposeViewController,
                                   didFinishWith result: MFMailComposeResult,
                                   error: Error?) {
            defer {
                $presentation.wrappedValue.dismiss()
            }
            guard error == nil else {
                self.result = .failure(error!)
                return
            }
            self.result = .success(result)
        }
    }

    public func makeCoordinator() -> Coordinator {
        return Coordinator(presentation: presentation,
                           result: $result)
    }

    public func makeUIViewController(context: UIViewControllerRepresentableContext<MailView>) -> MFMailComposeViewController {
        let vc = MFMailComposeViewController()
        vc.mailComposeDelegate = context.coordinator
        configure?(vc)
        return vc
    }

    public func updateUIViewController(
        _ uiViewController: MFMailComposeViewController,
        context: UIViewControllerRepresentableContext<MailView>) {

    }
}

我们没有完整的 Minimal Reproducible Example (MRE),但我认为您想要的是使用 sheet(item:onDismiss:content:) 初始值设定项。它不是使用 Bool 来触发 sheet 显示,而是在您希望传入的任何数据的可选值变为 non-nil 时触发。这样,您可以将数据传递给 .sheet 并且只需要一个变量即可。这是未经测试的,但请尝试:

struct ContentView: View {

    @FetchRequest(entity: Jot.entity(), sortDescriptors: [NSSortDescriptor(keyPath: \Jot.date, ascending: false)])
    var jots: FetchedResults<Jot>
    @State var result: Result<MFMailComposeResult, Error>? = nil
    @State var isShowingMailView = false
    // this is your optional selection variable
    @State private var selectedJot: Jot?

    var body: some View {
        NavigationView {
            List(jots) { jot in
                Text(jot.text!)
                .contextMenu {
                    if MFMailComposeViewController.canSendMail() {
                        Button(action: {
                            // this gives selectedJot a value making it non-nil
                            selectedJot = jot
                        }) {
                            Text("Email jot")
                            Image(systemName: "envelope")
                        }
                    }
                }
            }
            .listStyle(.plain)
            // When selectedJot becomes non-nil, this initializer will trigger the sheet.
            .sheet(item: $selectedJot) { jot in
                MailView(result: $result) { composer in
                    composer.setSubject("Jot!")
                    composer.setMessageBody(jot.text, isHTML: false)
                }
            }
        }
    }
}