I'm completely stuck on this one 😟I'm just presenting a simple UICloudSharingController and set the delegate.Even though my itemThumbnailData and itemTitle delegate methods are called (I can see from debugger) but they take no effect.The controller still shows the screen with "Untitled" and place holder image. Why?Further more, cloudSharingControllerDidSaveShare is also not called back when I click save.
Post
Replies
Boosts
Views
Activity
If I'm using "class definition" mode to generate the core data classes from the model, I don't get to see the files. In that case, how do I share those files with the host app and extension app if the core data stuff is in a framework?
The example they give in the doc is friends.@count https://developer.apple.com/documentation/coredata/nsderivedattributedescriptionBut is it possible to count the number of friends based on a condition? Like if friend.gender=male.@count?
I need to create some records in CloudKit for each user when they start an app.I can't just write a seed function that create records. Because when the user starts the app in two devices, they will each write their own seed record.What I want instead is for the first device to write to CloudKit gets to create the record. And then second device will simply update the values of those records no recreate them.How can I achieve this?
I'm trying to call CKFetchRecordZoneChangesOperation to get the latest changes from the shared database.But when I run that operation from inside didFinishLaunchingWithOptions, NSPersistentCloudKitContainer will break. It will save to coredata, but it will no longer sync to Cloudkit. It's as if it's paused. When I restart the app, the sync resumes.But if I call CKFetchRecordZoneChangesOperation later in the app lifecycle, say in viewDidLoad, everything works fine. Why is this?
Let's say the sequence of events go like thisI have token A for a Shared DatabaseRecords get created in Shared DatabaseI fetch for changes and downloaded new records, gets token BI accepted a new share in the same zone and databaseI take the new record (NEW_REC) from inside CKShare.Metadata and saves it, but I dont have a new tokenBut now NEW_REC gets deleted by the sharerI then fetch for new changes for the zone and use token B, but CK will not let me know NEW_REC is deletedI tested this using the dashboard, so it has nothing to do with my code.Is this intentional? I'm thinking that the algorithm is designed to work like this because it thinks that from the perspective of token B, NEW_REC never existed? So why bother telling the client is deleted?But that doesn't taken into account that the new record came from metadata. I also wonder the same case if you did CKQuery to get new records, without using CKFetchRecordZoneChangesOperation do you suffer from the same problem?
public var zonesChangeToken: [CKRecordZone.ID: CKServerChangeToken]? {
get {
if(backingPreviousZonesChangeToken == nil) {
guard let defaults: UserDefaults = UserDefaults(suiteName: CloudKitHandler.APP_GROUP_ID) else { return nil }
guard let data = defaults.data(forKey: CloudKitHandler.CK_PREVIOUS_ZONES_CHANGE_TOKEN)
else { return [CKRecordZone.ID: CKServerChangeToken]() }
do {
let unarchiver: NSKeyedUnarchiver = try NSKeyedUnarchiver(forReadingFrom: data)
unarchiver.requiresSecureCoding = true
backingPreviousZonesChangeToken = try unarchiver.decodeTopLevelObject() as? [CKRecordZone.ID: CKServerChangeToken]
} catch { }
}
return backingPreviousZonesChangeToken
}
set(value) {
backingPreviousZonesChangeToken = value
guard let value = value else { return }
guard let defaults: UserDefaults = UserDefaults(suiteName: CloudKitHandler.APP_GROUP_ID) else { return }
let archiver: NSKeyedArchiver = NSKeyedArchiver(requiringSecureCoding: true)
archiver.encode(value)
archiver.finishEncoding()
defaults.setValue(archiver.encodedData, forKey: CloudKitHandler.CK_PREVIOUS_ZONES_CHANGE_TOKEN)
}
}I'm trying to encode/decode a dictionary of IDs and Tokens. But for some reason the decode always gives me a nil.How to fix?Error Domain=NSCocoaErrorDomain Code=4864 "value for key '$0' was of unexpected class 'NSDictionary'. Allowed classes are '(null)'." UserInfo={NSDebugDescription=value for key '$0' was of unexpected class 'NSDictionary'. Allowed classes are '(null)'.}
In https://developer.apple.com/wwdc22/10054 it is shown that the best way to organize an iPad layout is by:
struct TwoColumnContentView: View {
@Binding var showExperiencePicker: Bool
@EnvironmentObject private var navigationModel: NavigationModel
var categories = Category.allCases
var dataModel = DataModel.shared
var body: some View {
NavigationSplitView(
columnVisibility: $navigationModel.columnVisibility
) {
List(
categories,
selection: $navigationModel.selectedCategory
) { category in
NavigationLink(category.localizedName, value: category)
}
.navigationTitle("Categories")
.toolbar {
ExperienceButton(isActive: $showExperiencePicker)
}
} detail: {
NavigationStack(path: $navigationModel.recipePath) {
RecipeGrid(category: navigationModel.selectedCategory)
}
}
}
}
NavigationModel defined as
final class NavigationModel: ObservableObject, Codable {
@Published var selectedCategory: Category?
@Published var recipePath: [Recipe]
@Published var columnVisibility: NavigationSplitViewVisibility
}
But what happens when in a child view, it triggers off some action in some other ViewModel that needs to update the navigation stack?
struct ChildViewModel {
func childViewCalledAndDidSomething {
//now I need to update recipePath, how?
}
}
I have the following code working great in iOS16
TextField(
"Describe...",
text: Binding(
get: { promptText },
set:
{ (newValue, _) in
if let _ = newValue.lastIndex(of: "\n") {
isFocused = false
} else {
promptText = newValue
}
}
),
axis: .vertical
)
but in iOS 17 it breaks.
But it breaks in a very mysterious way.
Firstly, the @ FocusState doesn't work.
Setting it to false does not dismiss keyboard. Fine, but also what's weird is that when I press the done button, the new line gets added to the textField anyway, even if I don't set the newValue. What's going on?
Let's say I've created a scene with 3 models inside side by side. Now upon user interaction, I'd like to change these models to another model (that is also in the same reality composer pro project). Is that possible? How can one do that?
One way I can think of is to just load all the individual models in RealityView and then just toggle the opacity to show/hide the models. But this doesn't seem like the right way for performance/memory reasons.
How do you swap in and out usdz models?
I was able to add a spotlight effect to my entities using ImageBasedLightComponent and the sample code. However, I noticed that whenever you set ImageBasedLightComponent the environmental lighting is completely turned off. Is it possible to merge them somehow?
So imagine you have a toy in a the real world, and you shine a flashlight on it. The environment light should still have an effect right?
What is the correct usage of two modelContexts (when you have a main one for swiftUI, and a background one for background operations - like networking)?
Is it expected that when the main one make updates, that the background modelContexts would also update automatically?
And if it doesn't, is there a way to force it to get updates?
Consider a sample SwiftData project
var body: some View {
List(recipes) { recipe in
NavigationLink(recipe.name, destination: RecipeView(recipe))
}
}
For SwiftUI views that uses SwiftData it's very straight forward.
However, if I need to read/write to SwiftData while in the background (let's say after a network call), the app crashes.
Imagine a simple workflow where
(1) user selects some model objects (via SwiftData modelContext)
(2) now I need to pass these objects to some API server
(3) in a background thread somewhere I need to use the modelActor but it now cannot read/write to the original model objects without risk of crashing
So instead, the only way I thought of is to create a separate modelContext for background processing. There I passed down the container from the main app, and creates a new ModelActor that takes in the container and owns a new modelContext of its own.
This works, without crash. However it introduces many side effects:
(1) read/write from this modelActor seems to trigger view changes for SwiftData's modelContext. But not vice versa.
(2) model objects fetched from one context cannot be used in another context.
(3) changes made in the actor also doesn’t not automatically sync with icloud but changes in SwiftData’s modelContext do.
So I guess the bigger question here is, what is the proper usage of SwiftData in a background thread?
Consider this code
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
init() {
let schema = Schema([
...
])
let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false)
do {
sharedModelContainer = try ModelContainer(for: schema, configurations: [modelConfiguration])
} catch {
fatalError("Could not create ModelContainer: \(error)")
}
SettingsViewModel.shared = SettingsViewModel(modelContext: sharedModelContainer.mainContext)
}
I'm basically saving a copy of mainContext in a viewModel. And then later on uses that viewModel to operate on the models while using the mainActor.
Is this ok? That same container is also pass into the view using
.modelContainer(sharedModelContainer)
Can it be used in both ways like that?
I created a local notification as follows:
func scheduleNotification(title: String, subtitle: String = "", date: Date, id: String) {
// Extract the components from the date
let calendar = Calendar.current
let hour = calendar.component(.hour, from: date)
let minute = calendar.component(.minute, from: date)
let second = calendar.component(.second, from: date)
// Set the extracted components into DateComponents
var dateComponents = DateComponents()
dateComponents.hour = hour
dateComponents.minute = minute
dateComponents.second = second
let content = UNMutableNotificationContent()
content.title = title
content.subtitle = subtitle
content.sound = UNNotificationSound.default
let action1 = UNNotificationAction(identifier: Constants.NOTIFICATION_ACTION_IDENTIFIER_1.id, title: Constants.NOTIFICATION_ACTION_IDENTIFIER_1.label, options: [])
let action2 = UNNotificationAction(identifier: Constants.NOTIFICATION_ACTION_IDENTIFIER_2.id, title: Constants.NOTIFICATION_ACTION_IDENTIFIER_2.label, options: [])
let category = UNNotificationCategory(identifier: "reminderCategory", actions: [action1, action2], intentIdentifiers: [], options: [])
UNUserNotificationCenter.current().setNotificationCategories([category])
content.categoryIdentifier = "reminderCategory"
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: false)
let request = UNNotificationRequest(identifier: id, content: content, trigger: trigger)
// add our notification request
UNUserNotificationCenter.current().add(request)
}
and I also have
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
// Handle foreground presentation options
completionHandler([.sound, .badge])
}
but for some reason the notification only shown on the phone. I've made sure that the phone is locked, apple watch is unlocked and also the notification setting in the watch app for this app is set to mirror.