Swift: Struct vs Class vs Actor, Value vs Reference Types, Stack vs Heap | Swift Concurrency #8

แชร์
ฝัง
  • เผยแพร่เมื่อ 30 ก.ย. 2024
  • Quite possibly the MOST important video on my entire channel. In this installation, we will take an extremely deep-dive into the Swift language. We are covering these topics primarily because we will begin to use Actors for the remainder of this playlist. However, the knowledge in this video goes far beyond Swift Concurrency. This are some of the most complex topics in Swift and I've received a ton of requests to cover the different between these data types. It goes without saying that these are extremely important topics for any Swift developer to know!
    Topics include:
    1) Structs vs Classes vs Actors
    2) Value vs Reference Types
    3) Stack vs Heap memory
    4) Automatic Reference Counting (ARC) in Swift
    5) Weak vs Strong References
    Links:
    - blog.onewayfir...
    - stackoverflow....
    - / swift-basics-struct-vs...
    - stackoverflow....
    - stackoverflow....
    - stackoverflow....
    - www.backblaze....
    - / automatic-reference-co...
    Next video: • How to use Actors and ...
    Previous video: • How to use Continuatio...
    If you are enjoying this FREE playlist, please consider supporting the channel: www.buymeacoff...
    🤙 WELCOME BACK 🤙
    WEBSITE: www.swiftful-t...
    DISCORD: / discord
    GITHUB: github.com/Swi...
    SAY THANKS: www.buymeacoff...

ความคิดเห็น • 224

  • @BillySangster
    @BillySangster 2 ปีที่แล้ว +44

    Definitely one of the best and most important videos on your channel, Nick.
    I've learned most of these things over the years, but it's been sporadic and I found that I'd forgotten a lot of the background to each topic along the way and ended up with a patchy understanding, to say the least.
    It's great to finally have one place where all this information is presented in a logical manner, seeing how each topic relates to the other and ending up with a complete picture of the whole subject.
    Lengthy but invaluable, Sir.
    Thanks for making this - I, for one appreciate it greatly. Well done.

    • @vimak
      @vimak 2 ปีที่แล้ว +2

      Can't agree more 🙌

  • @ryanchen5655
    @ryanchen5655 2 ปีที่แล้ว +25

    The best video I've seen explaining this topic so clearly and in a structured way, thank you

  • @Litebrite_
    @Litebrite_ ปีที่แล้ว +30

    You have an incredible talent for explaining complex topics clearly, in an order that makes complete sense. Thank you so much for making these videos!

  • @lincolndickerson1293
    @lincolndickerson1293 2 ปีที่แล้ว +15

    At the end, this is a work of art! Everyone who works in Swift should see this playlist and understand it. The final example was so well presented. You are amazing. Looking forward to seeing your integration of the actor data service into this foundation. Thank you!

  • @hao-bz
    @hao-bz 3 หลายเดือนก่อน +4

    so far the best iOS and Swift / SwiftUI related channel!!!!

  • @merlingrim2843
    @merlingrim2843 2 ปีที่แล้ว +2

    So the reference (pointer) is stored on the stack, but the data that the reference points to is located on the heap.

  • @TimoBrinkmann
    @TimoBrinkmann ปีที่แล้ว +1

    Great video and explanations, but one remark 27:40 is in my opinion a bit misleading. Its true that when you assign a struct to another struct that you get a new instance. But when you change a value of an attribute inside the struct you will not get a new whole instance of a struct. This can be checked easily by printing the (stack) pointer of the struct with print(String(format: "%p", Int(bitPattern: UnsafeRawPointer(&objectB)))). Changing a value will not change the pointer to the struct and also not the pointer of the other attributes.

  • @alexvaiman4966
    @alexvaiman4966 7 หลายเดือนก่อน +2

    Contrary to what has been said, passing by reference can be faster than passing by value, especially when working with big objects, as allocating memory and copying can be expensive operations. Immutable objects, by definition, are thread-safe, making immutable structs an efficient way to pass objects in a multi-threaded environment, as immutable objects are thread-safe by definition.
    It's important to note that structs in Swift are not always stored on the stack. While smaller struct instances are typically allocated on the stack due to its efficiency and reduced overhead, larger struct instances may exceed the stack's memory capacity. In such cases, the compiler allocates the struct instance on the heap instead. Stack memory is limited, and attempting to store large structs on the stack can lead to stack overflow errors. Therefore, while smaller struct instances are commonly stack-allocated, larger ones are allocated on the heap to ensure memory safety and prevent runtime issues.
    Generally, when dealing with a large dataset where only a small portion needs frequent changes, using a class instead of a struct is often more efficient.

  • @keithweiss229
    @keithweiss229 2 ปีที่แล้ว +4

    You are explaining several important topics to help understand actors. I think a point of clarification could help draw a distinction between an Actor and a Class. As you pointed out, duplicate pointers to the same object, in the heap, on separate threads, may access the same attributes at the same time. Your talk about threads and the heap help illustrate that nicely. But you used the word synchronized in your explanation. I would rephrase that to be shared mutability. Classes provide a mechanism for shared mutability between multiple instances of the same object. That is necessary as we have seen, but it does not do so synchronously. That is the distinction and the role of an actor. The actor also shares mutability, but it ensures that changes are completed serially and not concurrently (potentially, simultaneously.) Therefore, I would state that actors perform synchronized updates of shared attributes and classes do not guarantee synchronized updates. Classes can produce race conditions and actors cannot. Great job tackling these necessary and difficult topics. Thank you for your content!

    • @saurabhd7990
      @saurabhd7990 ปีที่แล้ว

      Thanks for explaining. I did think of this when Nick mentioned synchronized. This video is one of the greatest videos I have seen on Swift.

  • @vimak
    @vimak 2 ปีที่แล้ว +6

    You have a talent for explaining super complex topics and putting them in a simple and logical way. It literally and finally clicked in my head. Bravo 👏 🙌 🙌 🙌

  • @doctorstrangelove798
    @doctorstrangelove798 ปีที่แล้ว +3

    excellent - finally a complete explanation as to how memory and program constructs are related and why. Big help.

  • @absar66
    @absar66 2 ปีที่แล้ว +4

    This tutorial is a Masterpiece 👌 for both beginners and experienced programmers coz "basics" cannot be ignored or relegated as unimportant.
    I have a hunch that Nick would be contacted soon by Ray Wenderlich to produce Tutorial Videos for them or maybe they buy his entire Playlists (who knows some work is already going on behind-the-scenes 😉). Anyway , many thanks Nick for your time and efforts to create such quality tutorials. Wish you the best..

  • @SiamakAshrafi
    @SiamakAshrafi 2 ปีที่แล้ว +1

    References are more memory performant but leads to memory ownership issues. Always try to use Struct as that will not have ownership issues ...
    Also the (call) Stack is fixed at compile time and does not grow as the application runs. Heap is allocated as the program runs ...

    • @w0mblemania
      @w0mblemania 2 ปีที่แล้ว

      You will need to mix and match value types with references in all Swift/Cocoa/SwiftUI programming.
      Yes, structs are the go-to data type for value type and functional programming.
      But there are many situations where reference types are desirable.
      Think of SwiftUI: most of the Views are value types, providing great performance.
      But environmental state is most often a Reference type.

  • @collocheru
    @collocheru 2 ปีที่แล้ว +3

    Just logged into my TH-cam to say thanks for such an amazing explanation! One of the best especially the viewModel and inits part

  • @namankothari8390
    @namankothari8390 หลายเดือนก่อน +1

    I had seen multiple videos on this topic and still remained confused, I have to say that the way you explain everything in this video is just gold knowledge and so good, will never be able to forget these concepts, Thank you!

  • @MarcoDonati
    @MarcoDonati 2 ปีที่แล้ว +1

    await print("ObjectA: ", objectA.title)
    OR
    print("ObjectA: ", await objectA.title)
    ?
    That's the question!
    :-)
    I'd prefer the second since the await keyword is nearer to the actor

  • @lincolndickerson1293
    @lincolndickerson1293 2 ปีที่แล้ว +1

    Paused at 47 minutes. A simplistic analogy is to think of a classroom. Reference types are like the blackboard when something changes everyone sees it. Value types are like tests, (no cheating now) the test paper is handed out and each student has their own copy.

  • @kdtechniquesofficial6153
    @kdtechniquesofficial6153 ปีที่แล้ว +3

    Struct is like copying the same folder and paste it somewhere else with a different name, so if you change one’s content it doesn’t affect the other folder, because both folders have separate contents in it.
    Class is like making a shortcut to an original folder, so you can change the content from any of them, because it changes the content in the original folder reference.
    Nick, please correct me if I’m wrong. ❤

    • @SwiftfulThinking
      @SwiftfulThinking  ปีที่แล้ว +1

      KD is back!!!!!
      Yea you’re correct, but I’d add that the struct folder you can never edit contents inside. If you need to change it, you create another version. Where the class you can go inside and change it 🤙

    • @kdtechniquesofficial6153
      @kdtechniquesofficial6153 ปีที่แล้ว

      @@SwiftfulThinking Yes, That's right. I forgot that it's not editable anymore.

  • @kdtechniquesofficial6153
    @kdtechniquesofficial6153 ปีที่แล้ว +2

    Damn, I understood it to the core in just one video. Thank you Nick. ❤ I ask your brain 🧠 to give you more energy to make videos like this in the long run. 🎉 Hello Nick’s brain, please give Nick’s body more energy and keep him motivated 🤝

  • @andresraigoza2082
    @andresraigoza2082 2 ปีที่แล้ว +3

    What a great master class!!! 👏🏻 This explanation couldn't be better. Thank you so much for all the effort that you are putting into this videos. You deserve the best 👍🏻

  • @alexvaiman4966
    @alexvaiman4966 7 หลายเดือนก่อน +1

    Thank you ever so much for this channel. Your explanations are truly awesome-some of the best I've seen, whether free or paid. Your dedication to clarity and quality is evident and deeply appreciated. Keep up the fantastic work!

  • @istuart0
    @istuart0 หลายเดือนก่อน

    Instead of printing the literal string inside the functions such as print("structTest1") use print("\(#function)") and Swift will print the function name for you. Also you simply need to copy and paste this line to the top of all your functions where necessary.

  • @iOSTechie
    @iOSTechie 2 ปีที่แล้ว +2

    You have clarified everything so well and also revised many things. I love the way you go in deep of every single topic.Always looking forward to your videos.

  • @7themryze638
    @7themryze638 5 หลายเดือนก่อน

    Really impressive! Thanks alot for your effort of making this content! Your GOAT

  • @tomblah
    @tomblah 4 หลายเดือนก่อน

    48:49 small world, I worked wth Khanh back in 2022, incredibly smart guy

  • @zak_ray
    @zak_ray 26 วันที่ผ่านมา

    These videos are wonderful and really helped me understand concurrency. I would recommend getting a lav mic such as a Rode Wireless Go or the DJI version for clearer audio!

  • @echolumaque2130
    @echolumaque2130 หลายเดือนก่อน

    What a really great video! I just now learned what actor "truly" means because of you. I read tons of articles and forums but can't really grasp what it does mean.

  • @asigivati1382
    @asigivati1382 3 หลายเดือนก่อน

    i understand that structs are much faster than classes, but swiftUI with all it's structs views, is in the end just a layer above UIKit eventually. all the views are converted to UIViewController, UIVIew, UITextField etc..
    so how is it faster than using UIKit directly?

  • @shinitiomit1095
    @shinitiomit1095 หลายเดือนก่อน

    Thanks for this video! I'm grateful that you took the time to explain the characteristics of structs and classes and the new actors in detail through various examples, which made it very easy to understand. I'm also glad that the relationship with weak self was very easy to understand. The videos and reference books that teach you teach you the specific parts, but you teach with an eye on the whole picture, so I'm glad that it's very easy to understand why it happened. I look forward to your continued support.

  • @thinktech4389
    @thinktech4389 หลายเดือนก่อน

    1:31:00 Question here: In case of dependency injection we will initialize viewmodel in struct's init() so will that created a new class every time when struct reinitializes??

  • @julianm080808
    @julianm080808 5 หลายเดือนก่อน

    Hey nicks, I really appreciate it for this class, for it was really tough to understand, but I will try to remember everything you explained throughout the whole video.

  • @danielcrompton7818
    @danielcrompton7818 2 หลายเดือนก่อน

    37:59 with the coffee explanation for STRUCTS You could also pass the strict instance as inout to make it behave like a class

  • @tejaspatelia8179
    @tejaspatelia8179 5 หลายเดือนก่อน

    What a wonderful and informative video!! Nick, you have justified the time spend on this video. 👏

  • @sunilprajapati5708
    @sunilprajapati5708 3 หลายเดือนก่อน

    Awesome video! The way you have explained its so easy to understand the basic concepts. I have never seen such an amazing video on this topic. Thank you so much putting all these concepts together.

  • @TinaFazeliniaki
    @TinaFazeliniaki 6 หลายเดือนก่อน

    By far THE BEST Video on this topic that I've come across!
    Thanks a lot for this great video and all your effort!

  • @hashcat5721
    @hashcat5721 2 ปีที่แล้ว

    func address(fo object: UnsafeRawPointer) -> String {
    let addr = Int(bitPattern: object)
    return String(format: "%p", addr)
    }

  • @leonardogoncalves5896
    @leonardogoncalves5896 ปีที่แล้ว

    Amazing content! Thanks for sharing for free 🤩. Thanks from Brazil!!

  • @nontan5591
    @nontan5591 14 วันที่ผ่านมา

    Swift 6では、並列処理が多く登場しそうなので、今まで避けていた並列処理を学んでいるところです。スタックやヒープは初めて知りました。長い動画ありがとうございます。

  • @xybnedasdd2930
    @xybnedasdd2930 ปีที่แล้ว +1

    Great video. One minor suggestion: a setter which returns a new copy should usually be named differently, depending on convention. For example, 'updatingName` or 'withUdpatedName`, which makes it more clear it's returning and not just mutating. Similarly as we have .sort for in-place sort and .sorted for a new list without mutating the original.

  • @Amey57
    @Amey57 8 วันที่ผ่านมา

    Just one thing I would like to say
    Swiftful Thinking = Clarity.
    Thank you very much for this video. This helped me a lot and clarified all my doubts. You are the best and again - Thanks for teaching this!!!!!!

  • @nnyabwana
    @nnyabwana 3 หลายเดือนก่อน

    I am so grateful! this is a super helpful video and the clarity is breathtaking.

  • @betterchrisb3432
    @betterchrisb3432 ปีที่แล้ว

    Great video. However, when you mentioned the class being 'synchronized' in the summary at 1:15:58, there is ambiguity. In the computer field, including many other programming languages, 'synchronized' typically means locking, similar to 'Thread safe' you mentioned afterward. Here, you are trying to use 'synchronized' to express the data sync process between temporary storage and memory or other buffer storage used by the CPU. I believe that using 'synchronization' to describe this process is imprecise. Please inform me if you hold any different opinions.

  • @manishparihar3361
    @manishparihar3361 ปีที่แล้ว

    Well Expained everything , Your way of teaching is super simple to understand . Hatsoff for your hard work for the tutorial 😊

  • @alfonsomunoz4963
    @alfonsomunoz4963 ปีที่แล้ว

    Hi, I like the video as a general overview; good job! I have only one comment about something I see as an imprecise explanation about why "View Init" is printed several times in the 1:29:29. It is not about changing the isActive property of the StructClassActorBootcamp. The reason is only related to the StructClassActorBootcampHomeView. SwiftUI knows the dependencies of its body property, so when this outer isActive property changes, SwiftUI recreates the body property, which implies that it recreates the StructClassActorBootcamp view. That's the reason.

  • @ВалентинЗубков-ч2й
    @ВалентинЗубков-ч2й 4 หลายเดือนก่อน

    It’s crazy but I got time synced while watching this video. I look at my watch and it was 9:54 exactly when it was 9:54 at your menu bar.

  • @Aamirrz-m2x
    @Aamirrz-m2x หลายเดือนก่อน

    super crystal clear. thanks man ur way of teaching is awesome 👌🏻

  • @Reallymellie
    @Reallymellie ปีที่แล้ว

    Hey Nick, Thank you!. Just one question. Why do we use structs for models within our app? Thank you!

  • @tainguyen-ng3yl
    @tainguyen-ng3yl ปีที่แล้ว

    Hi Nick, Could you please make a video to talk about VIPER architecture 🙏and which one is better in large apps?

  • @bobbynwm
    @bobbynwm ปีที่แล้ว

    Thanks a lot mate! Indeed you did clarify simply how MVVM should be used and at the end all the pieces came together. I can't say I am mastering them all, but at least I understood now how to refactor my MVVM so far, and where shall I place the ObservableObjects and Structs and Views, as I was a bit confused between ViewModels, Models and Classes with more generic use overall in the app ( Actors ) not per View. Cheers!

  • @hansonchang
    @hansonchang 7 หลายเดือนก่อน

    Thanks for your sharing! It is absolutely a great video. But I wanna know that how does the view models manage the enviroment variables or environmentobject or is it the best practice to store the enviroment variables in view models?

  • @ShowMeLova
    @ShowMeLova 6 หลายเดือนก่อน

    Nick, thank you! Thank you very much for enlightening us.

  • @MaxTymchii
    @MaxTymchii ปีที่แล้ว

    Really good video. Thx for that. One thing that I think can improve it, when you print logs, also print address of objects and struts to visualise a difference and changes.

  • @moalsamman
    @moalsamman 2 ปีที่แล้ว

    Great video as always! ... It would be worthy if you mentioned about struct COW "Copy on write" ;)

  • @Harm0Niz
    @Harm0Niz 11 หลายเดือนก่อน

    Thank you for this wonderful video. I assume that the fact that the view structures are recreated with each mutation makes it interesting, aside from code refactoring and readability. Breaking down a large view into multiple child structures/views to partially recreate only the view blocks.

  • @danielcrompton7818
    @danielcrompton7818 5 หลายเดือนก่อน

    In about 30 seconds:
    Stacks are immutable meaning any changes made to them need the stack to be rebuilt therefore they have to be saved to a variable. Stacks are saves to the stack in memory which is faster accessed

  • @sergflop
    @sergflop 8 หลายเดือนก่อน

    Passing values is not faster in general. It depends on size of objects. If you want to pass a really huge objects passing by reference will be much faster

  • @dugrut1325
    @dugrut1325 ปีที่แล้ว

    Print statements work great but on a practical side the views will not display the changes when you expect, WHY
    I changed the class with @Published var title: String
    the func did nothing to change the title value [which is very confusing] in the view unless I directly; cl.title = "this title is changed'. then cl.title displayed the new value in the view.

  • @motionblurgamer
    @motionblurgamer 11 หลายเดือนก่อน

    Thanks! I feel like I finally understand Stack vs. Heap.

  • @luissda1
    @luissda1 ปีที่แล้ว

    this videos is amazing, I can undestand absolutely all , thanks for your content

  • @raymondcordero9718
    @raymondcordero9718 หลายเดือนก่อน

    Amazing video. Did awesome explaining this

  • @alx1931
    @alx1931 5 หลายเดือนก่อน

    Clear as mud. No but really this helped a lot. I will probably rewatch in a month or so and it will make even more sense.

  • @Awesome奥深
    @Awesome奥深 2 ปีที่แล้ว

    Long video but need to watch carefully. Thanks.

  • @alxkub
    @alxkub ปีที่แล้ว

    You say several times that passing a value type as a parameter is more efficient than passing a reference type instance. But is it true? Passing to a function just a tiny address of a class instance should be a lot more efficient than copying all the data of a structure and putting it into the stack (stack size is limited and copying is expensive!). Without internal optimizations like copy on write and storing internally some (large) structs data in the heap performance of operations with large structs would be a disaster.

  • @alisultanabdullah6924
    @alisultanabdullah6924 2 ปีที่แล้ว

    Great explanation, but what about VIPER architecture?

  • @HumbleHustle101
    @HumbleHustle101 10 หลายเดือนก่อน

    Nice video, I think closures also qualifies as reference type.

  • @suryabhan1000
    @suryabhan1000 ปีที่แล้ว

    a very details explanation, Thanks.. I own you beer

  • @spradohak
    @spradohak 10 หลายเดือนก่อน

    One of the best videos about this topic, Thank you so much Nick 👍🏼

  • @Денис-ж3ф5р
    @Денис-ж3ф5р ปีที่แล้ว

    Would you mind telling us how to work with the open source of Swift language?

  • @vojtechkalivoda8455
    @vojtechkalivoda8455 ปีที่แล้ว +1

    Long tutorial is the way to go with these complicated topics!!! I literally needed to hear the difference between class and structs hundred times to be able to start understanding it 🙂 Thank you for this video Nick!!

  • @leilaleila7802
    @leilaleila7802 ปีที่แล้ว

    you explained everything very well, thanks ❤

  • @MichaelHorta-d1z
    @MichaelHorta-d1z ปีที่แล้ว

    Fantastic! Thank you this incredible video

  • @gregas3068
    @gregas3068 ปีที่แล้ว

    Really nice explanation. Learning a lot here. Keep pushing.

  • @tainguyen-ng3yl
    @tainguyen-ng3yl ปีที่แล้ว

    Shout out to Khanh Nguyen, from Vietnam with love

  • @kumarutsav6653
    @kumarutsav6653 ปีที่แล้ว

    Awesome video again. You are the best teacher and yes I owe you coffee.

  • @protodimbo
    @protodimbo 2 ปีที่แล้ว

    NIck, this video is great! Thank you so much!

  • @cinquain0
    @cinquain0 2 ปีที่แล้ว +1

    The Stack vs Heap question is a very common one in iOS interviews.

  • @Pepe_the_raver
    @Pepe_the_raver 2 หลายเดือนก่อน

    Not enough Mastercards to pay this super valuable lesson

  • @eliasayele1102
    @eliasayele1102 ปีที่แล้ว

    Thank you very much, I love your teaching style and it help me a lot.

  • @EddiKh
    @EddiKh ปีที่แล้ว +1

    Wow really appreciate you taking the time to dive deeper into this topic, Nick! As a self taught programmer, I struggled myself with those topics and actually having one of the best and practical teaching channels cover it is a true blessing. Thank you!

  • @lumi6394
    @lumi6394 ปีที่แล้ว

    Another masterpiece! Thank you!

  • @tambui3603
    @tambui3603 8 หลายเดือนก่อน

    Another great video, thank you so much !

  • @Krafcik226
    @Krafcik226 หลายเดือนก่อน

    One of the best videos on this platform and I am not kidding.

  • @emdutt4012
    @emdutt4012 ปีที่แล้ว +1

    closures is also a reference type . thank u nick again indeed, it's a long video but it is an interesting to learn.

  • @pakaponwiwat2405
    @pakaponwiwat2405 11 หลายเดือนก่อน

    It is crystal clear! Thank you very much !

  • @fre.helfer
    @fre.helfer ปีที่แล้ว

    You are the best! Thank you, again, Nick!

  • @nickpavlov4012
    @nickpavlov4012 ปีที่แล้ว

    Incredible video, Thank you

  • @LeaTamola
    @LeaTamola ปีที่แล้ว

    This video is just amazing and clear 👌🏼

  • @eugenewolf7493
    @eugenewolf7493 2 ปีที่แล้ว

    Came here from the next video. This is waaay too long.

  • @Noneless-bl1tr
    @Noneless-bl1tr ปีที่แล้ว

    Awesome videos, so much learned here, thanks

  • @moon-3002
    @moon-3002 ปีที่แล้ว

    How about combine and async/await? Do we need to add weak self?

  • @Seepho
    @Seepho 2 ปีที่แล้ว

    Thats awesome job! Im finally get it! Thank you so much!

  • @suryakantsharma6761
    @suryakantsharma6761 ปีที่แล้ว

    Even new learning for Senior Dev. Best video I even seen in this detail 💌

  • @KarthikeyaReddyAkepati
    @KarthikeyaReddyAkepati ปีที่แล้ว

    Thanks Nick This Video Helps Me A Lot

  • @vadimshinkarenko2069
    @vadimshinkarenko2069 ปีที่แล้ว

    Thank you so much! Great video 🔥

  • @ionpavelescu2125
    @ionpavelescu2125 ปีที่แล้ว

    Wow . Why did I understand it sooooo easy? thank you .

  • @leavingtheapartment
    @leavingtheapartment 7 วันที่ผ่านมา

    This video is soooo good! Thank you very much for sharing this knowledge with us

  • @quarrlk
    @quarrlk 4 หลายเดือนก่อน

    So well explained! I can't stress enough how much your videos have helped me jumpstarting my iOS development. Being able to explain these concepts so well is another level of understanding. Thank you for your kindness of providing such quality contents for free! Wish you all the best

  • @brotskyCode
    @brotskyCode 2 ปีที่แล้ว

    love you man. You make me happy in Ukraine🇺🇦

  • @NavdeepSingh-ut8md
    @NavdeepSingh-ut8md ปีที่แล้ว

    really very helpful for a beginner in iOS

  • @mykhailotseitlin6979
    @mykhailotseitlin6979 ปีที่แล้ว

    Thank you very much for your video! 😊