为啥在我的结构中调用 self.init 之前使用了错误“self”?
Posted
技术标签:
【中文标题】为啥在我的结构中调用 self.init 之前使用了错误“self”?【英文标题】:Why am I getting the error 'self' used before self.init call in my struct?为什么在我的结构中调用 self.init 之前使用了错误“self”? 【发布时间】:2017-05-25 12:34:07 【问题描述】:我已经构建了这个struct
来处理我计划在一些自定义类中使用的特定类型的数据。
我的问题是 featureSubSet 变量能够成为少数枚举之一,当这个结构被初始化时,它不知道它将是哪个枚举,所以我将它声明为 Any。
当调用公共 init 时,它会适当地将数据汇集到所需的私有 init 方法中,以便它可以正确且完全地初始化。
我在公共 init 方法结束时收到错误,但我不知道如何让它消失。
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 ""
【问题讨论】:
你遇到了什么错误? 【参考方案1】:这是一种不正确的方法。如果您发现自己将某些内容存储为Any
,则几乎可以肯定您走错了路。探索这段代码很困难,因为它定义了许多其他类型,但是看着它,你不清楚为什么在这里需要Any
。 featureSubSet
始终是 CharacterFeatures
类型。枚举的所有值都是相同的“类型”。
这里有一个错误:
case featureCategoryList()[2]: //Skill Features
guard let newSkill = skill else
print("No skill")
return
这里:
default:
print("Somehow you picked something not on the list.")
break
这会在没有初始化 self
的情况下返回(这可能是您的问题)。如果您可能失败,那么您需要将其设为可选初始化程序 (init?
) 或抛出初始化程序,或者您需要在出错时调用 fatalError()
或类似的崩溃方法。你不能不初始化就返回。
不过,我强烈建议您重新设计它。我看不出参数应该是字符串的任何理由。与其传入"character"
并在某个表中查找,不如让调用者将.character
或.combat
作为枚举传递(您已经拥有枚举)。
注意,在 Swift 3 中,枚举大小写应始终以小写字母开头。
有点难以理解代码中发生了什么,但它看起来根本不应该是一个结构。它看起来像一个枚举。像这样的:
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)
或者,您可以在此处使用结构,尤其是当所有功能共享更多内容时:
struct Feature
enum Kind
case character(CharacterFeature, Effect)
case combat(CombatFeature, Effect)
case skill(Skill, Effect)
let kind: Kind
let effect: Effect
关键是您通常应该使用显式类型,而不是字符串。如果您发现自己需要的选项太多,那么您经常做错事。
【讨论】:
很好的答案!我只会添加使用String
的选项,作为枚举原始类型,如果他需要保留那些(讨厌的!)字符串用于其他目的 - 并且他希望对指定的命名进行一些控制使用的约定。
我其实完全同意。谢谢你的例子。不幸的是,这个错误让我发疯了,所以我还没有完成 switch 语句和私有 init 方法,但我使用 Any 作为 featureSubSet 的数据类型的原因是因为它可能是四种不同的枚举类型之一。使用您的替代方案,您建议在获取用户输入时如何处理初始化?我正在使用字符串通过适当的 init 方法序列对其进行过滤以完全初始化它,有什么更好的方法来做到这一点?
一般处理用户输入的方法是使枚举RawRepresentable
到String
。因此,您使用字符串初始化Kind
,然后将其传递给Feature
。这比将大量字符串传递给Feature
包含更多内容。如您所见,您避免使用枚举上的关联数据Any
。如果您可以举一个输入数据的示例以及您希望得到的结果,我相信我们可以构建一个示例。
好吧,用户将看到三到四个文本字段。两个或三个取决于第一个的结果,将通过 Popover 呈现一个 tableview 以选择一个选项。但是一个必须是一个字符串。 Effect 最终将成为一个接收字符串并将其转换为掷骰子计算公式的类。第一个输入将指示“种类”,第二个输入将指示“特征”,如果“特征”属于某些类型,它将为您提供另一个类别可供选择。因此,所涉及的数据类型将是 2 到 3 个枚举和一个字符串。我不确定这是否能更好地解释它。【参考方案2】:
假设featureCategoryList
是struct Feature
函数,你原来的错误:
self
在self.init
调用之前使用
可能来自以下几行:
case featureCategoryList()[0]:
...
case featureCategoryList()[1]:
...
case featureCategoryList()[2]:
因为您在初始化之前隐式调用了self
。
修复上述错误后,您还需要修复这些错误:
self.init
在从初始化程序返回之前不会在所有路径上调用
查看 Rob 的回答,了解一些不错的选择。
【讨论】:
以上是关于为啥在我的结构中调用 self.init 之前使用了错误“self”?的主要内容,如果未能解决你的问题,请参考以下文章
为啥在我的视图被推送到导航堆栈之前我的 UIAlertView 没有在屏幕上消失?
为啥当我使用 presentModelViewController 时未在我的 UITabBArController 中调用 viewWillAppear?