Just spent half of the day to find a solution. I hate videos, more prefer articles and it costs me 4 hours. Thanks for sharing this!
@RFIHW21 күн бұрын
I'm still using geometry in background Color to get offset, which is the only way I tested with acceptable frequency.
@rickywitherspoon2861Ай бұрын
I’d love for you to talk about test performance compared to XCTTests.
@DonnyWalsdevАй бұрын
Which performance characteristics do you have in mind? Overall time to run the suite from compilation or just one aspect of it?
@rickywitherspoon2861Ай бұрын
@ run times, yes. When it was first in beta I read about people doing performance tests and it was significantly slower than XCTests.
@DonnyWalsdevАй бұрын
Interesting, I'll definitely see if I can do a comparison video some day; I've mostly been exploring smaller scale test suites so for the time being I don't think I can say anything of use about performance
@user32352Ай бұрын
would love if you included the repo in these videos
@DonnyWalsdevАй бұрын
That's a good suggestion; there often isn't a repo/sample project but making one shouldn't take too long 😁
@compsci-guyАй бұрын
Great description and clarity. 👍
@DonnyWalsdevАй бұрын
Thank you 😁
@andreypopov6166Ай бұрын
Thank you for the great explanation. Another example that Swift concurrency should be used sparingly and designed properly, supplied with comment to explain "what is going on" without the believes that "this is just amazing and compiler will solve everything". By the way: "Doing one thing at a time but not atomically" should be printed on a t-shirt :) I am wondering what if an actor contain just private cache, async getter to read from the cache and sync setter to write to the cahe, will it behave as an atomic storage?
@SkwiggsАй бұрын
What's preventing you from just using the view model factory approach, and make that factory an environment object? Then any view that needs to instantiate another can just refer to factory from its environment
@DonnyWalsdevАй бұрын
Nothing, it’d be just another flavor of passing a factory around
@AvoluaАй бұрын
I think this throws some warning when swift 6 and complete modes enabled. I was hoping for something compatible with swift 6
@DonnyWalsdevАй бұрын
Neither DI approach is incompatible with Swift, what kinds of warnings do you get?
@AvoluaАй бұрын
@@DonnyWalsdev Static property 'current' is not concurrency-safe because it is nonisolated global shared mutable state; this is an error in Swift 6 language mode.
@DonnyWalsdevАй бұрын
@@Avolua ah I see, so that’s entirely unrelated to how you do DI. The compiler is complaining about that property being mutable without any means to ensure data race safety. Making current a let should work, or converting whatever holds that property to an actor might work too. It’s a bit of an annoying error that one because sometimes fixing it will mean you’ll have to move away from static vars (or marking those vars as nonisolated(unsafe))
@EustakioXCАй бұрын
There is something weird with the audio processing
@DonnyWalsdevАй бұрын
Yeah I’m not exactly sure what got messed up in processing. The initial upload I had was completely out of sync. This one’s much better in terms of syncing but there’s still something off and I have no idea what it is exactly 😅
@XaxxusАй бұрын
I definitely prefer the service locator pattern. Sure you can get a crash if you forget a dependency, but that’s something that you should be picking up during development.
@victorriureanАй бұрын
@victorriureanАй бұрын
@aleksandrzinovev429Ай бұрын
You have a talent for explaining complex concepts clearly
@DonnyWalsdevАй бұрын
Thank you!
@1987alejandroivanАй бұрын
You can also set the Swift language level at the package level, if you want to all your module targets to be in a specific Swift version
@1987alejandroivanАй бұрын
Just a quick note: the "block" declaration is not needed if you're just creating the object without doing anything else with it. This would work too: lazy var urlSession = URLSession(configuration: .default, delegate: self, delegateQueue: nil)
@stewartrule2 ай бұрын
You can also just use an array for the path and use an enum for the value type. Then you can use a switch in the navigationDestination, which gives the benefit of having multiple detail views for the same model, and you'll get an error if you try to push an optional or something else that isn't listed in the enum.
@hemantstha41442 ай бұрын
❤
@w0mblemania2 ай бұрын
Thanks for this. Very helpful. I gotta say that Swift has become a nightmare. It was supposed to be a clear, expressive language. Instead, it's become a plaything for comp-sci grads. Feature creep has made it a kitchen sink of a language, which rivals (and indeed surpasses) C++ for complexity and verbosity. It's hard to imagine explaining half of Swift's keywords to a new Swift developer.
@larschristiansen31362 ай бұрын
Thank you for this ray of light into Swift 6 obscurity
@Mirorval2 ай бұрын
Helpfull.
@AcidUser2 ай бұрын
Really good example, thank you! I learned a lot and think more in this new async/await way now instead of thinking in queues 😁
@zbighugh91932 ай бұрын
This doesn't show navigating forwards & backwards to any point in the path. For example: Root -> Dest1 -> Dest2 -> Dest3 -> Dest4 then jump to Dest2 then jump to Root then jump to Dest4, etc.
@DonnyWalsdev2 ай бұрын
With a plain navigation path you wouldn't really be able to achieve that. Luckily, you can also use an array as your navigation path. When doing that, you could easily remove the last 'n' entries to pop back to any place. Going back and then forward again isn't possible because NavigationStack always presents the last item in your path. So if you want to go back, you have to drop the items that came after the place you wanted to go to.
@lyheng78202 ай бұрын
Hi Sir first I would like to thanks u for help some tutorial Video But can I request Video about How to login with Gmail in Firebase ? I can find the the resource
@michaellatta2 ай бұрын
I avoided actors at the beginning because they were repentant in ways that broke my mental model. After watching apple’s concurrency video with the islands several times the phrase that clicked was that the serialization mechanism was tasks. So, rather than doing complex threading models or queuing work to run in the background I just create tasks from the UI and call actor methods for background work. This usage reduces the reentrancy issues as the control flow is in single tasks. If I need to spawn long running background tasks (detached) this will again raise the reentrancy issues.
@MassonLifestyle3 ай бұрын
Do I need this even when my app isn't asking users to put in any of their information ?
@DonnyWalsdev2 ай бұрын
Yes. If your app leverages UserDefaults to store preferences, or if you're interacting with the filesystem you'll need to provide a privacy manifest
@paccini13 ай бұрын
Great explanation and good catch about Actor reentrancy.
@anhhanry71673 ай бұрын
superb 👌👏
@michael_mei3 ай бұрын
Thanks Donny for the clear and detailed explanation. Optionals surely are a very handy and safe feature of Swift.
@AkimboFennec3 ай бұрын
Hey danni. I have a question for you. Let say in iOS 18, new Xcode 16, every view is already annotated with the @MainActor. Furthermore, let’s say I have a certain function, called func sortArray() async. Now, since this functino is inside a view, that is annotated with a main actor, but it is marked as async, it will block the main thread. I tested it in SwiftUI. Inside this sortArray() async, i have var array = Array(repeating: 2, count: 30_000_000); array.sort(). And let’s say that this function is triggered by a certain button press. As soon as i press this button, the UI totally freezes, and does not respond until the array sort operation finishes. However, as soon as i mark this async function as non isolated, then everything works fine, and the UI responds, while another thread is sorting this array. Why does this happen? You said int the video that marking a function as await does not freeze the UI. I don’t understand it conceptually
@DonnyWalsdev3 ай бұрын
Hey! Thanks for your question. So the await itself isn't why your function blocked the main actor. It's because the thing you were awaiting itself runs on the main actor that your UI freezes. That's also why marking the function as nonisolated fixes your problem. Even though you're awaiting the nonisolated function from the main actor, the main actor can do other stuff (like keeping your UI responsive) while it waits for the nonisolated async function to come back. In other words, while the await does not block the main actor, the thing your waiting for might.
@Xaxxus4 ай бұрын
To your last point about the environment. Prior to iOS 17 we had @EnviornmentObject which had bindings With iOS 17, there is a new environment property wrapper that does not take an environment key. I believe it also has bindings. So you can do something like: MyView() .environment(myObservable) And then in your view: @Environment var myObservable: MyObservable This does have the same downside as EnvironmentObject, as in, there is no default value. So your app will crash if you forget to inject the value in.
@ZeroTorySeats4 ай бұрын
I would like to have a sidebar for iOS rather than tabs. Is that possible? They have this in the Substack app, for example: you can slide from the side of the screen to reveal the sidebar, and can also slide it away again.
@DonnyWalsdev4 ай бұрын
Not with the built in navigation components. You'd have to build that from scratch
@DonatB984 ай бұрын
Thanks for the explanation Donny. It's funny, until now i was only using lazy for when i needed to show the user an alert on my controllers, and i was creating them as lazy var alert = someAlert(), with the thought process that those alerts might never show so why bother creating them when the view is shown if they won't be triggered.
@immatiaz4 ай бұрын
Ok but how do you make a view to be presented in full screen mode by using the navigation stack and the path thing ?
@DonnyWalsdev4 ай бұрын
Do you mean as an overlay? Or pushed on the navigation stack except the top bar is hidden? Neither relate to the path to be honest since the path just describes which models are in the stack of presented views. Hiding bars should be possible with the `navigationBarHidden` view modifier. If you're looking for an overlay, you'd use the fullScreenCover view modifier. This can't be captured in a navigation stack's path because navigation stack is just a list of views presented in a navigation stack; not including any overlays that you have presented on top of your NavigationStack
@SHOLINGER4 ай бұрын
❤ The content, keep it up!!
@md.ibrahimhassan25714 ай бұрын
awesome
@bertrandprenat4 ай бұрын
Thank you for the tip!!! Very useful!
@DonnyWalsdev4 ай бұрын
Thanks for watching! :D
@chanuhack4 ай бұрын
Great functionality, horrible naming. I mean @Entry? :(
@muncho4044 ай бұрын
Wow that's neat
@bobgodwinx4 ай бұрын
Great content here. Thanks for sharing. this trick actually applies to a lot of problems.
@gerardgomez59875 ай бұрын
Is there currently a way in iOS 18 to hide TabSection headers in the TabBar view while keeping them visible in the Sidebar view and, importantly, while still showing the tabs themselves in the TabBar.
@gerardgomez59875 ай бұрын
Never mind, I was able to use isTabBarShowingSections Environment Value. although I would much appreciate a tabSectionHeaderVisibility(.sidebar) modifier instead of using a if statement.
@gerardgomez59875 ай бұрын
That did not work
@ivanmatkovic5 ай бұрын
When viewModel is @Observable, you dont need @State in the View. Great video btw
@DonnyWalsdev5 ай бұрын
You do if that view creates/owns the state. Otherwise every time a new struct instance is made a new instance of the Observable is made.
@marksiracusano99315 ай бұрын
How would you handle the path if you have a tabView with different navigations for each tab? I guess every tab would have a a NavigationStack with their own path, right? If so, what if you need new paths further down those flows? Like a child coordinator situation? Should you nest NavigationStacks?
@PtolemysEye5 ай бұрын
Each tab view should have it's own navigation stack
@DonnyWalsdev5 ай бұрын
You’d have a dedicated path for each tab. Not sure what you mean by needing new paths later on. You shouldn’t nest navigation stacks, flows later on should use the same path that the stack that contains them would use. Of course, sheets can have their own navigation stacks if needed; you just shouldn’t nest them
@hami17055 ай бұрын
post more videos like this
@indomitabletr18345 ай бұрын
how would it be if I was in iOS 14
@DonnyWalsdev5 ай бұрын
A lot less convenient!
@indp87525 ай бұрын
When you add an Exercise to path, how does it know that it has to show the Exercise view ?
@DonnyWalsdev5 ай бұрын
Through the navigationDestination view modifier that I applied to one of the parent views
@enriqueduran65485 ай бұрын
EXCELENT
@indiekiduk5 ай бұрын
It’s strange that navigationDestination doesn’t go through the PreferenceKey’s reducer like navigationTitle does which is how it can be overridden without a warning. Maybe was implemented by a different dev at Apple.
@MarcosSuarezAyala5 ай бұрын
Thanks for the video, I have a question with the implementation of navigation with the NavigationStack. How do I control the navigation? In the case that I only want to navigate when I have received an OK response from the API, if the response has given me an error, I do not perform the navigation and show a pop up. How is this implemented with the NavigationStack?
@fitzventure5 ай бұрын
This is the one use case nobody covers in any tutorials. I know because I just struggled to figure it out. Say you have a view that displays on initial open of the app, it checks if the user is logged in and navigates to a login page if not. How do you handle that? I turns out , you use a single navigation destination modifier on the root nav stack and a case statement inside that destination checks the path (which you can use and enum for). Think of the navigation destination as a controller for navigation. This would make a great video because it's so common but there's nothing out there explaining it. Hope that helps.
@MarcosSuarezAyala5 ай бұрын
@@fitzventure Thanks. Now I'm using HomeRoute with enums and special func loadData, I don't like this approach but it's the only thing I can think of for now. @MainActor func loadData(for route: MoviesRouter) async throws { switch route { case .detail(let movie): do { try await Task.sleep(nanoseconds: 5_000_000_000) throw(NSError(domain: "error", code: 1)) // To test error moviesRouter.append(.detail(movie)) } catch { throw(error) } } } And call it in button inside the view Button("Go to a random Movie") { guard !viewModel.list.isEmpty, let randomMovie = viewModel.list.randomElement() else { return } showLoader.toggle() Task { do { try await homeRouter.loadData(for: .detail(randomMovie)) showLoader = false } catch { showLoader = false showError = true } } } .buttonStyle(.borderedProminent)