The SwiftData predicate documentation says that it supports the contains(where:) sequence operation in addition to the contains(_:) string comparison but when I put them together in a predicate to try and perform a tokenised search I get a runtime error.
Unsupported subquery collection expression type (NSInvalidArgumentException)
I need to be able to search for items that contain at least one of the search tokens, this functionality is critical to my app. Any suggestions are appreciated. Also does anyone with experience with CoreData know if this is possible to do in CoreData with NSPredicate?
import SwiftData
@Model
final class Item {
var textString: String = ""
init() {}
}
func search(tokens: Set<String>, context: ModelContext) throws -> [Item] {
let predicate: Predicate<Item> = #Predicate { item in
tokens.contains { token in
item.textString.contains(token)
}
}
let descriptor = FetchDescriptor(predicate: predicate)
return try context.fetch(descriptor)
}
Post
Replies
Boosts
Views
Activity
Has anyone successfully persisted Color, particularly in SwiftData? So far my attempts have failed:
Making Color conform to Codable results in a run time error (from memory something about ColorBox).
Color.Resolved already conforms Codable but this results in "SwiftData/ModelCoders.swift:124: Fatal error: Composite Coder only supports Keyed Container"
None of the other color types conform to Codable (CGColor, NSColor and UIColor) so does the swift language really not have a persistable color type?
I am persisting a tree data structure Node using SwiftData with CloudKit enabled. I understand how to manage my NonSingleton models in SwiftUI. However, when a user first launches my app a Node model instance needs to be created that is separate from any NonSingleton model. So I think a Singleton class is appropriate but I don't know how to persist it?
@Model
final class Node {
var parent: Node?
@Relationship(deleteRule: .cascade, inverse: \Node.parent)
var children = [Node]()
// ...
}
@Model
final class NonSingleton {
@Relationship(deleteRule: .cascade) var node: Node
// ...
}
@Model // ?
final class Singleton {
static var node = Node()
private init() {}
}
I want to be able to detect when an auxiliary window is closed in order to display a confirmation dialog box. Apple's Mail app on MacOS exhibits this exact behaviour when a user closes a message they were composing, a dialog box appears asking to save, don't save or cancel.
I am programmatically opening the auxiliary windows using the openWindow action in combination with the corresponding WindowGroup initialiser as described in this article Presenting windows and spaces and the WWDC video Bring multiple windows to your SwiftUI app.
The child views of my container need to get (not set) the size of container from within their view body, in order to perform some calculation. I've made a custom container that conforms to the Layout protocol (the actual implementation isn't important). The required placeSubviews method has a bounds parameter which is the size of container. Does anyone know whether it is possible to store the bounds somewhere so that the subviews of the container can access it, such as in environment key of the view hierarchy? Or is my only option to use a GeometryReader?
struct CustomContainer: Layout {
func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout Void) -> CGSize {
// Calculate and return the size of the layout container.
}
func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout Void) {
// Tell each subview where to appear.
// Can I store bounds parameter somewhere??
}
}
Is it intended behaviour for rotationEffect to choose its parent views centre as the axis of rotation, when applied after the position modifier? Whereas, if rotationEffect is applied before position, it rotates the view about its own centre. This can be demonstrated by the following which is not equivalent to a 360 degree rotation ie. no rotation:
Image(systemName: "arrowshape.up.fill")
.rotationEffect(.degrees(180))
.position(x:50, y: 50)
.rotationEffect(.degrees(180))
Why is my RedArrow view rotating about the centre of the BlueArrow and not itself? What I expect to happen is for the RedArrow to end up at the bottom right corner facing up.
This could be achieved by rotating the RedArrow about its own centre and then rotating the RedArrow about the BlueArrows centre. But if I remove the outer rotation, it is clear that the RedArrow is being rotated about the BlueArrows centre twice thus returning it to its starting point.
In my actual app I don't need the BlueArrow to rotate at all so if there is a way of "inverting" the position modifier, this would also achieve my goal. By "inverting" I mean that instead of measuring the position(x:25, y: 25) from the top left corner of ContentView (towards the centre of the RedArrow), it would measure from the bottom right corner flipping the direction of the x and y axis.
struct BlueArrow: View {
var body: some View {
Image(systemName: "arrowshape.up.fill")
.resizable()
.frame(width: 200, height: 200)
.foregroundColor(.blue)
}
}
struct RedArrow: View {
var body: some View {
Image(systemName: "arrowshape.up.fill")
.resizable()
.frame(width: 50, height: 50)
.foregroundColor(.red)
.position(x:25, y: 25)
}
}
struct ContentView: View {
@State var rotation: Double = 0
var body: some View {
VStack {
Button("flip") {
rotation = rotation == 0 ? 180 : 0
}
BlueArrow()
.overlay {
RedArrow()
.rotationEffect(.degrees(rotation), anchor: .center)
}
.rotationEffect(.degrees(rotation), anchor: .center)
}
}
}
I've put together a simplified code example to test how the location of dropDestination works within a Grid View. When I attach dropDestination to Grid, GridRow or the Text("\(row) , \(column)") view, I get a CGPoint corresponding to the drop location within the views coordinate space. But the problem is how would I get the either the index of a grid cell eg. (1, 1) or the grid cell view itself?
Apple's documentation regarding drag and drop in SwiftUI says to
prefer using transferable items
which I interpret as them recommending dropDestination over the older onDrop with an NSItemProvider.
But unlike in a List view there doesn't seem to be away for location to return discrete values. If I instead attach dropDestination to a one of the nested ForEach loops within the Grid view, the drop gesture doesn't do anything?
Also dropDestination exhibits some default behaviour that I don't want.
When dragging a view a little plus symbol within a green circle appears
Views can be dragged and dropped out of the apps window which transfers the data, in this case it creates a text file in the desktop
I could of sworn I read documentation or online resources that implied this behaviour was supposed to be opt-in rather than applied by default?
Ultimately, what I want to learn how to do is drag and drop views into grid cells. I've only been coding in Swift for a few months so it would be helpful if someone with more experience points me in the right direction.
import SwiftUI
struct ContentView: View {
var input: String = "hello world"
@State var output: String = " "
var body: some View {
VStack {
Text(input)
.frame(width: 100, height: 50)
.border(Color.blue, width: 2)
.draggable(input)
Grid {
ForEach(1..<4) { row in
GridRow {
ForEach(1..<4) { column in
Text("\(row) , \(column)")
.frame(width: 100, height: 50)
.border(Color.red, width: 2)
}
}
}
}.dropDestination(for: String.self) { _, location in
output = "\(location.x), \(location.y)"
return true
}
List {
ForEach(1..<4) { i in
Text("\(i)")
.frame(width: 100, height: 50)
.border(Color.green, width: 2)
}.dropDestination(for: String.self) { _, location in
output = "\(location)"
}
}
Text(output)
.frame(width: 200, height: 50)
.border(Color.cyan, width: 2)
}
}
}
I'm working on a chess GUI app (my first app) and I can't seem to figure out how to implement the drop part of drag and drop. So far I'm able to display a static chess board and pieces onto the screen and either use onTapGesture or DragGesture to move them but the UX isn't right yet. Do I need to use the draggable and dropDestination methods instead? Any advice or a simple code example that would get me going would be appreciated. Here are my requirements below to be clear:
Display an 8x8 Grid View (or I suppose LazyGrid) where all cells contain a Color view, and some may overlay an SF Symbol Image depending on the models state
UI needs to update the underlying model state and vice versa
Drag and drop gesture should be self contained within the Grid View, so no transfer of data between other window instances
Only one SF Symbol should be draggable and droppable at a time
An SF symbol dropped onto another should remove it from the state model
The drop gesture should snap a piece into the centre of the closest grid cell (or return it if it was an illegal chess move)
No need for backwards compatibility, I'm focusing on current software and hardware
Compatible with iOS, MacOS, iPadOS, WatchOS and potentially VisionOS