I'm playing around with some swift development for the first time in quite a few years and the language has changed some what with swiftui. I've been following a few different tutorials and I think I might be muddling up some ways of doing things.
I'm trying to initialize a FamilyActivityPicker
and respond to the onChange
event. Following one tutorial, the data I've bound to the FamilyActivityPicker
is from a model used as state in my view. However the onChange
event for the picker never fires (I have a print
statement that never fires). If I add some code to a didSet
in my model, this does fire (though seems to fire 6 times). Can someone see anything obvious I'm doing wrong here? I'm not sure if it's down to my understanding of swiftui and how everything binds together
struct ContentView: View {
@StateObject var model = FamilyControlModel.shared
@State var isPresented = false
var body: some View {
Button("Open picker") {
Task {
try await model.authorize()
isPresented = true
}
}
.familyActivityPicker(
isPresented: $isPresented,
selection: $model.selection
).onChange(of: model.selection) {
print("on change")
let data = try? encoder.encode(model.selection)
let strData = data!.base64EncodedString()
print(strData)
}
.padding()
}
}
Class FamilyControlModel {
static let shared = FamilyControlModel()
var selection = FamilyActivitySelection()
}
Here is my fully working test code using @StateObject private var model = FamilyControlModel()
and class FamilyControlModel: ObservableObject {...}
and an example func authorize()
.
On MacOS 15.3, using Xcode 16.2, target iOS-18, tested on real iOS device.
Note, you also need to add Family Controls (Development)
to your
Signing & Capabilities
of your target.
From the docs,
"Family Controls enables your app for parental controls, granting access to the Managed Settings and Device Activity frameworks in the Screen Time API."
import SwiftUI
import FamilyControls
struct ContentView: View {
@StateObject private var model = FamilyControlModel() // <-- here
@State private var isPresented = false
var body: some View {
Button("Open picker") {
Task {
try await model.authorize()
isPresented = true
}
}
.familyActivityPicker(isPresented: $isPresented, selection: $model.selection)
.onChange(of: model.selection) {
print("----> on change")
do {
let data = try JSONEncoder().encode(model.selection) // <-- here
let strData = data.base64EncodedString()
print(strData)
} catch {
print(error)
}
}
.padding()
}
}
class FamilyControlModel: ObservableObject { // <-- here
let center = AuthorizationCenter.shared
@Published var selection = FamilyActivitySelection()
func authorize() async throws { // <-- here
do {
try await center.requestAuthorization(for: FamilyControlsMember.individual)
} catch {
print(error)
}
}
}