Animating SF Symbols on iOS 18
11:03
What are Optionals in Swift?
19:19
Lazy vars in Swift explained
9:21
Defer in Swift explained
3:15
6 ай бұрын
Using Closures as Dependencies
15:18
What's new in Swift 5.10
5:09
8 ай бұрын
Пікірлер
@ДимаМейду
@ДимаМейду 6 күн бұрын
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!
@RFIHW
@RFIHW 21 күн бұрын
I'm still using geometry in background Color to get offset, which is the only way I tested with acceptable frequency.
@rickywitherspoon2861
@rickywitherspoon2861 Ай бұрын
I’d love for you to talk about test performance compared to XCTTests.
@DonnyWalsdev
@DonnyWalsdev Ай бұрын
Which performance characteristics do you have in mind? Overall time to run the suite from compilation or just one aspect of it?
@rickywitherspoon2861
@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
@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
@user32352 Ай бұрын
would love if you included the repo in these videos
@DonnyWalsdev
@DonnyWalsdev Ай бұрын
That's a good suggestion; there often isn't a repo/sample project but making one shouldn't take too long 😁
@compsci-guy
@compsci-guy Ай бұрын
Great description and clarity. 👍
@DonnyWalsdev
@DonnyWalsdev Ай бұрын
Thank you 😁
@andreypopov6166
@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
@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
@DonnyWalsdev Ай бұрын
Nothing, it’d be just another flavor of passing a factory around
@Avolua
@Avolua Ай бұрын
I think this throws some warning when swift 6 and complete modes enabled. I was hoping for something compatible with swift 6
@DonnyWalsdev
@DonnyWalsdev Ай бұрын
Neither DI approach is incompatible with Swift, what kinds of warnings do you get?
@Avolua
@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
@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
@EustakioXC Ай бұрын
There is something weird with the audio processing
@DonnyWalsdev
@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
@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 Ай бұрын
@victorriurean
@victorriurean Ай бұрын
@aleksandrzinovev429
@aleksandrzinovev429 Ай бұрын
You have a talent for explaining complex concepts clearly
@DonnyWalsdev
@DonnyWalsdev Ай бұрын
Thank you!
@1987alejandroivan
@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
@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)
@stewartrule
@stewartrule 2 ай бұрын
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.
@hemantstha4144
@hemantstha4144 2 ай бұрын
@w0mblemania
@w0mblemania 2 ай бұрын
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.
@larschristiansen3136
@larschristiansen3136 2 ай бұрын
Thank you for this ray of light into Swift 6 obscurity
@Mirorval
@Mirorval 2 ай бұрын
Helpfull.
@AcidUser
@AcidUser 2 ай бұрын
Really good example, thank you! I learned a lot and think more in this new async/await way now instead of thinking in queues 😁
@zbighugh9193
@zbighugh9193 2 ай бұрын
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.
@DonnyWalsdev
@DonnyWalsdev 2 ай бұрын
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.
@lyheng7820
@lyheng7820 2 ай бұрын
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
@michaellatta
@michaellatta 2 ай бұрын
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.
@MassonLifestyle
@MassonLifestyle 3 ай бұрын
Do I need this even when my app isn't asking users to put in any of their information ?
@DonnyWalsdev
@DonnyWalsdev 2 ай бұрын
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
@paccini1
@paccini1 3 ай бұрын
Great explanation and good catch about Actor reentrancy.
@anhhanry7167
@anhhanry7167 3 ай бұрын
superb 👌👏
@michael_mei
@michael_mei 3 ай бұрын
Thanks Donny for the clear and detailed explanation. Optionals surely are a very handy and safe feature of Swift.
@AkimboFennec
@AkimboFennec 3 ай бұрын
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
@DonnyWalsdev
@DonnyWalsdev 3 ай бұрын
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.
@Xaxxus
@Xaxxus 4 ай бұрын
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.
@ZeroTorySeats
@ZeroTorySeats 4 ай бұрын
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.
@DonnyWalsdev
@DonnyWalsdev 4 ай бұрын
Not with the built in navigation components. You'd have to build that from scratch
@DonatB98
@DonatB98 4 ай бұрын
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.
@immatiaz
@immatiaz 4 ай бұрын
Ok but how do you make a view to be presented in full screen mode by using the navigation stack and the path thing ?
@DonnyWalsdev
@DonnyWalsdev 4 ай бұрын
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
@SHOLINGER
@SHOLINGER 4 ай бұрын
❤ The content, keep it up!!
@md.ibrahimhassan2571
@md.ibrahimhassan2571 4 ай бұрын
awesome
@bertrandprenat
@bertrandprenat 4 ай бұрын
Thank you for the tip!!! Very useful!
@DonnyWalsdev
@DonnyWalsdev 4 ай бұрын
Thanks for watching! :D
@chanuhack
@chanuhack 4 ай бұрын
Great functionality, horrible naming. I mean @Entry? :(
@muncho404
@muncho404 4 ай бұрын
Wow that's neat
@bobgodwinx
@bobgodwinx 4 ай бұрын
Great content here. Thanks for sharing. this trick actually applies to a lot of problems.
@gerardgomez5987
@gerardgomez5987 5 ай бұрын
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.
@gerardgomez5987
@gerardgomez5987 5 ай бұрын
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.
@gerardgomez5987
@gerardgomez5987 5 ай бұрын
That did not work
@ivanmatkovic
@ivanmatkovic 5 ай бұрын
When viewModel is @Observable, you dont need @State in the View. Great video btw
@DonnyWalsdev
@DonnyWalsdev 5 ай бұрын
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.
@marksiracusano9931
@marksiracusano9931 5 ай бұрын
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?
@PtolemysEye
@PtolemysEye 5 ай бұрын
Each tab view should have it's own navigation stack
@DonnyWalsdev
@DonnyWalsdev 5 ай бұрын
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
@hami1705
@hami1705 5 ай бұрын
post more videos like this
@indomitabletr1834
@indomitabletr1834 5 ай бұрын
how would it be if I was in iOS 14
@DonnyWalsdev
@DonnyWalsdev 5 ай бұрын
A lot less convenient!
@indp8752
@indp8752 5 ай бұрын
When you add an Exercise to path, how does it know that it has to show the Exercise view ?
@DonnyWalsdev
@DonnyWalsdev 5 ай бұрын
Through the navigationDestination view modifier that I applied to one of the parent views
@enriqueduran6548
@enriqueduran6548 5 ай бұрын
EXCELENT
@indiekiduk
@indiekiduk 5 ай бұрын
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.
@MarcosSuarezAyala
@MarcosSuarezAyala 5 ай бұрын
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?
@fitzventure
@fitzventure 5 ай бұрын
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.
@MarcosSuarezAyala
@MarcosSuarezAyala 5 ай бұрын
@@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)