此文章同时提供中文版本:TinySolution:解决enum的限制
Swift’s enum
is much more powerful than Objective-C. We can create case values based on various types with different parameters, which are useful in situations where different states or objects have distinct data types. For example the Result
type is very useful.
BTW:
Result
type would be official supported in Swift5. (SE-0235)
Although enum
is powerful, there are some restrictions. For example, we often need to draw two lines, solid and dashed, with custom line width. At this time we can implement this with enum
.
Things never be that simple in the real project
In addition to the line width, the dash line needs to support custom width of dash and space. Of cause we can change Line
to the following format:
The problem is solved, but most of the dash lines use the same width of dash and space. We don’t want to manually pass the same value every time, so we try to use the default parameters:
Unfortunately, the compiler tells us that enum
does not support the default parameters. But we had this limitation with Objective-C for long time and we are familiar with how to implement the default parameters in other way. So we changed to this:
The compiler tells us everything works. The creation of the three case
objects is also successful. So the problem is solved? At least it seems to be the case.
Strange phenomenon
When you start writing the switch
method, things just not work as your expect. For example, I added a method of output()
and a warning appeared:
It seems like the previous case dash(...)
contains all the cases of the latter one. Considering that, let’s exchange it:
However, the same warning is still appear. It seems those two case dash(...)
are exactly same for the compiler, so we can’t find out the exact case
.
If this is all the problem, this kind of implementation still useful in some situations. Unfortunately, it isn’t. Let’s write a few tests based on the last implement of Line
:
You can see that Line.dash(width:1)
is judged as default
and does not belong to Line.dash
. So this kind of implement is already be an exception. The latter case
will overwrite the former one. The former one can only be created and not be judged by switch
, so basically this case
is useless.
Maybe this is a Swift bug? Please tell me if you know.
Solution
Since this is TinySolution, we certainly have to give a solution to the problem. As simple implementation we can manually create a static func dash
to replace the case dash(width: Float)
like this:
Then we can correctly output and judge our Line
object:
However, mixing the automatic generate initialization methods and manual create initialization methods is always a bit impure, especially if some configuration needs to be performed during initialization, the flexibility of the those initialization method is inconsistent. Because if we try to override the automatically generated static method, there will be a redeclaration error:
Better solution
Of course, since we can define an initialization method, we can change the case
name and create all the initialization methods ourselves. But in this case there are two sets of initialization methods mixed and have different behavior, which is not good. And this object is still enum
, when we switch
it we will see a set of cases that are completely inconsistent with the initialization.
I think this is not a good solution, so I recommend another clearer implementation like this:
First, we wrap the original enum Line
with a struct Line
. To prevent the name conflict we change the name of the enum Line
to enum Content
. So the struct
object holds the enum
object. Then we extract all method of enum
to the struct
layer and add static func
to achieve enum creation effect. Because it is a static func
, our default parameters can be use again. After all these changes we still won’t need to modify the creation code of the previous enum
object, they just work.
- All code in this article can be found in the GitHub project.
- If you have questions or suggestions, welcome to leave comment for discuss.
- If you feel this article is valuable, please forward it so more people can see it.
- If you like this type of content, welcome to follow my Medium and Twitter, I will keep posting useful content for everyone.