Why assigning function.formula = formula does not change function.formula to formula in one go? It's always late one change behind.
struct CustomFunction has defined
.formula as @MainActor.
I feel stupid.
There is a part of code:
struct CustomFormulaView: View {
@Binding var function: CustomFunction
@State var testFormula: String = ""
@EnvironmentObject var manager: Manager
....
.onChange(of: testFormula) {
debugPrint("change of test formula: \(testFormula)")
switch function.checkFormula(testFormula, on: manager.finalSize) {
case .success(let formula):
debugPrint("before Change: \(function.formula)")
function.formula = formula // Nothing happens
debugPrint("Test formula changed: \(testFormula)")
debugPrint("set to success: \(formula)")
debugPrint("what inside function? \(function.formula)")
Task {
//Generate Image
testImage = await function.image(
size: testImageSize),
simulate: manager.finalSize)
debugPrint("test image updated for: \(function.formula)")
}
....
and it produces this output when changed from 0.5 to 1.0
Debug: change of test formula: 1.0
Debug: before Change: 0.5
Debug: Test formula changed: 1.0
Debug: set to success: 1.0
Debug: what inside function? 0.5
Debug: test image updated for: 0.5
0.5 is an old value, function.formula should be 1.0
WT??
Post
Replies
Boosts
Views
Activity
I make some small program to make dots. Many of them.
I have a Generator which generates dots in a loop:
//reprat until all dots in frame
while !newDots.isEmpty {
virginDots = []
for newDot in newDots {
autoreleasepool{
virginDots.append(
contentsOf: newDot.addDots(in: size, allDots: &result, inSomeWay))
}
newDots = virginDots
}
counter += 1
print ("\(result.count) dots in \(counter) grnerations")
}
Sometimes this loop needs hours/days to finish (depend of inSomeWay settings), so it would be very nice to send partial result to a View, and/or if result is not satisfying — break this loop and start over.
My understanding of Tasks and Concurrency became worse each time I try to understand it, maybe it's my age, maybe language barier. For now, Button with {Task {...}} action doesn't removed Rainbow Wheel from my screen. Killing an app is wrong because killing is wrong.
How to deal with it?
I try to convert view to vector graphic (PDF) using ImageRenderer. But output image has ALL coordinates rounded to integer values, which is not OK - some very small circles become elipses, squares are no longer squares, very detailed or small shapes are distorted by rounding coordinates. Is a some option to switch off rounding?
I try to generate PDF from view. View is nice, there is a lot of transparency and many gradients (circular and linear). But if I use ImageRenderer in in a way that documentation suggest all transparency and gradients disappear. Is this bug or some feature? Is it way to generate vector graphic from view with transparency and gradients? PDF allows those features, so why not?
I have a view, and in this view I bind Axis class values — lowerBound which is a regular property and at – computed one which comes from protocol HasPositionProtocol associated with Axis.
struct AxisPropertiesView<Axis>: View
where Axis: StyledAxisProtocol,
Axis: HasPositionProtocol,
Axis: Observable
{
@Bindable var axis: Axis
var body: some View {
HStack {
TextField("", text: $axis.shortName)
.frame(width: 40)
TextField("",
value: $axis.lowerBound,
format: .number)
.frame(width: 45)
//Problem is here:
Slider(value: $axis.at,
in: axis.bounds)
...
Unfortunately I got en error Failed to produce diagnostic for expression; ... for whole View.
But if I remove Slider from View, error disappeared.
What could cause this strange behaviour?
Value of .at comes from:
public extension HasPositionProtocol {
///Absolut position on Axis
var at: Double {
get {
switch position {
case .max:
return bounds.upperBound
case .min:
return bounds.lowerBound
case .number(let number):
return number
}
}
set {
switch newValue {
case bounds.lowerBound:
position = .min
case bounds.upperBound:
position = .max
default:
position = .number(newValue)
}
}
}
}
I have a MacOS package dependency which defines some class: FontPens
import Foundation
...
public class BoundsPen: Pen {
var bounds = CGRect.null
private var currentPoint = CGPoint.zero
....
After upgrading Xcode to 14.1 both lines throws errors Type 'CGRect' has no member 'null' and Type 'CGPoint' has no member 'zero'.
Calling CGPoint.zero and CGRect.null from an app is OK if Foundation is imported.
Is it a way to solve this problem without changing package source?
I have a MacOS app which has a lot of TextFields in many views; and one editor view which has to receive pressed keyboard shortcut, when cursor is above. But as I try, I cannot focus on a view which is not text enabled. I made a small app to show a problem:
@main
struct TestFocusApp: App {
var body: some Scene {
DocumentGroup(newDocument: TestFocusDocument()) { file in
ContentView(document: file.$document)
}
.commands {
CommandGroup(replacing: CommandGroupPlacement.textEditing) {
Button("Delete") {
deleteSelectedObject.send()
}
.keyboardShortcut(.delete, modifiers: [])
}
}
}
}
let deleteSelectedObject = PassthroughSubject<Void, Never>()
struct MysticView: View {
var body: some View {
ZStack {
Rectangle()
.foregroundColor(.gray.opacity(0.3))
}.focusable()
.onReceive(deleteSelectedObject) { _ in
print ("received")
}
}
}
enum FocusableField {
case wordTwo
case view
case editor
case wordOne
}
struct ContentView: View {
@Binding var document: TestFocusDocument
@State var wordOne: String = ""
@State var wordTwo: String = ""
@FocusState var focus: FocusableField?
var body: some View {
VStack {
TextField("one", text: $wordOne)
.focused($focus, equals: .wordOne)
TextEditor(text: $document.text)
.focused($focus, equals: .editor)
///I want to receive DELETE in any way, in a MystickView or unfocus All another text views in App to not delete their contents
MysticView()
.focusable(true)
.focused($focus, equals: .view)
.onHover { inside in
focus = inside ? .view : nil
/// focus became ALWAYS nil, even set to `.view` here
}
.onTapGesture {
focus = .view
}
TextField("two", text: $wordTwo)
.focused($focus, equals: .wordTwo)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView(document: .constant(TestFocusDocument()))
}
}
Only first TextField became focused when I click or hover over MysticView
I can assign nil to focus, but it will not unfocus fields from outside this one view.
Is it a bug, or I missed something? How to make View focusable? To Unfocus all textFields?
I build a graphic editor. Dragging points through my canvas is smooth and fast. But when I try to display data in outline view everything slows down to 2 FPS. First I suspected slow data access, but when I check app in Instruments I found Core Animation Commits are displayed as a red blocks and Time Profiler bit busy.
Is a way to disable Core Animation for some views? Or this message is misleading?
I have a VSplitView with two views inside. But each time app starts proportions are set to 50/50, each one has the same height. I would like to set height of one of them to some number, (and save it in defaults... not most important thing). Of course I would like to change this height manually if I need to.
var body: some View {
return VSplitView {
HigherView(with: someContent) // Let it be float height
ShorterView(with: anotheContent) // let it height will be 300 when fired first time
}
}
Is it very hard?
I have a ZStack view embedded in ScrollView. The height of ZStack often changes.
var body: some View {
ScrollView([.vertical, .horizontal], showsIndicators: true) {
VStack { // embedding in VStack doesn't change behaviour
ZStack () {
ForEach(mapElements.indices, id:\.self) { i in
let element = mapElements[i]
MapElementView (mapElement: element)
.position(x: offset(x: element.x),
y: offset(y: element.y))
.zIndex(5)
MakeConnections(mapElement: element)
}
}.frame(width: calculateWidth(),
height: calculateHeight())
}
Rectangle() // Just to make VStack filled
}
}.frame(alignment: .topLeading)
}
Some scroll views (ie. list) always align embedded objects to top even they are shorter than embedding scroll view. But in this case ZStack is always centred when view is refreshed.
Is it possible to define behaviour, so each change of a content will align its top to scroll view top, even if height of ZStack is smaller than ScrollView?
As in a title: even empty new app has menu with working menu items, but with disabled and not working keyboard shortcuts. Is it bug, feature or I should do something to enable them?
Minimize, Zoom... works.
My Edit Menu have the same problem:
Commands Undo, Redo and Delete works when chosen from menu, but calling them via keyboard causes only cursor disappear.
I'm trying to learn how UndoManager works. I made a small app to Undo/Redo something.
And I have few questions, I cannot find answer in documentation:
I know UndoManager could be accessed in View via
@Environment(\.undoManager) var undoManager
Brilliant. But in this case it's only available in a View, if I want use it somewhere deeper in a structure I have to pass it via Model to Objects... Is a way to access the same UndoManager in other objects? Models, Data... I could be much more convenient, specially if there is many Undo groupings. If I create UndoManager in Document (or somewhere else) it's not visible for main menu Edit -> Undo, Redo
In the app repository on GitHub I implemented Undo/Redo. For me (haha) it looks OK and even works, but not for first action. First action Undo causes Thread 1: signal SIGABRT error. After three actions I can undo two last actions... Bang. Something is wrong
import Foundation
import SwiftUI
struct CustomView: View {
@ObservedObject var model: PointsViewModel
@Environment(\.undoManager) var undoManager
@GestureState var isDragging: Bool = false
@State var dragOffsetDelta = CGPoint.zero
var formatter: NumberFormatter {
let formatter = NumberFormatter()
formatter.allowsFloats = true
formatter.minimumFractionDigits = 2
formatter.maximumFractionDigits = 5
return formatter
}
var body: some View {
HStack {
VStack(alignment: .leading, spacing: 10) {
ForEach(model.insideDoc.points.indices, id:\.self) { index in
HStack {
TextField("X", value: $model.insideDoc.points[index].x, formatter: formatter)
.frame(width: 80, alignment: .topLeading)
TextField("Y", value: $model.insideDoc.points[index].y, formatter: formatter)
.frame(width: 80, alignment: .topLeading)
Spacer()
}
}
Spacer()
}
ZStack {
ForEach(model.insideDoc.points.indices, id:\.self) { index in
Circle()
.foregroundColor(index == model.selectionIndex ? .red : .blue)
.frame(width: 20, height: 20, alignment: .center)
.position(model.insideDoc.points[index])
//MARK: - drag point
.gesture(DragGesture(minimumDistance: 0, coordinateSpace: .local)
.onChanged { drag in
if !isDragging {
dragOffsetDelta = drag.location - model.insideDoc.points[index]
model.selectionIndex = index
let now = model.insideDoc.points[index]
undoManager?.registerUndo(withTarget: model, handler: { model in
model.insideDoc.points[index] = now
model.objectWillChange.send()
})
undoManager?.setActionName("undo Drag")
}
model.insideDoc.points[index] = drag.location - dragOffsetDelta
}
.updating($isDragging, body: { drag, state, trans in
state = true
model.objectWillChange.send()
})
.onEnded({drag in model.selectionIndex = index
model.insideDoc.points[index] = drag.location - dragOffsetDelta
model.objectWillChange.send()
})
)
}
}.background(Color.orange.opacity(0.5))
//MARK: - new point
.gesture(DragGesture(minimumDistance: 0, coordinateSpace: .local)
.onEnded{ loc in
let previousIndex = model.selectionIndex
undoManager?.registerUndo(withTarget: model, handler: {model in
model.insideDoc.points.removeLast()
model.selectionIndex = previousIndex
model.objectWillChange.send()
})
model.insideDoc.points.append(loc.location)
model.selectionIndex = model.insideDoc.points.count - 1
model.objectWillChange.send()
}
)
//MARK: - delete point
.onReceive(deleteSelectedObject, perform: { _ in
if let deleteIndex = model.selectionIndex {
let deleted = model.insideDoc.points[deleteIndex]
undoManager?.registerUndo(withTarget: model, handler: {model in
model.insideDoc.points.insert(deleted, at: deleteIndex)
model.objectWillChange.send()
})
undoManager?.setActionName("remove Point")
model.insideDoc.points.remove(at: deleteIndex)
model.objectWillChange.send()
model.selectionIndex = nil
}
})
}
}
}
Any comments about quality of my algorithms will be highly appreciated.
Maybe I missed something — is it possible to somehow edit / change / customise main menu in SwiftUI App lifecycle? I made a document based App, I can read, write, even Recent Documents have for free. But how to add or remove Items, and connect them with app in pure SwiftUI way? With no AppKit, pure?
I try to build an app in MacOS SwiftUI, where two different subviews of main contentView shows different parts of Axis element:struct ContentView: View {
		@Binding var document: GlyphDesignerDocument
		
		var body: some View {
				HStack {
						//Axes Sliders Slider causes explosion
AxesSlidersView(axes: $document.axes)
AxesView(axes: $document.axes,
addRows: {document.axes.insert(Axis("z", bounds: 0...1000), at: $0)},
removeRows: {document.axes.remove(at: $0)},
addAxis: {document.axes.append(Axis("z", bounds: 0...1000))})
}
}
Subviews works great, everything updates in both ways, but application hangs-up when AxisView will delete one Axis from axes array.
All experimental code (still changing) is available at https://github.com/typoland/GlyphDesignerTest
AxesView looks like this:
		struct AxesView : View {
				@Binding var axes: [Axis]
				@State var selected: Int? = nil
				var addRows: (_ at:Int) -> Void
				var removeRows: (_ at: Int) -> Void
				var addAxis: () -> Void
				var body: some View {
						VStack {
								.... Shows Axes
						}
				}
		}
		struct AxisView: View {
				
				@Binding var axis: Axis
				var insert: () -> Void
				var delete: () -> Void
				@Binding var selected: Bool
				
				var body: some View {
						HStack {
							 //Makes ForEach for each Axis, adds buttons to insert and delete, more parameters of an Axis...
						}
				}
		}
		struct AxesSlidersView: View {
				@Binding var axes: [Axis]
				var body: some View {
						VStack {
								ForEach(axes.indices, id:\.self) {index in
		HStack {
												 Text("\(axis.name)")
													Slider (value: $axes[index].at, in: axis.bounds)
		 }
}
						}
				}
		}
		
After suggestion received on stackoverflow I changed:
Slider (value: $axes[index].at, in: axis.bounds)
to
Slider (value: Bound(get: {axis.ataxes[index].at}, set: {axes[index].at = $0}, in: axis.bounds)
This way I can delete axis without explosion, but, second view does not live update anymore.
Is it SwiftUI problem? How to deal with this? @Binding arrays is somehow broken?
I have a struct:public typealias CoordUnit = Double
public struct StyledAxis: StyledAxisProtocol {
		public var name: String
		public var bounds: ClosedRange<CoordUnit>
		public var distribution: Double?
...
}
In SpaceAxisProtocol bounds are defined as:
		public protocol SpaceAxisProtocol: Equatable & Hashable {
				var name: String {get set}
				var bounds: ClosedRange<CoordUnit> {get set}
			 init(_ name: String, bounds: ClosedRange<CoordUnit>)
		}
		public protocol StyledAxisProtocol: SpaceAxisProtocol {...}
And I try to edit bounds in a View:
		struct StyledAxisView<SA:StyledAxisProtocol>: View {
				@Binding var axis: SA
				
				public var body : some View {
						VStack {
								// Axis name and distribution works
								HStack(alignment: .lastTextBaseline) {
										TextField("", text: $axis.name)
												.controlSize(.small)
												.font(.headline)
										
										DistributionView(
												value: $axis.distribution)
												.controlSize(.mini)
								}
								// It causes compiler `Cannot assign to property: 'lowerBound' is a 'let' constant`. But it isn't. ?
								HStack {
										ValueView(value: $axis.bounds.lowerBound)
										ValueView(value: $axis.bounds.upperBound)
								}
								...
When axis.bounds.lowerbound and axis.bounds.upperbound became let? How to edit them in View?