Dependency Container in iOS Swift + Property Wrappers

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hi guys welcome to another is tutorial from Conference Labs in this tutorial we will be learning the concept of dependency container apart from that we will also be using property levels in this tutorial I have a separate lecture on property wrapper I would recommend you all to go through that lecture as well because property wrappers is a super useful concept we will be implementing this dependency container as a framework so that we can reuse it wherever we want if we talk about the concept of dependency container the first question that should come to your mind is what is dependency if you already know what is dependency then it's good but if you don't know let me tell you if you are already developing iOS applications you are already using this concept it's just that you don't know the standard names used among developers let me show you multiple examples of dependencies so here let's talk about the above example the profile class inside profile class we have an initializer which takes an argument of type Account Manager so it's very clear here that if we want to create an instance of profile class then we need to pass it an instance of type Account Manager so Account Manager instance is the dependency for the profile class here and let's talk about the example we have below the view control class so inside view control class inside viewdidload function we are getting the name property from this user profile object and setting it as a text property of our user name label so in case the view controller is loaded its viewdidload will be invoked and if the user profile is still nil then our app will crash crash so user profile here is kind of a dependency for our view controller because if it will be nil then our app might get crash let's see one more example of dependencies here we have again taken the same profile class but here inside its initializer it takes two arguments one is of type Account Manager another is type of user profile so there are such cases in our application as well when a class needs when a class have multiple dependencies so according to me dependencies in code is somewhat similar to the dependencies in real life suppose as an iOS developer someone has given me a task to integrate a web service into my application then in that case I need a web service from the back-end team so to complete my task I have a dependency I need a web service from the back-end team until I get this web service I can't complete my tasks so this web service from the backend team is the dependency for me in this case so similarly in if you want to create an instance of this profile class we have to give it an instance of account manager and user profile in this case these two instances are dependencies for this profile class so now I hope you do understand the concept of dependencies from here let's move to our next question what is dependency container suppose for an instance we have two objects Account Manager and user profile these are two most commonly used objects at different places of your applications so what you are going to do in this case are you going to create new instances of Account Manager wherever it is required no you can't create multiple instances of Account Manager why because Account Manager represents a single users account which is logged in so you should only create a single instance of Account Manager and it should be passed the same object should be passed at multiple locations where it is required similarly you can only create a single instance of user profile which represents the profile of user which is logged in you can't have multiple instances of user profile so we can solve this problem using the global dependency container what we will do is we will register our dependencies to our dependency container by calling the register function and after calling this register function this dependency container will hold all of our dependencies I mean which we resisted and we're forever or whenever these dependencies are required we will simply invoke the dependency not resolve function and we can simply get it now we do need any initializer with dependencies because we have dependency container we can simply fetch the dependency we require from the dependency container before resolving the dependency we must be ensured that it is already registered to the dependency container so our code already looks much better we know we don't need any lengthy initializer with dependencies we can simply get the dependencies using the resolve function of our dependency container from any location of our application but we can even further reduce our code using property wrappers so using property wrappers we can introduce another level of abstraction by hiding the call to resolve function of our dependency container so you can see the difference by using dependency container our code looks much readable much short much maintainable so let's start implementing this dependency container as a framework let's create a framework let's name it dependency container click Next let's create it in documents let's create a new file Swift file and let's name it dependency container let's create a class called dependency container we'll make this class public so that it can be exist from the outside of this module public class we'll create two functions one is to register any dependency and other one is to resolving a dependency so what will be the type of dependency type of dependency could be anything and like in the example I showed you a corn manager user profile or any type so it must be gender ik dependency so this dependency argument represents the dependency that has to be registered and [Music] this resolve function would would also be gender ik okay so these are the function two resistor and resolving a dependency now we will create our hash map dictionary which will hold all our dependencies so we'll make it of type string and any object for now but I change this later on in this tutorial so now whenever the register function would be invoked we will add the dependency in our dependencies dictionary so let's do that and we will use the name of the type of dependency as the key for our dictionary so let's fetch the key first let's take a constant we'll use the function type of and we will try to give the type of this generic parameter dependency and now we'll add this dependency in our dependencies dictionary corresponding to the key which represents the name of the type of dependency and I'll also typecast it for now I change this later on this tutorial so we have implemented the register function now we will implement the resolve function in resolve function we will return back the ask dependency to the caller of this function so again we will try to get the key from the generate parameter and will again create a constant dependency equals to and then C object for key so this dependency would be optional so what we will do here is we'll put a precondition so dependency should not equal to no dependency is nil the app will be crashed with the message that we will provide here a second argument so if dependency is nail'd it means the dependency is not registered with our dependency container so what we'll do is no dependency found for this type then we will also tell user that application must register a dependency before resolving it yeah so now we will return the dependency it our dependency as not the so again I have typecasted the dependency here but I'll update all such course later on so all these functions and this dependencies property will be private I don't want the user of this library to exist them so I will make it private instead I'll create some static function static public functions which will be used by the user of this library let's copy this okay so here I can't exist a non static property inside a static function so for that you will create an instance static dependency contained in it skip the static no I guess we need to have this static let me put it back yeah now I'll invoke the register function this non static register function with the dependency provided by the user similarly I'll create another public static function to resolve a dependency and inside that I will call the resolve function so this implementation seems good but that's not the case we have a bug here and the bug is all the dictionaries in is by default hold the elements inside it strongly but that shouldn't happen why because whenever a user register a dependency the dependency container will hold it strongly and even if that dependency is not needed anymore it will still want PT allocated by the operating system why because dependency container is holding that dependency strongly so we need to break this thing how we can do this I have a quick solution for this I have used the same solution in my previous tutorial the generate multi delegate patterns so what we can do here is either we can replace this dictionary with a nice map table but instead of that I will use a quick solution so what I will do is I will create a new file and s map table actually hold its element weekly so I'll create a new but we are not going to use that and it's map table here I I'll create a new class so in this class I will paste my implementation of V class I created in my previous tutorial generate multi delegate pattern but I'll explain it here as well so we have a class called week it confirms to equitable protocol what does that mean it means that two instances of this week type can be compared using double equals to operator and inside this function we ever we are comparing those two ins instances on the basis of the value property that we have here if value property will be equal then you are those two instances of V type would be equal and yeah as we have a value property inside this V class but it is a weak property so whatever we put inside this value will be held weekly so we also have an initializer and in this initializer we pass the value of type any object and that object will be held weekly by our value property of glass so now instead of putting the dependencies directly into the dictionary we'll put it inside our value property of this week type so that venue property will hold those dependencies weekly and depend those dependencies can be allocated by the system anytime based on the application logic the our dependency container won't hold those dependencies strongly so the problem solved lest let's implement it let's replace this any object with week and now we will be facing too many errors so let's go here let's create a constant of type week week dot and eat let's put the dependency inside it as any object let's put the weak object inside it so the dependency would already be stored inside the value property of this weak type and now let's fetch the dependency so first of all I will replace the name here I'll make it weak because now dictionary is holding the weak type of values and I'll also change the name here in our precondition so now I will check if the value is inside the weak type of instance the values is still there or not because now the dependency is being held weekly so dependency can be de-allocated anytime by the system based on the application logic so before resolving it or giving it back to the user who invoked this function we must check it if it still exists or not okay so let's call it dependency and week we could definitely want to be nil now because if it would be nil then the our app will crash here on the precondition so I can use this force unwrapping here because I know it won't be nil here and this any object of sorry this value could be nil here so that's what we are checking here and it should be of type D now we will implement another precondition here so I will copy it here so if the dependency is nil it means dependency is already diello get it by the system and now we don't need this we can simply return the dependency oh I just need to falsely unwrapped it because I know it won't be nil here as if it would be knit then the precondition would crash the application and we are good to go everything seems awesome I'll just make this one private so it can be exist outside from this module or even outside of this class everything seems good but now we will use property wrapper to introduce another lever of level of abstraction let's create a new file let's name it dependency I have a dedicated lecture on property rapper as well but I'll explain a bit here as well so to make a class a property rapper we need we need to use this keyword property rapper with enter it as a prefix and every property rapper must have a property of type rap value and our property property rapper would be genrich's so I'll use a generic type here T and the rev value could be of same type and I'll have an initializer here rap extra P who rapped value of type T and he rapped value is equal to so this is kind of a default implementation of a property wrapper now I will show you how we can create an object of the property wrapper let's take a random class ABC and inside that we will create an object of property kappa type so first we will use a trade then the name of the property wrapper and rest of the object we will create normally so I have created an object of type this property wrapper and I'll name it X and I give it I give it an integer value so this is a generic property wrapper so this gender type would be replaced by int in this case and the most important concept is whenever we give this default value to a property wrapper then its initializer will be called with that default value and this one would be passed here as wrapped value and that one will be assigned to this rev value property so that's how the property wrapper works usually but here we will do some changes so let's not remove that we will update it later so instead of for asking for the wrapped value inside the initializer that we call when default value is a sign we will give it the initial value from dependency container by invoking the resolve function so what will happen is now let's pick another class this create a class called Account Manager okay and [Music] you will create an property which will represent this Account Manager let's try to understand the flow step by step so first of all we created a property wrapper of type Account Manager so the first thing that will happen is this generate parameter will be replaced by the type Account Manager and now the rep value is of type Account Manager then this property wrapper is created without any default value source initializer will be invoked without any default value or wrapped value when the initializer in invoke this piece of code will be executed so dependency containers resolve function will be invoked and the result function note that this Rev value accepts expects a value of type account manager so resolve is also a generate function now resolve will automatically infer the generate type as account manager let's move to this resolve function this is a static function now it's invoking this private function resolve this one and inside that it will create a key from that generic type which is account manager so it will create a string representation of account manager here and then it will fetch the corresponding dependency to that key from registered dependencies and then it will typecast it to type T which is in our cases Account Manager and return it back to the caller which in our case is the draft value so now the ref value contains an object of type about which is actually a dependency which was registered previously so one more interesting thing and the most important thing whenever this account manager is exist it is actually backed by this wrapped value it means whenever we access it we will get the value of wrapped value this property wrapped value so if I will exchange it anyway in my application I am actually getting the value of this wrapped value which is in our case is a dependency of type account manager which is fetched from this dependency container so how beautifully our work is done in one line of code using property wrappers one thing we should always remember is first we have to register a dependency only then we should try to resolve a dependency from any location of your application otherwise our app will crash here at this precondition so first register a dependency only then try to access a dependency from any location of your application so we are almost done here let's try to integrate this framework to a real life application and see how this framework will help us in a real-world application so I have already integrated this dependency container framework in one of my application so I just drag and drop this Xcode project file into this application and I have also added this dependency container framework in this embedded content section and I'm good to go wherever I need to use any public class of this dependency container I just need to import this framework by writing this let me show you by writing this line import dependency container I just made the one little change in the dependency container framework I just make this property wrapper and it's initializer and add value as public property so that it can be exist from outside of the dependency container module let's go back to the app delegate yeah so now I will show you how I've used this dependency container in my application so here these are few dependencies that I used need to access at multiple location of my application so card file manager carbon so this app basically manage these cards so card file manager is to manage the card file to save and retrieve the cards from a file card manager has operations to add or remove or edit a card and this is date manager this is used to manage dates so let's ignore this one so when I created these objects in my did finish launching with option I mean you don't necessarily need to create all your dependencies here it depends on your application logic I just created it here because it suited me so I created my dependencies here and I just registered all those dependencies in my dependency container using the register function so now I don't need to pass these dependencies anywhere from class to class and all blah blah I just registered it it with my dependency container now wherever I need it I just get it using the property wrapper that we have created inside dependency container let's search this property container so property wrapper so so wherever I need this card manager I just used to create this property wrapper and this property wrapper will internally get this dependency of type card manager from the dependency container as I shown you before so you can see I just need to create this object of type property wrapper then wherever I want to exist this card manager so the managing dependencies has become pretty simple by using this dependency continue framework so that's all regarding dependency container in this tutorial I hope you guys learned a lot in this tutorial and I'll recommend you guys to go through my other tutorials as well on property rappers and generate multi delegate pattern my next tutorial hopefully would be on and on even bus or unit testing and before leaving this tutorial I'll tell you a little improvement that we can do the problem here is this Reb value is will hold the dependencies is strongly so to tackle that what we can do is we can create a protocol that every dependency has to implement to register itself as a dependency and here we can say and now we can make this as unknown so now in this case this rap value or this property wrapper won't hold any dependencies strongly so this is good for our application logic and but the thing is every dependency like card manager file manager manager has to confirm this protocol is dependency so that's all the in this tutorial see you in the next tutorial bye bye
Info
Channel: Confiance Labs
Views: 1,632
Rating: undefined out of 5
Keywords: Dependency Container, Dependencies, dependencies in swift, property wrappers, ios, swift, swift 5, xcode
Id: h2FBZcLBeq0
Channel Id: undefined
Length: 30min 31sec (1831 seconds)
Published: Mon Apr 13 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.