Posts

Post not yet marked as solved
2 Replies
831 Views
Hi, say in my model I have members and each member optionally can have a relationship to a Club. So the relationship in the Member entity would be modelled like so: @Relationship(.nullify, inverse: \Club.members) var club: Club? Now I would like to fetch al Members with no Club relationship. I would assume that this would work with a predicate like this: let noClubPred = #Predicate<Member> { member in member.club == nil } Unfortunately this gives me the following error when compiling: Generic parameter 'RHS' could not be inferred. Has anybody an idea how to phrase this predicate correctly, or is this a beta issue and it should actually work? Thank you! Cheers, Michael
Posted
by milutz.
Last updated
.
Post not yet marked as solved
2 Replies
1.9k Views
Hi, using the following ContentView in a SwiftUI app on macOS I would expect that the state of the toggle persists across application launches: struct ContentView: View { @SceneStorage("Toggle") var onOrOff: Bool = false var body: some View { VStack { Toggle("Will it persist?", isOn: $onOrOff) .padding() } } } To my surprise it does not persist. Am I wrong about how @SceneStorage should work? (I am trying this on the lates macOS/Xcode versions) Does @SceneStorage work for anybody on macOS? Thanks for your feedback! Cheers, Michael
Posted
by milutz.
Last updated
.
Post not yet marked as solved
4 Replies
1.7k Views
Hi, when inserting an entity with a relationship I get the following runtime error: Illegal attempt to establish a relationship 'group' between objects in different contexts [...]. The model looks like this: @Model class Person { var name: String @Relationship(.nullify, inverse: \Group.members) var group: Group init(name: String) { self.name = name } } @Model class Group { var name: String @Relationship(.cascade) public var members: [Person] init(name: String) { self.name = name } } It can be reproduced using this (contrived) bit of code: let group = Group(name: "Group A") ctx.insert(group) try! ctx.save() let descriptor = FetchDescriptor<Group>() let groups = try ctx.fetch(descriptor) XCTAssertFalse(groups.isEmpty) XCTAssertEqual(groups.count, 1) XCTAssertTrue(groups.first?.name == "Group A") let person = Person(name: "Willy") person.group = group ctx.insert(person) try ctx.save() (See also full test case below). Anybody experiencing similar issues? Bug or feature? Cheers, Michael Full test case: import SwiftData import SwiftUI import XCTest // MARK: - Person - @Model class Person { var name: String @Relationship(.nullify, inverse: \Group.members) var group: Group init(name: String) { self.name = name } } // MARK: - Group - @Model class Group { var name: String @Relationship(.cascade) public var members: [Person] init(name: String) { self.name = name } } // MARK: - SD_PrototypingTests - final class SD_PrototypingTests: XCTestCase { var container: ModelContainer! var ctx: ModelContext! override func setUpWithError() throws { let fullSchema = Schema([Person.self, Group.self,]) let dbCfg = ModelConfiguration(schema: fullSchema) container = try ModelContainer(for: fullSchema, dbCfg) ctx = ModelContext(container) _ = try ctx.delete(model: Group.self) _ = try ctx.delete(model: Person.self) } override func tearDownWithError() throws { guard let dbURL = container.configurations.first?.url else { XCTFail("Could not find db URL") return } do { try FileManager.default.removeItem(at: dbURL) } catch { XCTFail("Could not delete db: \(error)") } } func testRelAssignemnt_FB12363892() throws { let group = Group(name: "Group A") ctx.insert(group) try! ctx.save() let descriptor = FetchDescriptor<Group>() let groups = try ctx.fetch(descriptor) XCTAssertFalse(groups.isEmpty) XCTAssertEqual(groups.count, 1) XCTAssertTrue(groups.first?.name == "Group A") let person = Person(name: "Willy") person.group = group ctx.insert(person) try ctx.save() } }
Posted
by milutz.
Last updated
.
Post not yet marked as solved
1 Replies
705 Views
Hi, I am trying my first SwiftData migration, but my custom migration stage never gets called. Since I am not sure if this is a bug with the current beta of if I am "holding it wrong" I was wondering, if anybody got migration working (their MigrationStage.custom called)? Would be great, if you could just let me know, if you got it working or running into the same issue! :-) Thank you! Cheers, Michael
Posted
by milutz.
Last updated
.
Post not yet marked as solved
4 Replies
1k Views
Hi, if I have a @Model class there's always an id: PersistentIdentifier.ID underneath which, according to the current documentation "The value that uniquely identifies the associated model within the containing store.". So I am wondering if it is (good) enough to rely on this attribute to uniquely identify @Model class entities, or if there are edge cases where it does not work (like maybe when using CloudKit)? If anybody saw some information regarding this, please let me know :-) Cheers, Michael
Posted
by milutz.
Last updated
.
Post not yet marked as solved
4 Replies
1.6k Views
Hi, in the session the following is mentioned: If a trip already exists with that name, then the persistent back end will update to the latest values. This is called an upsert. An upsert starts as an insert. If the insert collides with existing data, it becomes an update and updates the properties of the existing data. Nevertheless, if I have a unique constraint on an (String) attribute and try to insert the same again, I end up in the debugger in the generated getter of the attribute: @Attribute(.unique) public var name: String { get { _$observationRegistrar.access(self, keyPath: \.name) return self.getValue(for: \.name) // <- here } EXC_BREAKPOINT (code=1, subcode=0x1a8d6b724) Am I missing something? If this is expected behaviour, how should I prevent this crash (other than checking for uniqueness before every insert)? Thank you! Cheers, Michael
Posted
by milutz.
Last updated
.
Post marked as solved
2 Replies
786 Views
Hi, given this model: @Model class OnlyName { var name: String init(name: String) { self.name = name } } I would assume that I could write a predicate like this: #Predicate<OnlyName> { $0.name == other.name }, where other is also an instance of OnlyName for example returned by an earlier fetch. Unfortunately this results in the following compiler errors: Initializer 'init(_:)' requires that 'OnlyName' conform to 'Encodable' Initializer 'init(_:)' requires that 'OnlyName' conform to 'Decodable' Any idea if this is a bug in SwiftData or if I am missing something? Cheers, Michael
Posted
by milutz.
Last updated
.
Post not yet marked as solved
0 Replies
985 Views
Hi, I encountered the issue, that unless an inverse relationship is modelled, the relationship is not persisted. This can be reproduced with the sample code below: Press the "Add Person" button twice Then press the "Add group" button You now can see that the group has to member, but once you restart the app the members a gone. Once an inverse relationship is added (see commented code) the relationships are persisted. Any idea if this is intended behaviour? import SwiftData import SwiftUI // MARK: - Person - @Model class Person { var name: String // uncomment to make it work @Relationship(.nullify) var group: Group? init(name: String) { self.name = name } } // MARK: - Group - @Model class Group { var name: String // uncomment to make it work @Relationship(.nullify, inverse: \Person.group) public var members: [Person] @Relationship(.nullify) public var members: [Person] // comment to make it work init(name: String) { self.name = name } } // MARK: - SD_PrototypingApp - @main struct SD_PrototypingApp: App { var body: some Scene { WindowGroup { ContentView() } .modelContainer(for: [Person.self, Group.self]) } } // MARK: - ContentView - struct ContentView: View { @Environment(\.modelContext) private var modelContext @Query private var groups: [Group] @Query private var persons: [Person] var body: some View { VStack { ForEach(groups) { group in Text("\(group.name): \(group.members.count)") } ForEach(persons) { person in Text("Person: \(person.name)") } Button { assert(persons.isEmpty == false) if groups.isEmpty { let group = Group(name: "Group A") group.members = persons modelContext.insert(group) try! modelContext.save() } } label: { Text("Add a group") } .disabled(!groups.isEmpty || persons.isEmpty) Button { let person = Person(name: "Person \(Int.random(in: 0 ... 1_000_000))") modelContext.insert(person) } label: { Text("Add Person") } } } }
Posted
by milutz.
Last updated
.
Post not yet marked as solved
1 Replies
565 Views
Hi! When using the Sample "NavigationCookbook" in the two column layout, the selection in the first column is not remembered, when navigating to the Home Screen and back. This behaviour can be reproduced by starting the app on the iPad or simulator, selecting for example "Pancake" and then navigating to the home screen and back into the navigation. Sometimes this (the navigation to/back from the home screen) has to be done twice, to lose the selection. In the console log you can see the message "Update NavigationAuthority bound path tried to update multiple times per frame." appearing. Not sure if this has something todo with the selection being lost. This is on iOS 16.4.1 not sure if the behaviour before was different. Anybody experiences the same behaviour? Bug in SwiftUI or in the sample app? Cheers, Michael
Posted
by milutz.
Last updated
.
Post not yet marked as solved
0 Replies
1k Views
Hi, when generating thumbnails I sometimes see the error "QLThumbnailErrorDomain Code=110". This happens to files which can be processed when trying again, so it is not an issue with the files in general. I could not find an error with that code here. Any ideas where to look and/or what causes this? Thanks, Michael
Posted
by milutz.
Last updated
.
Post not yet marked as solved
1 Replies
1.9k Views
Hi, I want to import GPX files into my iOS App. It works fine in the simulator using: .fileImporter(isPresented: $showFileImporter, allowedContentTypes: [UTType(filenameExtension: "gpx")!, UTType(filenameExtension: "GPX")!], allowsMultipleSelection: true) But running the app on an actual device (iOS 15 Beta 6), I am not allowed to select any of the GPX files. The strange thing is, that if I am using "jpg" instead of "gpx" I can select "jpg" files just fine. So it seems, that it has to do something with the "GPX" type being 'custom'. Any idea/hint what I am missing? Thank you! Michael
Posted
by milutz.
Last updated
.
Post not yet marked as solved
3 Replies
2.6k Views
Hi, it seems that a @State variable in a View will not update (initialize to the new value) on subsequent calls to the Views .init method. In the example below (tested on macOS) the Text("internal: \(_internalNumber)") still shows 41, even after 1s is over and number was set to 42 (in the .task). TestView.init runs as expected and _internalNumber shows the correct value there, but in the body method (on the redraw) _internalNumber still has the old value. This is not how it should be, right? import SwiftUI struct ContentView: View { @State private var number = 41 var body: some View { VStack { TestView(number: number) .fixedSize() } .task { try! await Task.sleep(nanoseconds: 1_000_000_000) await MainActor.run { print("adjusting") number = 42 } } } } //////////////////////// // MARK: - TestView - public struct TestView: View { public init(number: Int) { self.number = number __internalNumber = .init(initialValue: number) print("Init number: \(self.number)") print("Init _internalNumber: \(_internalNumber)") } var number: Int @State private var _internalNumber: Int public var body: some View { VStack(alignment: .leading) { Text("number: \(number)") Text("internal: \(_internalNumber)") } .debugAction { Self._printChanges() print("number: \(number)") print("_internalNumber: \(_internalNumber)") } } } // MARK: - debugAction extension View { func debugAction(_ closure: () -> Void) -> Self { closure() return self } }
Posted
by milutz.
Last updated
.
Post not yet marked as solved
4 Replies
1.4k Views
Hi, I have a strange case involving sheets, which I think it's a bug, but then again I might be missing something. Using the following code: import SwiftUI enum WhichSheet: String { &#9;case one, two, three, none } struct ContentView: View { &#9;@State private var _showSheet = false &#9;@State private var _whichSheet: WhichSheet = .none &#9;&#9;var body: some View { &#9;&#9;&#9;VStack(spacing: 8) { &#9;&#9;&#9;&#9;&#9;Button("One Sheet", action: { self._whichSheet = .one; self._showSheet = true}) &#9;&#9;&#9;&#9;&#9;Button("Two Sheet", action: { self._whichSheet = .two; self._showSheet = true}) &#9;&#9;&#9;&#9;&#9;Button("Three Sheet", action: { self._whichSheet = .three; self._showSheet = true}) &#9;&#9;&#9;} &#9;&#9;&#9;&#9;.sheet(isPresented: $_showSheet, content: { &#9;&#9;&#9;&#9;Text("whichSheet = \(_whichSheet.rawValue)") &#9;&#9;&#9;}) &#9;&#9;} } struct ContentView_Previews: PreviewProvider { &#9;&#9;static var previews: some View { &#9;&#9;&#9;ContentView() &#9;&#9;} } I would assume that, depending on which button is pressed, I would say a sheet with the text "whichSheet = one" or "whichSheet = two" etc. But no matter which button is pressed first the text on the sheet is always "whichSheet = none". Only if you choose a different button the second (or third, or ...) time the correct text is being displayed. Bug or am I missing something really obvious? (Test using an iOS 14 / 14.2 project with Xcode 12 / 12.2 beta) Cheers, Michael
Posted
by milutz.
Last updated
.
Post not yet marked as solved
1 Replies
1.8k Views
Hi, having the concurrency checks (-Xfrontend -warn-concurrency -Xfrontend -enable-actor-data-race-checks-Xfrontend -warn-concurrency -Xfrontend -enable-actor-data-race-checks) enabled I always get this warning, when trying to access/use an actor in a SwiftUI .task: "Cannot use parameter 'self' with a non-sendable type 'ContentView' from concurrently-executed code". What would be a correct implementation? Here's a minimal code-sample which produces this warning: import SwiftUI struct ContentView: View { @State var someVar = 5 var a1 = A1() var body: some View { Text("Hello, world!") .padding() .task { await a1.doSomething() } } } public actor A1 { func doSomething() { print("Hello") } }
Posted
by milutz.
Last updated
.
Post not yet marked as solved
1 Replies
1k Views
Hi, I am using a child NSManagedContext trying to isolate changes to a NSManagedObject from changes done to the same object in the parent NSManagedObjectContext. This works fine for normal properties, but any changes to relationships performed on the object in the parent context will show up immediately in the child object as well. Is this the intended behavior? If yes is there a way to create an "isolated" version of an NSManagedObject? Thanks in advance for any hints! Cheers, Michael
Posted
by milutz.
Last updated
.