我已经缩小了我正在开发的一个应用程序的规模,以学习如何编程App Intents并在我的应用程序中使用Siri。我将在下面以最简单的形式发布我的代码的缩小版本。这是一个简单的应用程序,它只将总数保存在一个名为counter
的@State var
中。该应用程序显示当前总数以及2个按钮,其中一个按钮被标记为";减去";另一个标记为";添加";。
当有人点击减号按钮时,如果counter
大于0,则从counter
中减去1。当有人点击加号按钮时,只要不大于10000,就会在counter
中添加1。
这些按钮实际上调用了名为decrementCounter
和incrementCounter
的函数,它们进行数学运算并更新状态变量counter
的值。
该应用程序可以正常工作。减号和加号按钮可以工作,并且视图会随着按钮的按下而更新,以反映counter
的当前值。
问题是当我尝试使用AppIntent来添加或减去counter
时。在这个例子中,我只放入了两个AppIntent,一个添加到counter
,另一个让Siri告诉你counter
的当前值是多少
名为SiriAddOne
的应用程序意图调用的函数与按下按钮时使用的函数相同,但counter
不会递增。
此外,应用程序意图SiriHowMany
将始终告诉您计数器为零。
这就像App Intents无法访问视图中使用的counter
变量。
我确实知道这些函数被调用了,因为在我提取这些函数的主程序中,incrementCounter
和decrementCounter
函数也做其他事情。当我使用AppIntent调用函数时,这些其他事情都会起作用,但counter
变量保持不变。
希望有人能告诉我我在这里做错了什么,或者我需要如何正确地做这件事。非常感谢。
import SwiftUI
import AppIntents
struct ContentView: View {
// This variable counter is the only thing that changes
// and should be what forces the view to update
@State var counter = 0
var body: some View {
VStack {
Spacer()
Text("Total")
// Displays the current value of the counter
Text(String(counter))
Spacer()
// When button is pressed call decrementCounter function
Button(action: {
decrementCounter()
}, label: {
Text("Minus")
})
Spacer()
// When button is pressed call incrementCounter function
Button(action: {
incrementCounter()
}, label: {
Text("Add")
})
Spacer()
}
.padding()
}
// subtract 1 from the counter
// when this happens the view should update to
// to reflect the new value.
func decrementCounter() {
if counter > 0 {
counter -= 1
}
return
}
// Add 1 to the counter
// when this happens the view should update to
// to reflect the new value.
func incrementCounter() {
if counter <= 9999 {
counter += 1
}
return
}
// Set up App Intent, perform action when matched
// and have siri state it has been done.
@available(iOS 16, *)
struct SiriAddOne: AppIntent {
static var title: LocalizedStringResource = "Add 1"
static var description = IntentDescription("Adds 1 to the counter")
@MainActor
func perform() async throws -> some IntentResult {
ContentView().incrementCounter()
return .result(dialog: "Okay, added 1 to counter.")
}
}
// Set up App Intent, perform action when matched
// and have siri state the current value of the counter.
@available(iOS 16, *)
struct SiriHowMany: AppIntent {
static var title: LocalizedStringResource = "How Many"
static var description = IntentDescription("How Many?")
func perform() async throws -> some IntentResult {
return .result(dialog: "You have (ContentView().counter).")
}
}
// Defines the two shortcut phrases to be used to call the two AppIntents
@available(iOS 16, *)
struct SiriAppShortcuts: AppShortcutsProvider {
static var appShortcuts: [AppShortcut] {
AppShortcut(
intent: SiriAddOne(),
phrases: ["Add one to (.applicationName)"]
)
AppShortcut(
intent: SiriHowMany(),
phrases: ["How many (.applicationName)"]
)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
ContentView().incrementCounter()
执行ContentView()
时,您正在创建一个新的ContentView
对象,该对象与应用程序创建的主ContentView
有一个单独的计数器。
我建议将计数器移动到符合ObservableObject
协议的类。只生成它的一个实例,并将该实例存储在全局变量中,然后向值为该对象的ContentView
添加@ObservedObject
属性。例如:
class CounterData: ObservableObject {
var counter = 0
}
let counterData = CounterData()
struct ContentView: View {
@ObservedObject let myCounterData = counterData
func incrementCounter() {
if myCounterData.counter <= 9999 {
myCounterData.counter += 1
}
}
@available(iOS 16, *)
struct SiriHowMany: AppIntent {
static var title: LocalizedStringResource = "How Many"
static var description = IntentDescription("How Many?")
func perform() async throws -> some IntentResult {
return .result(dialog: "You have (counterData.counter).")
}
}
/* other code skipped for brevity */
}