Say I have an instance of a class which i need access to in many different places of my app. I have come up with three solutions so far
Passing the instance as an argument in every class of the app
Making a top level Provider above the MaterialApp-widget that exposes the instance to every method that has access to the app's context
Storing the instance in a static field
Which way is the best performance wise? Will the Flutter-framework ever discard the instance stored in the static field?
Which way is the best performance wise? Will the Flutter-framework ever discard the instance stored in the static field?
In this case, I like to use the DI framework like get_it
With the DI you can specify what is the object that you want and you can have it in your Wiget or Component, without coupled it with the specific implementation.
Use the get started guide to see how it is simple to use and what are the benefits.
Get Started
Suggestion
I suggest wrapping the library in one component inside your app, with the only motivation that with your own wrapper around the DI library you avoid to coupled all the app with the get_it, and you can change it easily in the future if you want.
Not sure about the performance, but the second option (Provider way) is what I am using in my projects and that's even a recommended approach (https://flutter.dev/docs/development/data-and-backend/state-mgmt/options#provider).
Passing the instance as an argument in every class of the app
This could lead to a very cumbersome code, every constructor would be cluttered by the same property passing all the way down to the Widget tree - not a Flutter way at all, that's why InheritedWidget was introduced some time ago, and later - Provider.
Storing the instance in a static field
It depends. E.g. it is ok to store all the colour constants inside a class having static fields - that's just convenient to access them everywhere. This option could also work in your case (not sure about the size and the amount of information stored in that class instance), but implementing your class as a Singleton would probably make more sense than storing the whole instance in a static field.
Related
Question for Flutter users.
I have a class which holds a number of static values regarding a project. These values need to be accessible in various widgets.
Is it more efficient to create one instance of that class in the main.dart file, and pass it's pointer through to all the widgets that need it, or should each widget create it's own instance of the class? Given that the parameters within the class will never change.
I suspect both is fine (especially when there are only 20 or so parameters), but I want to select the more efficient approach.
I have a big project and manage a lot of data with firebase. For this I have a class "MyFirestoreDatabase" in which I have every single firebase function, which I then call from my providers.
The problem is, that the MyFirestoreDatabase class has gotten really really big and I would want to split it up into sub classes and different files.
Every time I call a firebase function I use MyFirestoreDatabase.instance.functionName(),
so I don't think I want different classes, because then I would have multiple instances of the database open at the same time right?
Would it work to extend the class?
Calling FirebaseFirestore.instance always returns the same (default) instance, no matter how many times you call it. This is the essence of the singleton pattern.
So calling it in each separate class won't make any change in resource consumption, nor in the number of connections to the backend servers.
I've been doing iOS now for about two years and mostly by consequence of simple data layers (no real need for ID's, joins, complex queries, etc), I've always managed persistence manually by extending NSObject, conforming to NSCoder, and saving my data in flat files.
However, now I am in a position where I need to start doing more complex query work and I am digging into CoreData.
My hangup right now is with NSManagedObject. It's a pretty intimidating class and I am wondering if there are any unwritten gotchas I should be aware of that might restrict my freedom while building a sophisticated application.
For example, things like #dynamic getter/setters are not to clear to me, etc
So:
1) Are there any features of NSManagedObject that would prevent me from handling instances of custom classes just as I would with NSObject?
2) Does NSManagedObject have any unusual behavior when objects are handled WITHOUT the presence of a ManagedObjectContext?
3) Can I supplant a #dynamic property declaration with my own custom getter/setter without too much pain? I use a lot of custom setters to enforce business logic.
and so on, and so on.
Thanks
Beware!
Core Data is not lightweight. It will require a lot of changes to the way your objects work, unless they are very basic.
1) Are there any features of NSManagedObject that would prevent me from handling instances of custom classes just as I would with NSObject?
Faulting and the lifecycle of managed objects are a little tricky to understand. Your objects can be "faulted" almost at any time (each iteration of the event loop anyway), which makes them lose any non-persistent state. When they get "un-faulted", they don't have access to anything outside the managed object context to restore their state. It's very hard for managed objects to access anything outside the managed object context.
Transient properties are possible, but are pretty much limited to things that can be computed from the persistent properties, since their state will be lost if the object is ever faulted. You also have to formally declare that you're using a transient property in the data model. Trying to just set up instance variables will run into problems.
So basically managed objects properties all must be persistent or related to persistent properties. Look at the objects you're planning to make managed. Are all their instance variables feasible and desirable to put into a persistent store? If not things will not be straightforward. You probably set up your instance variables in your init. There is no init that gets called every time your program runs for managed objects. There are awakeFromInsert and awakeFromFetch, but those don't work exactly like init. Your code calls init and can pass arguments. The framework calls awake and it gets no parameters.
Threading is another issue to consider. A managed object context, and therefore the managed objects in it, are recommended to be used only by a single thread. If you have multiple threads, and they need to access your model, you need to create duplicate managed object contexts containing duplicates of your managed objects. Core Data is designed to handle that without putting too much strain on memory, disk I/O, and processor, but it isn't lightweight from a coding perspective.
2) Does NSManagedObject have any unusual behavior when objects are handled WITHOUT the presence of a ManagedObjectContext?
You cannot have a managed object without a managed object context.
That's not usually an issue. Managed objects carry a pointer to their managed object context. It can be a little limiting though. If something outside your model needs to create a model object as an input to your model, it needs to have access to the managed object context to do that. Hopefully that would be through some kind of abstraction layer so it doesn't need to know it's dealing with Core Data, but you can't just give it a class and have it alloc/init. It is also a bit of work to move managed objects between different managed object contexts.
3) Can I supplant a #dynamic property declaration with my own custom getter/setter without too much pain? I use a lot of custom setters to enforce business logic.
Yes. It's a bit complicated but doable. You write your own accessors. In addition to your business logic, they must call key-value observing methods like willChangeValueForKey:. Then you access the data using primitive accessors.
1) Are there any features of NSManagedObject that would prevent me from handling instances of custom classes just as I would with NSObject?
Creating and removing them is different, but not difficult. Otherwise, no
2) Does NSManagedObject have any unusual behavior when objects are handled WITHOUT the presence of a ManagedObjectContext?
I'm not sure what you mean, you can pass a managed object to another class and use it quite happily without the other class knowing about the context, but you must have a context somewhere.
3) Can I supplant a #dynamic property declaration with my own custom getter/setter without too much pain? I use a lot of custom setters to enforce business logic.
Yes, NSManagedObject is designed for this purpose. There are plenty of examples of overridden accessors in the core data programming guide - there are some rules you need to follow but they are not too onerous.
Core data is primarily a persistence framework rather than a query framework - I imagine once you get into it you will wonder why you were wasting your time on all those NSCoding implementations...
1) Are there any features of NSManagedObject that would prevent me
from handling instances of custom classes just as I would with
NSObject?
No. You can extend a NSManagedObject subclass just like a NSObject subclass.
2) Does NSManagedObject have any unusual behavior when objects are
handled WITHOUT the presence of a ManagedObjectContext?
The #dynamic directive will create accessors optimized for saving in a persistent store managed by a context. The values will still be available just like any other object but you will generate a lot of overhead.
3) Can I supplant a #dynamic property declaration with my own custom
getter/setter without too much pain? I use a lot of custom setters to
enforce business logic.
You can but you will incur some performance penalty because the generated accessors will be highly optimized for the specific code in your app.
One major point of novice confusion with regard to managed object is missing that the generic NSManagedObject can represent any entity in the data model without subclassing. NSManagedObject has "associative storage" which basically means that it has an open dictionary attached to it that save any key-value pairs. When you you insert a generic NSManagedObject into a context, the keys of the associative storage "dictionary" are set to the property names of the entity given.
Therefore, you are actually never really forced to subclass NSManagedObject. Doing so is largely a matter of convenience.
That is why you sometimes see code that uses generic NSManagedObject and the setValue:forKey and other times you see custom subclasses that use anObject.propertyName.
I would also advise that if you find yourself using or saving managed object outside a context, then chances are good that you have a bad design.
I am making an object of AppDelegate and using it throughout my program, and I have declared all setters and getters, and also insert, select, delete, update queries of database in it.
I want to ask that is it a good practice to do so,
if yes, then how, and if no then why it is not a good practice?
I hope my question is clear, please ask relating questions if you have any.
It's not a good strategy to turn your AppDelegate into a "big ball of mud" that contains a million methods and properties (although it might be tempting).
A better and more object oriented approach to section off bits of functionality into well-designed objects -- for example you might have a class DatabaseManager which handles all database interactions. You might then have bits of your app which need the DatabaseManager ask the app delegate instance for a reference to a DatabaseManager.
Alternatively, you can pass around a reference to the DatabaseManager to the parts of the app that need it. This last approach does however cause more 'interface pollution', where you have to modify interfaces in lots of places in order to pass in the DatabaseManager.
And yet another alternative would be to effectively make your DatabaseManager itself be a 'singleton' -- whereby an instance of it is accessed via a class method on the class. Singletons that work in this way are often frowned upon, and usually for good reasons (makes testing harder, that sort of thing). I tend to avoid having objects have their 'singleton' nature baked right into the object -- I prefer, if I need that sort of thing, to have a known point of access (a kind of 'factory' if you like) where you can go to obtain a shared instance.
I think the best way would be creating a global singleton class instead of handling in the Appdelegate.
Declare all you setters and getters there and using the singleton object handle all around your project. See this link how to create singleton class
For Database, create a DataAccessLayerClass. whenever you want to execute any queries access this class. This class methods should have inputs as your data and will create the queries and will execute that query and return the data.
It's all about complexity and your feelings. You must like your solution ;-)
I obviously do this in another way - I've got singleton, which does handle all my common database things. I'm trying to keep application delegate as simple as possible. It's better for code sharing, etc.
What do you do with classes that have no member data, only methods?
Do you make them static?
In my case it is an repository class that executes queries against the database. Maybe I got the repository pattern wrong... (It does implement an interface)
Inherit from an Interface mean that you cannot use static. Simply create a class and instantiate it.
If it implements an interface, and gets passed around as that interface, then you can't make the members (or the class) static. The interface aspect means that although an instance won't have any actual fields, it still contains valuable information - its type.
You might want to make it a singleton, but there's no particular need to.
Why won't you make a database wrapper class, that maintains the connection to database opened/closed. Moreover, it can also open it automatically if new query is sent. You can include the functions your class has, running them right on the inner pointer to the database.
I guess this is the best database management pattern. If you use it, you should make a Factory method that returns the object of this class initialized on some specific database. Then you pass that object around.
Or if you are lazy and sure that you will need only 1 database, make it a singleton.
It depends. Most of the time it might be possible to make the class static, but sometimes you need to pass an instance of it around. Sounds like you might be having this situation. In this case perhaps you should consider a Singleton pattern, since more than 1 instance of the class is not likely to be needed?