As can be seen here, all categories are expanded but nothing under them:
Not sure if related, but when I tried to upload my app for internal TestFlight testing I got following error:
The code looks like this:
@ObservedObject var model : MyModel
@State var isPresented = false
var body: some View {
Button("select apps to discourage"){
isPresented = true
}.onAppear {
Task {
do {
try await AuthorizationCenter.shared.requestAuthorization(for: .child)
} catch {
}
}
}.familyActivityPicker(isPresented: $isPresented, selection: $model.selectionToDiscourage)
}
}
Now I am wondering, is there one more thing that I need to do before familyActivityPicker would work?
Here is what I have done: I subscribed to $99 Apple developer plan, Then I was finally able to see and add Family Controls capability under my Xcode project, Then I created Apple Family and logged in iphone (and simulator) as child. Then several days ago I submitted this form - https://developer.apple.com/contact/request/family-controls-distribution (not sure if this was mandatory for internal testing, but I have not received any communication from Apple - even confirmation for my request).
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
My swift app has several places where it updates data stored with SwiftData. In each place I have to remember to add function doSomethingWithTheUpdatedData().
I would like my app to be reactive and call doSomethingWithTheUpdatedData() from a single place opposed to be scattered throughout my app. How to accomplish this?
I am creating a macOS app with the following requirements:
Automatic Startup: After initial installation, the app should automatically start, even after the OS restarts.
Notarized Installation: The installation package (.pkg) should be notarized to avoid user have to make security exception.
In my current setup I’ve created a script, ci_scripts/ci_post_xcodebuild.sh, which uploads the package file $CI_APP_STORE_SIGNED_APP_PATH/<appName>.pkg to GitHub via Xcode Cloud. While I can successfully download the app, I’m encountering two main issues:
Notarization (I assume): I’m unsure how to get Xcode Cloud to notarize the .pkg file. Currently, upon opening the .pkg file for the first time, users have to go to System Settings > Privacy & Security to allow an exception for the package, after which installation proceeds successfully on second try. I’d like to automate the notarization process to eliminate this extra step.
Adding Additional Files to PKG installer: My current .pkg file only includes the app binary. I need to configure Xcode Cloud to include a postinstall script and a launchd daemon configuration file within the package. This would ensure that necessary files are set up on installation and that the app is properly registered as a launch daemon.
I have a SwiftData model where I need to customize behavior based on the value of a property (connectorType). Here’s a simplified version of my model:
@Model
public final class ConnectorModel {
public var connectorType: String
...
func doSomethingDifferentForEveryConnectorType() {
...
}
}
I’d like to implement doSomethingDifferentForEveryConnectorType in a way that allows the behavior to vary depending on connectorType, and I want to follow best practices for scalability and maintainability. I’ve come up with three potential solutions, each with pros and cons, and I’d love to hear your thoughts on which one makes the most sense or if there’s a better approach:
**Option 1: Use switch Statements
**
func doSomethingDifferentForEveryConnectorType() {
switch connectorType {
case "HTTP":
// HTTP-specific logic
case "WebSocket":
// WebSocket-specific logic
default:
// Fallback logic
}
}
Pros: Simple to implement and keeps the SwiftData model observable by SwiftUI without any additional wrapping.
Cons: If more behaviors or methods are added, the code could become messy and harder to maintain.
**Option 2: Use a Wrapper with Inheritance around swiftdata model
**
@Observable
class ParentConnector {
var connectorModel: ConnectorModel
init(connectorModel: ConnectorModel) {
self.connectorModel = connectorModel
}
func doSomethingDifferentForEveryConnectorType() {
fatalError("Not implemented")
}
}
@Observable
class HTTPConnector: ParentConnector {
override func doSomethingDifferentForEveryConnectorType() {
// HTTP-specific logic
}
}
Pros: Logic for each connector type is cleanly organized in subclasses, making it easy to extend and maintain.
Cons: Requires introducing additional observable classes, which could add unnecessary complexity.
**Option 3: Use a @Transient class that customizes behavior
**
protocol ConnectorProtocol {
func doSomethingDifferentForEveryConnectorType(connectorModel: ConnectorModel)
}
class HTTPConnectorImplementation: ConnectorProtocol {
func doSomethingDifferentForEveryConnectorType(connectorModel: ConnectorModel) {
// HTTP-specific logic
}
}
Then add this to the model:
@Model
public final class ConnectorModel {
public var connectorType: String
@Transient
public var connectorImplementation: ConnectorProtocol?
// Or alternatively from swiftui I could call myModel.connectorImplementation.doSomethingDifferentForEveryConnectorType() to avoid this wrapper
func doSomethingDifferentForEveryConnectorType() {
connectorImplementation?.doSomethingDifferentForEveryConnectorType(connectorModel: self)
}
}
Pros: Decouples model logic from connector-specific behavior. Avoids creating additional observable classes and allows for easy extension.
Cons: Requires explicitly passing the model to the protocol implementation, and setup for determining the correct implementation needs to be handled elsewhere.
My Questions
Which approach aligns best with SwiftData and SwiftUI best practices, especially for scalable and maintainable apps?
Are there better alternatives that I haven’t considered?
If Option 3 (protocol with dependency injection) is preferred, what’s the best way to a)manage the transient property 2) set the correct implementation and 3) pass reference to swiftdata model?
Thanks in advance for your advice!
I changed my application's name and bundle identifier from xcode.
I am able to publish this app to testflight (internal) successfully. However, when users of my app report crash and I try to open them from App Store Connect crash section I see following error in Xcode:
Xcode failed to locate iOS App with App Store Identifier "XXXXXXX418".
If I open in Xcode > Window > Organizer > Crashes I see following error:
Upload "YourAPP" to App Store Connect to begin receiving crash logs.
It seems that AppStore identifier at one point changed and xcode and appstore connect are out of sync. What solution is there?
I’m building a cross-platform app targeting macOS, iPad, and iPhone. My app currently uses both 2-level and 3-level navigation workflows:
3-level navigation:
First level: Categories
Second level: List of items in the selected category
Third level: Detail view for a specific item
2-level navigation:
First level: Category
Second level: A singleton detail view (for example, StatusView). It does not have concept of List.
After watching a couple of WWDC videos about multi-platform navigation, I decided to go with NavigationSplitView.
However, on macOS, a 3-column NavigationSplitView felt a bit overwhelming to my eyes when the third column was empty—especially for the occasional 2-level navigation case. So I removed the third column and instead embedded a NavigationStack in the second column. According to the official Apple documentation, this is supported:
You can also embed a NavigationStack in a column.
The code with NavigationStack in NavigationSplitView works fine on macOS.
But on iPhone, for the same code I’m seeing unexpected behavior:
The first time I tap on the “Actions” category, it briefly shows the “Select an item” view, and then automatically pops back to the all-categories view.
If I tap the same "Actions" category again, it shows the list of actions correctly, and everything works fine until I terminate and relaunch the app.
Here is a minimal reproducible example:
import SwiftUI
struct StatusView: View {
var body: some View {
NavigationStack {
List {
Text("Heartbeat: OK")
Text("Connected to backend: OK")
}
}
}
}
struct ActionListView: View {
var body: some View {
NavigationStack {
List {
NavigationLink(value: "Action 1 value") {
Text("Action 1 label")
}
NavigationLink(value: "Action 2 value") {
Text("Action 2 label")
}
}
}
.navigationDestination(for: String.self) { action in
Text(action)
}
}
}
struct ContentView: View {
var body: some View {
NavigationSplitView {
List {
NavigationLink(value: "Actions") {
Text("Actions (3 level)")
}
NavigationLink(value: "Modes") {
Text("Modes (3 level)")
}
NavigationLink(value: "State") {
Text("Status (2 level)")
}
}
.navigationDestination(for: String.self) { category in
switch category {
case "Actions":
ActionListView()
case "Modes":
Text("Modes View")
case "State":
StatusView()
default:
Text("Unknown Category")
}
}
} detail: {
Text("Select an item")
}
}
}
Questions and considerations:
How can I prevent this unexpected automatic pop back to the root view on iPhone the first time I select a category?
Future-proofing for more than 3 level navigation: In the future, I may allow users to navigate beyond three levels (e.g., an item in one category can reference another item in a different category). Is it correct to assume that to support this with back navigation, I’d need to keep using NavigationStack inside NavigationSplitView?
Is embedding NavigationStack in a 2 column NavigationSplitView the only practical approach to handle mixed 2 and 3 navigation depth if I don't want the third column to be ever empty?
On macOS, NavigationStack alone doesn’t feel appropriate for sidebar-based navigation. Does it mean everyone on macOS pretty much always use NavigationSplitView?
Any advice or examples would be appreciated. Thanks!
Topic:
UI Frameworks
SubTopic:
SwiftUI
I am trying to install my LaunchAgent (which is bundled as .app in .pkg file) with:
sudo installer -pkg ./XXX.pkg -target /
And I see following error:
2025-07-29 19:06:29-05 MacBook-Pro installd[764]: PackageKit: Skipping component "com.XXX.Agent" (1.0.0-1.0.0-*) because the version 1.0.0-21.0.0-* is already installed at /Users/user/Downloads/Xcode Cloud Artifacts/XXX-C0E61B13-3F49-42DF-81B3-1037BC34D11B/b1ac6a32-3236-417e-bd62-88de90fa700d/789d0aa2-5531-403c-bcab-e3de8d6b34ee/myAgent.app.
After installer command returns, I don't see any files from my .app bundle extracted on filesystem.
If I understand the error message properly, then installer checks if ANYWHERE on filesystem there already exists this app bundle. And if it exists, then do not extract another copy of bundle.
But why? And do I need to specify version in xcodebuild command?
Topic:
App Store Distribution & Marketing
SubTopic:
General
At 11:37 in this video - https://developer.apple.com/videos/play/wwdc2021/10123/ - Nolan instantiates MyModel() in swiftui view file. And then at 12:02 he just uses MyModel from extension.
I have the exact same code and when I try to build my project, it fails with error that MyModel() could not be found.
I shared my MyModel.swift file between extension target and main app. Now it builds. However, it seems there are two separate instances of MyModel.
What is proper way for DeviceActivityMonitor extension to pass data to main app? I simply want to increment counter from extension every minute and let the main app to know that.
Or even better, - is there a way to use SwiftData from Device Activity Monitor extension?
In Xcode I have created UI-less application. I tried to add following code:
import CloudKit
let container = CKContainer.default()
And it is failing with:
In order to use CloudKit, your process must have a com.apple.developer.icloud-services entitlement. The value of this entitlement must be an array that includes the string "CloudKit" or "CloudKit-Anonymous".
If I go to project and select my Command Line Tool target I don't see CloudKit capability that I usually see in UI based applications.
So, is it impossible to use CloudKit from Command Line tools?
I am able to fetch CloudKit records from my MacOS command line tool/daemon.
However, I would like CloudKit to notify my daemon whenever CKRecords were altered so I would not have to poll periodically.
In CloudKit console I see that my app successfully created CloudKit subscription, but the part that confuses me is where in my app do I define callback function that gets called whenever CloudKit attempted to notify my app of CloudKit changes?
My first question - do I need to define callback in my implementation of UNUserNotificationCenterDelegate? NSApplicationDelegate? Something else?
My second question, would CKSyncEngine work from command line application?
Topic:
App & System Services
SubTopic:
iCloud & Data
Tags:
CloudKit
Command Line Tools
Service Management
I'm currently managing two independent ModelContext instances in my app—one dedicated to CKSyncEngine and another for the Main/UI thread.
While this setup works to some extent, I'm encountering a couple of issues:
UI Updates: When SwiftData is updated via CKSyncEngine, the UI doesn't automatically refresh. To address this, I've had to implement .refreshable() and write imperative Swift code to (re)fetch data. This approach feels counterintuitive since it prevents me from fully leveraging SwiftUI's declarative nature, such as using @Query and user must explicitly trigger refresh.
Deletion Logic: If users delete data via the UI, I have to manage a different delete code path. Specifically, I need to ensure that the object is removed from the UI's ModelContext without triggering a deletion in CKSyncEngine's ModelContext. This dual-path deletion logic feels unnecessarily complex.
Also, I intend to later re-use CKSyncEngine part for Command Line tool app that will not have UI at all.
What is the correct way to manage SwiftData in a background process like CKSyncEngine while maintaining a seamless and declarative approach in SwiftUI?
I took CKShare with Zone example - https://github.com/apple/sample-cloudkit-sharing
Modified it a little bit so code looks like this:
struct ResourceView: View {
@State private var showingShare: Bool = false
@State private var shareView: CloudSharingView?
...
var body: some View {
HStack {
Button(action: {
Task {
let (share,container) = try! await shareConfiguration()
shareView = CloudSharingView(container: container, share: share)
showingShare = true
}
}) {
Label("Share", systemImage: "circle")
}
...
.sheet(isPresented: $showingShare) {
if let shareView = shareView {
shareView
} else {
Text("No sheet to show")
}
}
And the first time I click on Share button I am getting "No sheet to show" despite showingShare boolean being set after shareView variable. Presumably because shareView is nil.
The second time I click on Share button it shows the sharing view.
Topic:
UI Frameworks
SubTopic:
SwiftUI
I am able to send invitation from my device to friend's device. When friend clicks on invitation that was shared through text messages it says:
Open "Resources"?
User X wants to collaborate.
You'll join as User Y
(user Y @iCloud.com).
|Not Now| |Open|
If friend clicks on |Open| then nothing happens. Share remains in "invited" state and the callbacks which I expected to be called are not.
The official Apple CloudKit Sharing App - https://github.com/apple/sample-cloudkit-sharing/blob/main/Sharing/App/AppDelegate.swift - is confusing me because it does not have following code like typical SwiftUI app:
@main
struct MainApp: App {
Instead it uses @main for AppDelegate.
Here is my code with prints that encode what is going on:
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
print("I see this getting called on App startup")
return true
}
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
print("I also see this getting called on App startup")
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
}
func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
print("I don't see this getting called")
}
func application(userDidAcceptCloudKitShareWith cloudKitShareMetadata: CKShare.Metadata) -> Bool {
print("However, I expected this to be called when friend opened his CloudKit share invitation")
return false
}
}
@main
struct MainApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
static let sharedModelActor: ModelActorDatabase = {
let schema = Schema([
Resource.self,
])
let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false, cloudKitDatabase: .none)
do {
let modelContainer = try ModelContainer(for: schema, configurations: [modelConfiguration])
return ModelActorDatabase(modelContainer: modelContainer)
} catch {
fatalError("Could not create ModelContainer: \(error)")
}
}()
@StateObject var syncedDatabase: SyncedDatabase = SyncedDatabase(modelContainer: Self.sharedModelActor.modelContainer)
var body: some Scene {
WindowGroup {
ResourceView()
.environmentObject(syncedDatabase)
}
.modelContainer( Self.sharedModelActor.modelContainer )
.database(SharedDatabase.shared.database)
}
}
I was expecting that this would call userDidAcceptCloudKitShareWith, but it is not. Why?
User A shares zone with User B (influenced from https://github.com/apple/sample-cloudkit-zonesharing, but I have just one zone "Contacts" that I am sharing):
private func shareConfiguration() async throws -> (CKShare, CKContainer) {
let container = CKContainer(identifier: "iCloud.com.XXX.syncer")
let database = container.privateCloudDatabase
let zone = CKRecordZone(zoneName: "Contacts")
let fetchedZone = try await database.recordZone(for: zone.zoneID)
guard let existingShare = fetchedZone.share else {
print("Does not have existing share")
let share = CKShare(recordZoneID: zone.zoneID)
share[CKShare.SystemFieldKey.title] = "Resources"
_ = try await database.modifyRecords(saving: [share], deleting: [])
return (share, container)
}
print("Has existing share")
guard let share = try await database.record(for: existingShare.recordID) as? CKShare else {
throw NSError(domain: "", code: 0, userInfo: nil)
}
return (share, container)
}
...
let (share,container) = try! await shareConfiguration()
shareView = CloudSharingView(container: container, share: share) // UIViewControllerRepresentable implementation
User B accepts share invitation (borrowed from https://github.com/apple/sample-cloudkit-zonesharing)
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func windowScene(_ windowScene: UIWindowScene, userDidAcceptCloudKitShareWith cloudKitShareMetadata: CKShare.Metadata) {
guard cloudKitShareMetadata.containerIdentifier == "iCloud.com.XXX.syncer" else {
print("Shared container identifier \(cloudKitShareMetadata.containerIdentifier) did not match known identifier.")
return
}
// Create an operation to accept the share, running in the app's CKContainer.
let container = CKContainer(identifier: "iCloud.com.XXX.syncer")
let operation = CKAcceptSharesOperation(shareMetadatas: [cloudKitShareMetadata])
debugPrint("Accepting CloudKit Share with metadata: \(cloudKitShareMetadata)")
operation.perShareResultBlock = { metadata, result in
let shareRecordType = metadata.share.recordType
switch result {
case .failure(let error):
debugPrint("Error accepting share: \(error)")
case .success:
debugPrint("Accepted CloudKit share with type: \(shareRecordType)")
}
}
operation.acceptSharesResultBlock = { result in
if case .failure(let error) = result {
debugPrint("Error accepting CloudKit Share: \(error)")
}
}
operation.qualityOfService = .utility
container.add(operation)
}
}
User B through CKSyncEngine is able to read all records. However, when User B tries to write to database through CKSyncEngine, User B on his device gets following error:
<CKSyncEngine 0x1282a1400> error fetching changes with context <FetchChangesContext reason=scheduled options=<FetchChangesOptions scope=all group=CKSyncEngine-FetchChanges-Automatic)>>: Error Domain=CKErrorDomain Code=2 "Failed to fetch record zone changes" UserInfo={NSLocalizedDescription=Failed to fetch record zone changes, CKPartialErrors={
"<CKRecordZoneID: 0x3024872a0; zoneName=Contacts, ownerName=_18fb98f978ce4e9c207daaa142be6024>" = "<CKError 0x30249ed60: \"Zone Not Found\" (26/2036); server message = \"Zone does not exist\"; op = DC9089522F9968CE; uuid = 4B3432A4-D28C-457A-90C5-129B24D258C0; container ID = \"iCloud.com.XXX.syncer\">";
}}
Also, in CloudKit console, if I go to Zones, I don't see any zones under Shared Database. Wasn't I supposed to see my zone here?
However, I see "Contacts" zone under Private Database. If I expand Zone details I see following:
Zone wide sharing is enabled. All records in this zone are being shared with the sharing participants below.
And under Participants I see both User A and User B. User B is marked as:
Permission READ_WRITE
Type USER
Acceptance INVITED
What puzzles me is why READ works, but not WRITE?
I’m working on a project where I’m using CKSyncEngine to sync different types of SwiftData models, specifically User and Organization, to CloudKit. Here’s how I schedule these models to be synced:
For the User model:
let pendingSaves: [CKSyncEngine.PendingRecordZoneChange] = [.saveRecord(user.recordID)]
syncEngine.state.add(pendingRecordZoneChanges: pendingSaves)
For the Organization model:
let pendingSaves: [CKSyncEngine.PendingRecordZoneChange] = [.saveRecord(organization.recordID)]
syncEngine.state.add(pendingRecordZoneChanges: pendingSaves)
The problem arises in my CKSyncEngineDelegate's nextRecordZoneChangeBatch method where from CKRecord.ID alone I need to create the actual CKRecord that will be synced to CloudKit. This recordID alone doesn’t provide enough information to determine 1) in which local model table I need to fetch actual data to build whole CKRecord; and 2) what to put in CKRecord.recordType - whether it’s a User or an Organization.
Question:
What is the best practice for passing or determining the model type (e.g., User or Organization) in nextRecordZoneChangeBatch? How should I handle this in a way that effectively differentiates between the different model types being synced?
Any advice or examples would be greatly appreciated!
Few ideas:
embed the Model type in RecordID.recordName string, but this makes my recordNames longer (like resource_29af3932).
fetch data by recordID in all local persistent storage, but this seems slow and there is constraint that User and Organization IDs should never be the same.
introduce lookup table where from CKRecordID I can look up model type.
Somehow extend CKRecordID to add model type field?