ngOnChanges is deprecated in favour of ngAfterChanges, but the former was given a list of properties that changed. The latter gets nothing. How do I know what changed so I can only perform expensive actions if a particular #Input changed?
Calculating the list of changes was actually expensive itself. So it was dropped instead I would suggest having a setter mark if something has changed for just the expensive inputs.
Related
I have TKeyframe as a class, and Keyframes: TObjectlist<TKeyframe> in a base class TTrack, but in descendants of TTrack, Keyframes contains descendants of TKeyframe with additional fields and appropriate typecasting.
TTrack has methods that call Keyframes.Move and Keyframes.Delete methods, that generally seem to be working properly with the descendants of TKeyframe. Deleting a keyframe that isn't at the end of the list appears to be working properly except for a specific situation, when one of the additional fields in the next Keyframe is getting set to a NaN by some subsequent operation that I haven't been able to isolate.
The source of TList Delete uses System.Move to move what are just pointers for a class, so it looks safe to me. So is it safe to use with descendants of T or not?
TList Move casts to T for the item being moved, so looks dodgier, but I haven't had any problems with it so far.
Yes, there is nothing in TObjectList<T> that affects polymorphism and System.Move just moves memory.
To find out what code sets some field to an unexpected value I suggest to use a data breakpoint.
We've started using VirtualTreeView v5.5.3 with Delphi7 since 1 year and love it!
We would like to use the full potential of the component, but there is only a little information about the BeginSynch method in the help file.
When should BeginSynch + EndSynch be used compared to BeginUpdate + EndUpdate?
Which one should be nested into the other?
What methods can be used in which case? (Sort, ScrollIntoView, MoveTo, NodeHeight, isVisible[], ... ) to group manipulations before painting to speed up the app?
To my understanding they have different, almost opposite purposes, and for your use case you would need BeginUpdate.
BeginUpdate is typically called when you want to do a lot of updates, and you don't want redrawing etc to happen during that process. Many controls, including TListBox and TDBGrid, have this possibility to speed up bulk updates.
BeginSynch is related to events, especially the OnChange event. The VirtualTreeView can fire the OnChange event with some delay when you set the ChangeDelay property to a value higher than 0.
This also means that you may miss some events. If you make two changes in rapid succession, you may only get one event, or you may get the event later than desired.
BeginSynch will start a synchronous mode that fires the OnChange event immediately after (in sync with) the change being made, overriding the ChangeDelay property. Starting this sync mode is easier than saving the value of the ChangeDelay property and restoring it afterwards.
So in a way, you could say that BeginUpdate and BeginSync are almost opposites of each other, in terms of speed, but really it's just about what your usecase is. For your case ("grouping manipulations") you would definitely use BeginUpdate.
The documentation on BeginSynch could be a bit more clear in this regard. It refers to BeginUpdate because it's a similar kind of mechanism (entering some kind of update mode, with a correlating EndSomething method), while actually it should refer to ChangeDelay which it is functionally related to. It's also interesting that the 'Send feedback' link at the bottom of the documentation is not actually a link...
I have a control derived from TStringGrid.
During creation I want to access the Cancas to do some one time initializing.
I can't do it in Create because the Canvas is not ready yet. I also can't do it in CreateWnd because CreateWnd it is called multiple times.
There are some cheap tricks (use a Boolean variable) to initialize that var only once but I would like to know how to do it the 'nice way'.
So, since Create and CreateWnd is not a good place, where during the creation of a control can I initialize the var ONLY once.
The simple answer is that you should not cache this value. Calculate the value on demand, when you need it.
Caching is something that you should avoid doing. The problem with caching is that you have to make sure that you never work with a stale value. You need to respond to anything that might result in a change in the value and update your cached value.
It's easy to get that updating logic wrong. Even if you get it right, you've just added a whole load of complexity to your code. And you always want to avoid that if possible. In the case of a physical font metric, they are cheap to obtain in comparison with what you use them for. Invariably you will be using the font metric as part of your painting code. And surely that is many orders of magnitude more expensive than obtaining a font metric.
So, you can make all your problems go away by the very simple expedient of not caching, and obtaining the font metric as and when you need it. By all means wrap it up in a property with a getter method to make the code as clean as possible.
I have an Polymer.dart element with multiple attributes, e.g.
<code-mirror lines="{{lines}}" widgets="{{widgets}}">
</code-mirror>
on some occasions lines and widgets change simultaneously sometimes only widgets changes.
I would like to rerender component once independently on how many properties change in the same turn of event loop.
Is there a way a good built-in way to achieve that?
Additional trouble here is that interpretation of widgets depends on content of lines and ordering in which linesChanged and widgetsChanged callbacks arrive is browser dependent, e.g. on Firefox widgetsChanged arrives first before linesChanged and component enters inconsistent state if I do any state management in the linesChanged callback.
Right now I use an auxiliary class like this:
class Task {
final _callback;
var _task;
Task(this._callback);
schedule() {
if (_task == null) {
_task = new async.Timer(const Duration(milliseconds: 50), () {
_task = null;
_callback();
});
}
}
}
final renderTask = new Task(this._render);
linesChanged() => renderTask.schedule();
widgetsChanged() => renderTask.schedule();
but this looks pretty broken. Maybe my Polymer element is architectured incorrectly (i.e. I have two attributes with widgets depending on lines)?
*Changed methods are definitely the right way to approach the problem. However, you're trying to force synchronicity in an async delivery system. Generally we encourage folks to observe property changes and react to them and not rely on methods being called in a specific order.
One thing you could use is an observe block. In that way, you could define a single callback for the two properties and react accordingly:
http://www.polymer-project.org/docs/polymer/polymer.html#observeblock
Polymer's data binding system does the least amount of work possible to rerender DOM. With the addition of Object.observe(), it's even faster. I'd have to see more about your element to understand what needs rendering but you might be creating a premature optimization.
I think there are three possible solutions:
See this: http://jsbin.com/nilim/3/edit
Use an observe block with one callback for multiple attributes (the callback will only be called once)
Create an additional attribute (i.e. isRender) that is set by the other two attributes (lines and widgets). Add a ChangeWatcher (i.e. isRenderChanged() in which you call your expensive render method)
Specify a flag (i.e. autoUpdate) that can be set to true or false. When autoUpdate = false you have to call the render method manually. If it is set to true then render() will be called automatically.
The disadvantage of solution 1 is that you can only have one behavior for all observed attributes. Sometimes you want to do different things when you set a specific attribute (i.e. size) before you call render. That's not possible with solution 1.
I don't think there is a better way. You may omit the 50ms delay (just Timer.run(() {...});) as the job gets scheduled behind the ongoing property changes anyway (my experience, not 100% sure though)
Lets say i have a UISegmentedSwitch for the User to set Metric or Imperial Measure
I could then test for its state in various part of the code,
but if the condition was what i thought it was, have i wasted my time (and cycles) in the asking?
In other languages I have normally set a variable/flag as a multiplier, the default being 1, ( no change as a result) and the other being what conversion is required ( e.g. 3.048 ).
that way there is no need to test, and if there are other things happening at the calculation its not an additional nesting of methods.
But does it get into global variable territory? Is it so bad if there is only one such flag even though it will be required in a number of places?
Perhaps I should create a custom class with just one property, or make it a property of the viewController, but is the cpu processing involved in all that just as taxing on battery life or UI responsiveness?
whats 'the usual' here?
There are those who believe that global variables are evil, and like most anything else, if they're abused they can be. But the idea that a variable like this shouldn't be made global is silly.
If you're going to be using it heavily and restricting it to read-only except for the one location, I'd forget the naysayers and go with it. If it isn't going to be that heavily referenced, you could make it a property that gets passed around from class to class, but that is a pain.
Another alternative is a singleton to hold "globals" as shown here:
http://maniacdev.com/2009/07/global-variables-in-iphone-objective-c/
IMO, the excitement about occasional use of globals is overdone. There are times and places where it just makes sense.
I think the "normal" here would be to use [NSUserDefaults standardUserDefaults] and have it persist.
You are making decisions in the code in other places based on this value. It would also seem likely you would like to have this value persist between uses of the App, so that their choice would be maintained.
Referring to it as [[NSUserDefaults standardUserDefaults] boolForKey:kUsesMetric]; is what would be "the norm" in my programming group.