I want to add selection field in a model which should be array of references. If I add this to model selection: types.array(types.reference(Todo)) then I have some undesirable side-effects like selection is being saved/loaded in snapshots and also changes to selection are recorded to the undo/redo history when using UndoManager middleware. If I put selection in volatile properties as just plain array then I lose reference sync capabilities(ie if one of selected elements removed from model selection will not be updated automatically).
Is there an approach which would allow to get benefits of both? Is there a way to ignore model field in patches/snapshots without moving it to volatile?
Good approach for models is to only have fields that belong to this entity and that you need in snapshots to send to server or elsewhere. Otherwise models become confusing and hard to manage.
Usually in such cases I put property like that into separate store or sub-store which bound to particular page/view for example. So this is structural issue more then anything else in my opinion.
Related
I'm struggling to understand how to use UICollectionViewDiffableDataSource and NSDiffableDataSourceSnapshot to model change of items.
Let's say I have a simple item which looks like this:
struct Item {
var id: Int
var name: String
}
Based on the names of the generic parameters, UICollectionViewDiffableDataSource and NSDiffableDataSourceSnapshot should operate not with Item itself, but only with identifier, which Int in this example.
On the other hand, again based on names of generic parameters, UICollectionView.CellRegistration should operate on complete Item's. So my guess is that UICollectionViewDiffableDataSource.CellProvider is responsible for finding complete Item's by id. Which is unfortunate, because then aside from snapshots, I need to maintain a separate storage of items. And there is a risk that this storage may go out of sync with snapshots.
But it is still not clear to me how do I inform UICollectionViewDiffableDataSource that some item changed its name without changing its id. I want UICollectionView to update the relevant cell and animate change in content size, but I don't want insertion or removal animation.
There are two approaches that would work solve your problem in this scenario.
The first is to conform your Item model to the hashable protocol. This would allow you to use the entire model as an identifier, and the cell provider closure would pass you an object of type Item. UICollectionViewDiffableDataSource would use the hash value for each instance of your model (which would consider both the id and name properties, thereby solving your name changing issue) to identify the data for a cell. This is better than trying to trick the collection view data source into considering only the id as the identifier because, as you stated, other aspects of the model might change. The whole point of structs is to act as a value-type, where the composition of all the model's properties determine its 'value'...no need to trick the collection view data source into looking only at Item.id.
Do as you said, and create a separate dictionary in which you can retrieve the Items based on their id's. While it is slightly more work to maintain a dictionary, it is a fairly trivial difference in terms of lines of code. All you should do is dump and recalculate the dictionary every time you apply a new snapshot. In this case, to update a cell when the model changes, make sure to swap out the model in your dictionary and call reloadItem on your snapshot.
While the second option is generally my preferred choice because the point of diffable data source is to allow for the handling of massive data sets by only concerning the data source with a simple identifier for each item, in this case your model is so simple that there's really no concern about wasted compute time calculating hash values, etc. If you think your model is likely to grow over time, I would probably go with the dictionary approach.
I have this idea of generating an array of user-links that will depend on user-roles.
The user can be a student or an admin.
What I have in mind is use a foreach loop to generate a list of links that is only available for certain users.
My problem is, I created a helper class called Navigation, but I am so certain that I MUST NOT hard-code the links in there, instead I want that helper class to just read an object sent from somewhere, and then will return the desired navigation array to a page.
Follow up questions, where do you think should i keep the links that will only be available for students, for admins. Should i just keep them in a text-file?
or if it is possible to create a controller that passes an array of links, for example
a method in nav_controller class -> studentLinks(){} that will send an array of links to the helper class, the the helper class will then send it to the view..
Sorry if I'm quite crazy at explaining. Do you have any related resources?
From your description it seems that you are building some education-related system. It would make sense to create implementation in such way, that you can later expand the project. Seems reasonable to expect addition of "lectors" as a role later.
Then again .. I am not sure how extensive your knowledge about MVC design pattern is.
That said, in this situation I would consider two ways to solve this:
View requests current user's status from model layer and, based on the response, requests additional data. Then view uses either admin or user templates and creates the response.
You can either hardcode the specific navigation items in the templates, from which you build the response, or the lit of available navigation items can be a part of the additional information that you requested from model layer.
The downside for this method is, that every time you need, when you need to add another group, you will have to rewrite some (if not all) view classes.
Wrap the structures from model layer in a containment object (the basis of implementation available in this post), which would let you restrict, what data is returned.
When using this approach, the views aways request all the available information from model layer, but some of it will return null, in which case the template would not be applied. To implement this, the list of available navigation items would have to be provided by model layer.
P.S. As you might have noticed from this description, view is not a template and model is not a class.
It really depends on what you're already using and the scale of your project. If you're using a db - stick it there. If you're using xml/json/yaml/whatever - store it in a file with corresponding format. If you have neither - hardcode it. What I mean - avoid using multiple technologies to store data. Also, if the links won't be updated frequently and the users won't be able to customize them I'd hardcode them. There's no point in creating something very complex for the sake of dynamics if the app will be mostly static.
Note that this question doesn't quite fit in stackoverflow. programmers.stackexchange.com would probably be a better fit
We're looking for a way to document Core Data entities. So far the only real options I've come up with are:
Document externally using UML or some other standard
Create NSManagedObject subclasses for every entity and use code comments
Use the User Info dictionary to create a key value pair that holds a string comment
Option 1 feels like too much extra work and something that will almost certainly be out of date 99% of the time.
Option 2 feels natural and more correct than option 1. The biggest con here is that those comments could potentially be lost if this model class is regenerated using Xcode.
Option 3 feels a little less correct than option 2, but has the added advantage of adding automation possibilities with regards to meta data extraction. For instance, in one of our apps we need to keep a real close eye on what we're storing locally on the device as well as syncing to iCloud. Using the user info dictionary it's pretty easy to automate the creation of some form of artefact which can be checked both internally and externally (by the client) for compliance
So my question is whether it would be inappropriate to use the user info dictionary for this purpose? And are there any other options I'm missing?
Option 2 is what I use every time. If you look at your core data model (something.xcdatamodeld or something.xcdatamodel) you will see something like the picture below.
You can tie your entity to whatever class you want and then put the comments in there. It helps if you keep your entity name the same as your class name to make it obvious what you've done.
Additionally this also gives you the ability to add automation. You can do this by creating custom getters and setters (accessor methods) and a custom description method.
I use option 2 and categories. I'll let XCode generate the NSManagedObject subclasses and use a categorie on each of these subclasses. With the categories I do not loose my changes made in the categories, can document, make custom getter and setters and I am still able to use generated subclasses.
If we speak only about documenting (i.e. writing more or less large amounts of text which is intended to be read by humans) your classes, I'd use the option 2.
If you are concerned with the possibility of Xcode overwriting your classes in the option 2, you may consider creating two classes for each entity: one which is generated by Xcode and always could be replaced (you generally do not touch this file) and one other which inherits from the generated one and in which you put all your customizations and comments.
This two-class approach is proposed by the mogenerator.
Although if you need to store some metadata with the entities which will be processed programmatically, the userInfo is perfectly suitable for this.
If from one view a user enters some invalid data, e.g.:
E-mail: bill#apple.com
then i want the controller to:
not place the data into the model
color the text box reddish
not allow the user to save
But it's possible that if the user enters the same invalid data in a different view i want the controller to:
place the data into the model
color the text box reddish
allow the user to save
But it's possible that if the user enters the same invalid data in a different view i want the controller to:
place the data into the model
color the text box bluish
allow the user to save
And it's possible that another view will:
place the data into the model
leave the text box uncolored
allow the user to save
And it's possible that another view will:
auto-correct the data, placing it into the model
color the text-box reddish
allow the user to have
And it's possible for another view to:
auto-correct the data, placing it into the model
update the view with the new data
color the text-box bluish
allow the user to save
[ad infinitum]
Without using n-controllers for n-views, how do i do this?
Update
i was about to ask a new question on stackoverflow, 'How do i have the controller change its behavior depending on the view." But then i realized that i have the exact same question title in use already.
Today's example:
If the entered data is too long for some parts of some of the database tables it will be going into, then perform validation and reject a save.
unless the data is coming from another view. In which case automatically trim certain fields to fit the database rules
unless the data is coming from another view. In which case, require the database to throw it's truncated exception
So many practical problems with MVC that i never see addressed in the books/articles/blogs i've read - it's no wonder i don't use it.
The logic of what has to be done with each view must reside somewhere. I would recommend you empower the view with that information, instead of using multiple controllers, or creating some sort of mapping between view => configuration within a single controller.
I don't know what these views represent in terms of your domain, but it looks like the view seems to be commanding if invalid data can be saved into the model, if auto-correction is permitted, the visual indication for invalid data, etc. Why not empower the view with all that information?
Each of these views would have certain properties.
acceptsInvalidData => boolean, place invalid data to model
requiresAutoCorrection => boolean, auto-correct the data
synchronizeWithModel => boolean, always keep the view in sync with the model
allowsSavingInvalidData => boolean, allow saving of invalid data
invalidDataIndicator => string:color, how to color view for invalid data
Given these 5 properties (maybe missing one or two), the controller can initiate a sequence of actions that will uniquely handle each type of view. The view will have to expose himself or the properties to the controller.
Your examples can be somewhat generalized in the view as suggested, however, some use cases really ask for different controller imho. Also you might try add some logic in models.
Colors are straight view thing, controllers should decide if it is reasonable to save the data in the models, if that data doesn't have some property deciding if it should be saved or not, let it on controllers, possible different ones. Auto-corrections should be in views and helpers.
That is only my opinion.
To summarize the problem:
It seems you want N different behaviors without having N controllers.
You don't want to tightly couple the views and the controllers (no 1<->1 relationship), but the you want the controller to have strong and varied control over the behavior of each view.
Let me state this differently:
It seems you want N different behaviors without having N objects.
You don't want to tightly couple the A objects and B objects (no 1<->1 relationship), but the you want B object to have varied tight control over the behavior of each A object.
Here's how I see these 2 issues:
This isn't a problem of MVC, its a classic software problem: you either need N objects to have N different behaviors, or you need to parameterize the behaviors so that you can distill out commonality (e.g. the approach Anurag suggested) to have less than N separate objects and/or resort to a giant case statement. :-)
This one isn't a problem of MVC, but rather its one of the trade-offs. MVC has us decouple the M, V, and C code to ease future changes (e.g. changing or adding views). But the trade-off isn't free, the components necessarily have to have less knowledge and control of each other. Either you give up on the controller having tight control over the views (no N different kinds of behaviors) or you give on the segregation between the C and V (e.g. allow 1<->1 tightly coupled views-controllers).
Certainly, there has been great success with MVC in decoupling the Ms from the Vs and Cs, but less success in decoupling the Vs and Cs from each other. I think today's responsive interfaces call for coupling views and controllers, or started differently, its not worth the effort and complexity to strongly isolate views and controllers. This modified M(VC) approach has worked much better for me in the real world.
I have a model and two views set up like this:
Model ---> OSortFilterProxyModel ---> OListView
Model ------------------------------> OTableView
When the user selects something in one of the views, I want the other view to mirror that selection. So I thought I'd use a QSelectionModel to link them together. But this does not work. I have a feeling it is because the views think they have two different models, when in fact they have the same model. Is there a way to get this to work?
What is probably happening is that the views do have two different models. One is your original model, the other is the sort filter model.
I'm not sure if this would work, and it depends on what Qt considers "activated", but you could connect a function to each of the view's activated slots. These will pass you a model index. You'll have to send the model index through the proxy model in the appropriate direction (mapFromSource and mapToSource). Then, call the setCurrentIndex on the other view.
The documentation for the activated signal states that what is considered "activated" varies by platform. There might be other signals you could latch onto, such as the selection model's selection changed signal. You might have to do a different call to change the selection as seen by the user. And finally, it might be possible or even easier to do in a derived QSelectionModel, as long as you remember about mapping to/from the source model.
Not quite sure how your model subclass is implemented - but the selection depends on persistent model indexes being correct. Can you provide some source code? Are you using the same selection model on both?
You propably need to use void QItemSelectionModel::select combined with QAbstractProxyModel::mapSelectionFromSource and QAbstractProxyModel::mapSelectionToSource. In QListView's selectionChange signal handler you should have
tableView->selection()->select(
proxyModel->mapSelectionToSource(selected),
QItemSelectionModel::ClearAndSelect);
and analogically with mapSelectionFromSource in QTableView's signalChange signal handler.
Note that i am not sure if Qt will prevent infinite recursion when table will change selection of list which in turn will change selection of table and so on...