无法访问视图中的变量值
Unable to access variable values in view
正在尝试从我的 iOS 应用发送电子邮件。它已经设置好了,可以开始了,但是我似乎无法将文本传递到发送电子邮件时显示的视图。当我传递要发送的文本时,它总是空的。
我知道这可能与无法访问它的视图有关,但我正在摸索要更改什么或添加什么才能使其正常工作。我试过 @binding
和 ObservableObject
,但我对 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)
}
}
}
}
}
正在尝试从我的 iOS 应用发送电子邮件。它已经设置好了,可以开始了,但是我似乎无法将文本传递到发送电子邮件时显示的视图。当我传递要发送的文本时,它总是空的。
我知道这可能与无法访问它的视图有关,但我正在摸索要更改什么或添加什么才能使其正常工作。我试过 @binding
和 ObservableObject
,但我对 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)
}
}
}
}
}