Post

Replies

Boosts

Views

Activity

KeyframeAnimator or PhaseAnimator with long tail spring animations
Hi, When defining a KeyFrameAnimation with spring tracks, the animation do not complete until the very end , but, as default when using withAnimation with a spring animation, it will start the next animation For example if a complete spring animation is 600ms, the next animation may start only after 300ms My designer has given me the mass, stiffness, and dumping values for the animation, and expects that the animation will perform for X time, and after that a new animation will start, as it occurs on figma Using withAnimation with completition callback i can replicate the behaviour, using the ".removed" CompletitionCriteria, but i'd rather use the new KeyFrame phase animator, because i'm not very confident having 5-6 animations started recursively with "withAnimation"
0
0
572
Aug ’23
Bindable is never deallocated
I've encountered a problem which I don't know if is related to swiftui, the observation framework, or both If I run the following code I have two tabs, with the second tab that use a "lazy model" which is deallocated each time disappears (this is necessary for my use case) If I switch to the second tab, all works right. If I return to the first tab, the onDisappear on the foo view should force the "Bar" variable to nil , because the FooView may be still allocated (it is a tab bar) but that resource should be released If that bar variable is set to nil, the MyBar should be replaced by the ProgressView in the "background" I expect regarding that the Bar that: the instance is nil on Foo no other view should be shown with that instance (MyBar is now disappeared) Because no ref, the Bar observable object should be now deallocated In reality the Bar object is still in my memory graph Any suggestions? is it a bug? @Observable class Bar { var hello: String = "" } struct Foo: View { @State var bar: Bar? @ViewBuilder private var content: some View { if let bar { MyBar(bar: bar) } else { ProgressView() } } var body: some View { content .onAppear { bar = Bar() } .onDisappear { self.bar = nil } } } struct MyBar: View { @Bindable var bar: Bar var body: some View { Text("MyBar") } } struct ContentView: View { @State var tag: Int = 0 var body: some View { TabView(selection: $tag) { Text("First") .tag(0) .tabItem { Text("First") } Foo() .tag(1) .tabItem { Text("Foo") } } } }
1
0
672
Nov ’23
State that contains a class (example: an enum with associated values) will retain the class until another state change
When using as a State in view that contains a class object (as an example an Enum with associated values, or directly the class as a nillable state): When the body will trigger a state change, that should deallocate that object (as an example setting the enum to another value that do not contains the object as the associated value, or setting the state class to nil), the object is not deallocated If then the state change another time, setting the state to a third different value (ex: setting enum to a third case) the class object will be then deallocated. In case of not passing through a third state (ex. alternating nil and not nil object) the first object will be deallocated just before the new one is initiated. This behaviour is not consistent with Swift memory retain system, State apparently is masking a retain inside its implementation, and no documentation appears to show this problem I may suppose that the problem may due to the "onChange" modifier that will advertise a view of its old and new values, so state may retain the old class until the onChange is fired, but it should be smarter then the current behaviour Any suggestions for a workaround? radar filed as FB13614543 You can reproduce using the following code class MyClass { init() { print("Allocate") } deinit { print("Deallocate") } } enum LocalState { case normal case withClass(MyClass) case third } struct ContentView: View { @State var localState: LocalState = .normal @State var oldState: LocalState? var body: some View { switch localState { case .normal: Button("Go To Class") { self.localState = .withClass(MyClass()) } case .withClass: Button("Go To Third") { self.localState = .third } case .third: Button("Go To Normal") { self.localState = .normal } } } } @main struct DemoApp: App { var body: some Scene { WindowGroup { ContentView() } } }
1
0
371
Feb ’24
Exporting localization using xcodebuild with a project containing macros
I've a workspace with multiple packages, and due to the a bug in Xcode I cannot export the app localizations using the Xcode GUI tool, but I need to resort on using a command from terminal xcodebuild -exportLocalizations -localizationPath . -workspace <path_workspace> -sdk iphoneos -exportLanguage en One of my packages contains some macros, and I use them from my code without any problem, the code compile But when I try to export localizations using that command, the build fails due to "compiler plugin not loaded" So I cannot use Xcode normal exporting because Xcode bug, and cannot export by running a command due to the macro problem What should I do? It is very discouraging this situation, do you have any suggestion? I've found a similar problem
2
0
685
Mar ’24
Export localization not working when using packages due to unnecessary macOS compile
Hi This issue is present both in previous, current, and beta versions of Xcode When a project has localization in packages, Xcode FAILS to export localization The reason is that when trying to export in this configuration, the compiler will try to export using macOS sdk, but if the package support only iOS of course will not find symbols for frameworks and functions that are scoped only for iOS This behaviour is not changed when the platforms for the package includes ".macOS("99") has I've found as a suggestion online The only way to perform this operation is to run, from CLI the following command xcodebuild -exportLocalizations -localizationPath . -sdk iphoneos -project TranslateTest.xcodeproj -exportLanguage en The problem is that this command will not work when one of the packages contains a macro. The following error will return in CLI if the macro is used (if the package is only imported no error appears) error: external macro implementation type 'MyMacroMacros.StringifyMacro' could not be found for macro 'stringify' I've found online some suggestions from apple folks that says to replace -sdk iphoneos with -destination 'platform=iOS,name=Any iOS Device’ in case your project contains a macro, but this changes nothing in the final result, the export will fail I'm providing a zip for apple in the radar (cannot upload zip here) that contains 3 example project for the 3 cases: A project without any packages that can extract its strings with any mode A project with a package that can only extract its strings only by CLI A project with multiple packages, one of which has a macro, and it can never extract its string This problem affects any possibility to have a modularised application with localisations, macros, and packages. Feedback FB13902424
1
0
512
Jun ’24
Working correctly with actor annotated class
Hi, I have a complex structure of classes, and I'm trying to migrate to swift6 For this classes I've a facade that creates the classes for me without disclosing their internals, only conforming to a known protocol I think I've hit a hard wall in my knowledge of how the actors can exchange data between themselves. I've created a small piece of code that can trigger the error I've hit import SwiftUI import Observation @globalActor actor MyActor { static let shared: some Actor = MyActor() init() { } } @MyActor protocol ProtocolMyActor { var value: String { get } func set(value: String) } @MyActor func make(value: String) -> ProtocolMyActor { return ImplementationMyActor(value: value) } class ImplementationMyActor: ProtocolMyActor { private(set) var value: String init(value: String) { self.value = value } func set(value: String) { self.value = value } } @MainActor @Observable class ViewObserver { let implementation: ProtocolMyActor var value: String init() async { let implementation = await make(value: "Ciao") self.implementation = implementation self.value = await implementation.value } func set(value: String) { Task { await implementation.set(value: value) self.value = value } } } struct MyObservedView: View { @State var model: ViewObserver? var body: some View { if let model { Button("Loaded \(model.value)") { model.set(value: ["A", "B", "C"].randomElement()!) } } else { Text("Loading") .task { self.model = await ViewObserver() } } } } The error Non-sendable type 'any ProtocolMyActor' passed in implicitly asynchronous call to global actor 'MyActor'-isolated property 'value' cannot cross actor boundary Occurs in the init on the line "self.value = await implementation.value" I don't know which concurrency error happens... Yes the init is in the MainActor , but the ProtocolMyActor data can only be accessed in a MyActor queue, so no data races can happen... and each access in my ImplementationMyActor uses await, so I'm not reading or writing the object from a different actor, I just pass sendable values as parameter to a function of the object.. can anybody help me understand better this piece of concurrency problem? Thanks
1
0
182
1w