Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ChartViewBase cleanup #3034

Closed
wants to merge 16 commits into from
Closed

ChartViewBase cleanup #3034

wants to merge 16 commits into from

Conversation

jjatie
Copy link
Collaborator

@jjatie jjatie commented Nov 23, 2017

For the most part, condensing logic and using guard where appropriate
Removed optionality of many internal variables as they were only optional to allow for deferred initialization. This is now replaced with lazy vars.
Removed empty initializer overrides.
fileprivate is now private

@codecov-io
Copy link

codecov-io commented Nov 23, 2017

Codecov Report

Merging #3034 into 4.0.0 will decrease coverage by 0.01%.
The diff coverage is 27.69%.

Impacted file tree graph

@@            Coverage Diff            @@
##           4.0.0    #3034      +/-   ##
=========================================
- Coverage   20.9%   20.88%   -0.02%     
=========================================
  Files        111      111              
  Lines      15458    15390      -68     
  Branches     250      251       +1     
=========================================
- Hits        3231     3214      -17     
+ Misses     12187    12136      -51     
  Partials      40       40
Impacted Files Coverage Δ
Source/Charts/Charts/RadarChartView.swift 0% <0%> (ø) ⬆️
Source/Charts/Charts/PieRadarChartViewBase.swift 0% <0%> (ø) ⬆️
Source/Charts/Charts/BarLineChartViewBase.swift 22.52% <100%> (-0.04%) ⬇️
Source/Charts/Charts/ChartViewBase.swift 21.81% <27.11%> (-0.33%) ⬇️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update e126844...c35d469. Read the comment docs.


/// This property is deprecated - Use `chartDescription.text` instead.
@objc @available(*, deprecated: 1.0, message: "Use `chartDescription.text` instead.")
open var descriptionText: String
{
get { return chartDescription?.text ?? "" }
set { chartDescription?.text = newValue }
get { return chartDescription.text ?? "" }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it seems we have a future conflict that these will be removed, but we change it now?
I'm not sure if we should merge #2996 into master now or for 4.0. I don't think it's worthy to refactor what will be removed

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It’s not a big deal though, and I will likely be the one handling merge conflicts. In this case, these deprecations need to be changed in order for the project to build.

I think we should merge into master, and I’ll handle any merge conflicts when we merge into 4.0 in the future.

Copy link
Member

@liuxuan30 liuxuan30 Dec 18, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have merged #2996 to make things easier.
btw, I need to think about if changing to lazy fits. something like description or empty texts should be released if not used later, not retaining all the time (though memory pressure is no longer a thing, but we should keep a good habit?)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Conflicts are resolved

@@ -500,8 +463,7 @@ open class ChartViewBase: NSUIView, ChartDataProvider, AnimatorDelegate
/// - parameter callDelegate: Should the delegate be called for this change
@objc open func highlightValue(x: Double, y: Double, dataSetIndex: Int, callDelegate: Bool)
{
guard let data = _data else
{
guard let data = _data else {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

code style is make { a separate line

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

@@ -443,19 +410,15 @@ open class ChartViewBase: NSUIView, ChartDataProvider, AnimatorDelegate
/// null or an empty array to undo all highlighting.
/// This should be used to programmatically highlight values.
/// This method *will not* call the delegate.
@objc open func highlightValues(_ highs: [Highlight]?)
@objc open func highlightValues(_ highs: [Highlight])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I remember highlight objects are allowed to be nil

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reverted

@liuxuan30 liuxuan30 self-assigned this Dec 18, 2017
}
_indicesToHighlight = highs ?? []

lastHighlighted = _indicesToHighlight.isEmpty
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one line is enough for ?: (code style here just uses one line)

if entry == nil
{
h = nil
var high = highlight
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm feeling this rewrite makes harder to understand the logic (the guard else{} part). If we cannot find a better one, I suggest add simple comment here.

@@ -519,7 +480,7 @@ open class ChartViewBase: NSUIView, ChartDataProvider, AnimatorDelegate
/// CandleStick-Chart.
@objc open func getHighlightByTouchPoint(_ pt: CGPoint) -> Highlight?
{
if _data === nil
guard _data != nil else
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not feeling guard is better here.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The convention is as the Swift Book states:

You use a guard statement to require that a condition must be true in order for the code after the guard statement to be executed.

While technically it doesn't matter if we use an if or a guard, the guard does make it clear that we need a condition to be true to continue.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I agree with @jjatie on this one - we are used to C-style languages, while Swift does not aim at being one... For Swift it's more natural to put a guard

{
continue
}
guard entryIndex <= Int(Double(set.entryCount) * _animator.phaseX) else { continue }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is guard in swift as fast as if, in terms of assembling code? I'm feeling we are using lots of guard, when it just means if condition. If guard is slower than if, I would rather not to use too many.

Copy link
Collaborator Author

@jjatie jjatie Dec 24, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They compile the same. I think you're just not used to seeing guard yet since it isn't in objc.

The convention is as the Swift Book states:

You use a guard statement to require that a condition must be true in order for the code after the guard statement to be executed.

While technically it doesn't matter if we use an if or a guard, the guard does make it clear that we need a condition to be true to continue.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most of what you know as "optionals", and stuff that work with optionals, and guards and stuff - are compile time. You want to be sure that something is not null and unwrap it, and unwrapping does not mean that you have more code there - it just means that the compiler trusts the non-null object and allows you to refer to it without the ? operator

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I have time, I would create a sample app and check what guard and if implementation looks like in asm code. Ideally should not "that" impact the performance. I was just obsessed a little recently about the asm code 😂

{
val = 0.999
switch newValue {
case ..<0.0: _dragDecelerationFrictionCoef = 0
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

where can I find this magic definition.. I just can find things like case 1..<5: in the manual.

Copy link
Collaborator Author

@jjatie jjatie Dec 24, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One Sided Ranges are new in Swift 4.

#endif

_animator = Animator()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so if we uses lazy, how do we override the property in subclass to a new class object? e.g some users may write their own animator class, or XAxis class, and just override initialize() to replace them.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They are still able to do this exactly the same as they have before.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then we should add some comments/notes that people should override initialize() to replace the objects with their classes?

Copy link
Collaborator Author

@jjatie jjatie Dec 28, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why? We never did before. As far as the consumer is concerned, nothing has changed other than it is no longer an implicitly unwrapped optional. Swift initialization already works that way where you must override the initializer to provide a different default value for a stored property.

liuxuan30 and others added 4 commits December 25, 2017 09:10
* fix #1830. credit from #2049

* add combined chart unit tests for iOS, tvOS (macOS only have build process)

* use iterater rather than index
* Removed redundant ivars in favour of proper access control

* Moved initialization of axes to their declaration to keep the same optionality exposed.
jjatie and others added 2 commits December 27, 2017 21:29
* Replaced relevant `ChartUtils` methods with `Double` extensions

Improves readability.
`nextUp` is built in and provides the same functionality.

* Updated `ChartUtilsTests` to match changes
* add option to build demo projects unit tests on iOS

* add ChartsDemo-OSX build test.
@liuxuan30
Copy link
Member

@jjatie I'm confused. We have a card for PRs merged to master, and 4.0 card merge to 4.0 branch. You moved most of them from master to 4.0 card, shall we change the branch?

@jjatie
Copy link
Collaborator Author

jjatie commented Dec 28, 2017

Yep! I missed a couple I guess. Things will be easier if I just move them to 4.0 and they aren't adding/changing functionality so they can wait until 4.0

@jjatie jjatie changed the base branch from master to 4.0.0 December 28, 2017 02:37
@liuxuan30
Copy link
Member

alright, one last comment. do you think any chance anyone would nil out some of those old optionals? Like legend.
Corner case: Someone displays legend and later want to remove it, rather than disable, he would like to nil legend out (like to save memory)

@jjatie
Copy link
Collaborator Author

jjatie commented Dec 28, 2017

You're looking at the internal properties. The consumer facing properties were already non-optional.

@liuxuan30
Copy link
Member

Let's try the new tests then. looks good to me


/// object responsible for animations
internal var _animator: Animator!
internal lazy var _animator: Animator = {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

code style for blocks? { another line?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess so?


attrs[NSAttributedStringKey.font] = description.font
attrs[NSAttributedStringKey.foregroundColor] = description.textColor
let attrs: [NSAttributedStringKey : Any] = [
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how about [

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking through the rest of library, [ and ( seems to be on the same line.

h = nil
var high = highlight
guard
let h = high,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we use single let here

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately, no. I tried, but couldn't find a way because we need to assign the original highlight.

guard
let h = high,
let entry = _data?.entryForHighlight(h)
else {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry about missing these code style, { another line

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought we agreed this was the style for multiline guard statements?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh is it? sorry don't remember.

{
_indicesToHighlight = [h!]
}
if callDelegate {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry about missing these code style, { another line

// set the indices to highlight
_indicesToHighlight = [h]

if callDelegate {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry about missing these code style, { another line

if val < 0.0
{
val = 0.0
switch newValue {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

{ another line or?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess so. Seems weird to me on switch statements.

@liuxuan30
Copy link
Member

@jjatie looks like these commits are no with latest rake file. Feel free to just test on your side or merge master(like practice rebase)

@jjatie
Copy link
Collaborator Author

jjatie commented Dec 28, 2017

Oops! Fixing now.

@liuxuan30
Copy link
Member

any idea why the UT is not latest?

@jjatie
Copy link
Collaborator Author

jjatie commented Dec 29, 2017

4.0.0 is out of sync with master

@liuxuan30
Copy link
Member

please merge and rebase on master, once the CI passed, this can be merged I think.

jjatie and others added 8 commits January 2, 2018 22:00
For the most part, condensing logic and using `guard` where appropriate
Removed optionality of many internal variables as they were only optional to allow for deferred initialization. This is now replaced with lazy vars.
Removed empty initializer overrides.
`fileprivate` is now `private`
* Renamed `IMarker` to `Marker`

following Swift API guidelines.

* Renamed `IAxisValueFormatter` to `AxisValueFormatter`

* Renamed `IFillFormatter` to `FillFormatter`

* Renamed `IValueFormatter` to `ValueFormatter`

* Renamed `IHighlighter` to `Highlighter`

* Renamed `I*DataSet` to `*DataSetProtocol` to follow Swift API guidelines

* Fixed naming of `LineRadarChartDataSetProtocol` and `RadarChartDataSetProtocol` from previous commit

* Renamed "Interfaces" to "DataProviders" for clarity

* Updated Demos to for new type naming
* Renderer is now a protocol

Renamed Renderers, and organized the Renderer folder.

* DataRenderer is now a protocol

* AxisRenderer is now a protocol
@jjatie
Copy link
Collaborator Author

jjatie commented Jan 3, 2018

I still don't understand how you want me to rebase 4.0.0 branch since I can't push it up without review. I rebased this PR, but obviously 4.0.0 has not been rebased.

Also, I noticed that when I rebased from master, the merging took many old commits that I had to manually correct whereas pulling master did not. Very frustrating.

@liuxuan30
Copy link
Member

liuxuan30 commented Jan 3, 2018

Oh I see. If you see the old conflicts you already resolved but once again appear when you rebase, you are on the "right rebase way" I'm talking about, and yes, it's frustrating.

What I meant in the other thread is, I hope you no longer need to have those "merging from upstream master..." commits in your commit log by using rebase.

When you rebase, the old conflicts you resolved will jump again, and if it's easy to fix again, just continue. If it's a lot of burden, let's simply pull master, and then we squash the commits when we want to merge the pull requests on github page.

The whole point using rebase with this project is to squash the commits into one or remove useless commits before filing the PR or updating the PR. The purpose is to make the project commit logs simple and easy to search.

Hope this clarify? For this PR, I saw conflicts now, you can just revert back to the commit you think is all good and pull master then, let CI pass and click "squash and merge", don't need to rebase then.

@jjatie
Copy link
Collaborator Author

jjatie commented Jan 3, 2018

You can't undo a rebase like this.

I figured out what my problem is with the rebasing in this case. You can't rebase from two different branches at the same time which is what we need to do for PRs going into 4.0.0. You can either rebase from master OR 4.0.0, not both. In order for rebasing to work here, 4.0.0 needs to be regularly rebased from master, and then PRs for 4.0.0 need to rebase off the freshly rebased 4.0.0. The problem with this is that there is no way rebase 4.0.0 without review.

Most guides will tell you that you should never rebase a branch someone else might touch, which in this case is the 4.0.0 branch. While I disagree with rebasing in general because you lose history, I'm okay doing it for PR branches. If we are going to rebase, all PRs should be rebasing from the branch they are PRing into. I'll create an issue about this and we can update the docs from there for future PRs to be accepted.

This PR is garbage now, but luckily #3045 includes all the changes I made here. I will update that PR with the current 4.0.0. They should have been the same PR in the first place, but I wasn't sure what changes might be accepted at the time I made them.

@jjatie jjatie closed this Jan 3, 2018
@liuxuan30
Copy link
Member

liuxuan30 commented Jan 4, 2018

You can't undo a rebase like this.

to clarify, can't rebase abort action plus git reset --harddo the job?

@jjatie
Copy link
Collaborator Author

jjatie commented Jan 4, 2018

Not when you need to rebase from multiple branches

@jjatie jjatie deleted the chartviewbase-cleanup branch January 6, 2018 10:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants