Reputation: 95
I've built this struct
to handle a specific type of data I plan on using in some custom classes.
My issue is that featureSubSet variable is capable of being one of a few enums, and when this struct is initialized it wont know which enum it will be, so I declared it as Any.
When the public init is called, it will appropriately funnel the data to the needed private init method so that it can properly and fully be initialized.
I get the error at the end of the public init method, but I'm not sure how to get it to go away.
struct Feature {
//MARK: Variables needed for Feature
var featureSet: FeatureType
var featureSubSet: Any
var effect: String
var active: Bool?
var skill: Skill?
var ability: Ability?
public init(base: String, sub: String, effect: String, skill: Skill? = nil, ability: Ability? = nil) {
switch base {
case featureCategoryList()[0]: // Character Features
self.init(CharacterFeature: sub, effect: effect)
case featureCategoryList()[1]: // Combat Features
self.init(CombatFeature: sub, effect: effect)
case featureCategoryList()[2]: //Skill Features
guard let newSkill = skill else {
print("No skill")
return
}
self.init(SkillFeature: sub, effect: effect, skill: newSkill)
default:
print("Somehow you picked something not on the list.")
break
}
}
private init(CharacterFeature sub: String, effect: String) {
self.featureSet = .CharacterFeatures
self.featureSubSet = CharacterFeatures.init(rawValue: sub)!
self.effect = effect
}
private init(CombatFeature sub: String, effect: String) {
self.featureSet = .CombatFeatures
self.featureSubSet = CharacterFeatures.init(rawValue: sub)!
self.effect = effect
}
private init(SkillFeature sub: String, effect: String, skill: Skill) {
self.featureSet = .SkillFeatures
self.featureSubSet = CharacterFeatures.init(rawValue: sub)!
self.skill = skill
self.effect = effect
}
//MARK: Feature functions
func string() -> String {
//TODO: Make a string output for what the feature is.
return ""
}
}
Upvotes: 3
Views: 1959
Reputation: 19349
Assuming featureCategoryList
is a struct Feature
function, your original error:
self
used beforeself.init
call
might be coming from this lines:
case featureCategoryList()[0]:
...
case featureCategoryList()[1]:
...
case featureCategoryList()[2]:
since you are implicitly calling self
before initialization.
After fixing the above error, you will also need to fix these as well:
self.init
isn't called on all paths before returning from initializer
Check out Rob's answer for some great alternatives.
Upvotes: 0
Reputation: 299565
This is an incorrect approach. If you find yourself storing something as Any
, you're almost certainly on the wrong path. It's difficult to explore this code because it defines so many other types, but looking at it, it's unclear why you've needed Any
here. featureSubSet
is always of type CharacterFeatures
. All the values of an enum are the same "type."
You have an error here:
case featureCategoryList()[2]: //Skill Features
guard let newSkill = skill else {
print("No skill")
return
}
And here:
default:
print("Somehow you picked something not on the list.")
break
}
This returns without initializing self
(and is probably your issue). If you can fail, then you need to make this an optional initializer (init?
) or a throwing initializer, or you need to call fatalError()
or similar crashing method on error. You can't just return without initializing.
I highly recommend that you redesign this, however. I don't see any reason that the parameters should be strings. Rather than passing in "character"
and looking that up in some table, have the caller pass .character
or .combat
as an enum (you already have the enum).
Note in Swift 3, enum cases should always begin with a lowercase letter.
It's a little hard to understand what's going on in your code, but it doesn't really look like it should be a struct at all. It looks like an enum. Something like this:
enum CharacterFeature {
// Features for characters
}
enum CombatFeature {
// Features for combat
}
enum Skill {
// skills
}
enum Effect {
// effects
}
enum Feature {
case character(CharacterFeature, Effect)
case combat(CombatFeature, Effect)
case skill(Skill, Effect)
}
Alternately, you could use a struct here, especially if there are more things that are shared by all features:
struct Feature {
enum Kind {
case character(CharacterFeature, Effect)
case combat(CombatFeature, Effect)
case skill(Skill, Effect)
}
let kind: Kind
let effect: Effect
}
The key point is that you should generally work in explicit types, not strings. If you find yourself needing a too many optionals, you're often doing something incorrectly.
Upvotes: 3