Ios 类不实现其超类';这是必需的成员
所以我今天更新到Xcode 6 beta 5,注意到我在苹果类的几乎所有子类中都收到了错误 错误状态为: 类“x”未实现其超类的必需成员 这里是我选择的一个例子,因为这个类目前非常轻量级,所以很容易发布Ios 类不实现其超类';这是必需的成员,ios,swift,sprite-kit,Ios,Swift,Sprite Kit,所以我今天更新到Xcode 6 beta 5,注意到我在苹果类的几乎所有子类中都收到了错误 错误状态为: 类“x”未实现其超类的必需成员 这里是我选择的一个例子,因为这个类目前非常轻量级,所以很容易发布 class InfoBar: SKSpriteNode { //Error message here let team: Team let healthBar: SKSpriteNode init(team: Team, size: CGSize) {
class InfoBar: SKSpriteNode { //Error message here
let team: Team
let healthBar: SKSpriteNode
init(team: Team, size: CGSize) {
self.team = team
if self.team == Team.TeamGood {
healthBar = SKSpriteNode(color: UIColor.greenColor(), size:size)
}
else {
healthBar = SKSpriteNode(color: UIColor.redColor(), size:size)
}
super.init(texture:nil, color: UIColor.darkGrayColor(), size: size)
self.addChild(healthBar)
}
}
所以我的问题是,为什么我会收到这个错误,我该如何修复它?我没有实施的是什么?我正在呼叫指定的初始值设定者。添加
required init(coder aDecoder: NSCoder!) {
super.init(coder: aDecoder)
}
来自开发者论坛上的苹果员工: “一种向编译器和编译程序声明 如果不想与NSCoding兼容,请执行以下操作: 如果您知道您不想遵守NSCoding,这是一个选项。我在很多SpriteKit代码中采用了这种方法,因为我知道我不会从故事板加载它
您可以采取的另一个非常有效的方法是将该方法实现为方便的init,如下所示:
convenience required init(coder: NSCoder) {
self.init(stringParam: "", intParam: 5)
}
注意self
中对初始值设定项的调用。这允许您只需为参数使用伪值,而不是所有非可选属性,同时避免抛出致命错误
当然,第三个选项是在调用super时实现该方法,并初始化所有非可选属性。如果对象是从情节提要加载的视图,则应采用这种方法:
required init(coder aDecoder: NSCoder!) {
foo = "some string"
bar = 9001
super.init(coder: aDecoder)
}
为什么会出现这个问题?好的,显而易见的事实是,处理您的类不准备处理的初始值设定项一直很重要(例如,在Objective-C中,从我开始在MacOSX10.0中编程Cocoa的那天起)。文件中对您在这方面的责任一直非常清楚。但是,我们当中有多少人不厌其烦地完全、不折不扣地完成这些任务呢?可能我们都没有!编译器没有强制执行它们;这完全是传统的 例如,在具有此指定初始值设定项的my Objective-C view controller子类中:
- (instancetype) initWithCollection: (MPMediaItemCollection*) coll;
…向我们传递一个实际的媒体项集合是至关重要的:没有一个实例,该实例就无法存在。但是我没有写“阻止器”来阻止有人用裸骨init
来初始化我。我应该写一个(实际上,正确地说,我应该写一个initWithNibName:bundle:
,继承的指定初始值设定项的实现);但我懒得去打扰,因为我“知道”我永远不会以这种方式错误地初始化自己的类。这留下了一个大洞。在Objective-C中,有人可以调用裸骨init
,使我的IVAR处于未初始化状态,因此我们没有划桨
在大多数情况下,斯威夫特奇妙地把我从自己身边救了出来。我一把这个应用程序翻译成Swift,整个问题就消失了。斯威夫特有效地为我创造了一个塞子!如果init(collection:mpmediateitemcollection)
是类中声明的唯一指定初始值设定项,则无法通过调用基本init()
来初始化我。这是个奇迹
seed 5中发生的事情仅仅是编译器已经意识到奇迹在
init(coder:)
的情况下不起作用,因为理论上这个类的实例可能来自nib,而编译器无法阻止——当nib加载时,将调用init(coder:)
。因此,编译器让您显式地编写stopper。也非常正确。现有答案中缺少两条绝对重要的Swift特定信息,我认为这有助于彻底澄清这一点
required
关键字标记该初始值设定项init
方法的特殊继承规则Swift有一套关于
init
方法的特殊继承规则。
我知道这是我提出的两点中的第二点,但我们无法理解第一点,或者在理解这一点之前,required
关键字为什么存在。一旦我们理解了这一点,另一点就变得非常明显
我在本答案的这一部分中介绍的所有信息都来自苹果公司的文档
从苹果文档:
与Objective-C中的子类不同,默认情况下,Swift子类不会继承它们的超类初始值设定项。Swift的方法防止了这样一种情况:来自超类的简单初始值设定项被更专门的子类继承,并用于创建未完全或正确初始化的子类的新实例
我的
因此,直接从Apple文档中,我们可以看到Swift子类并不总是(通常不会)继承其超类的init
方法
那么,它们何时从超类继承?
有两个规则定义子类何时从其父类继承init
方法。从苹果文档:
规则1
如果您的子类没有定义任何指定的初始值设定项,它将自动继承其所有超类指定的初始值设定项
规则2
如果您的子类通过按照规则1继承其所有超类指定的初始值设定项,或者通过按照规则p提供自定义实现来提供其所有超类指定初始值设定项的实现
- (instancetype) initWithCollection: (MPMediaItemCollection*) coll;
class Foo {
var foo: String
init(foo: String) {
self.foo = foo
}
}
class Bar: Foo {
var bar: String
init(foo: String, bar: String) {
self.bar = bar
super.init(foo: foo)
}
}
let x = Bar(foo: "Foo")
class Bar: Foo {
var bar: String
}
protocol InitProtocol {
init(foo: Int)
}
class ConformingClass: InitProtocol {
var foo: Int
init(foo: Int) {
self.foo = foo
}
}
class Box {
var size: CGSize
init(size: CGSize) {
self.size = size
}
class func factory() -> Self {
return self.init(size: CGSizeZero)
}
}
class Foo {
init(a: Int, b: Int, c: Int) {
// do nothing
}
}
class Bar: Foo {
init(string: String) {
super.init(a: 0, b: 1, c: 2)
// do more nothing
}
}
let f = Foo(a: 0, b: 1, c: 2)
let b = Bar(a: 0, b: 1, c: 2)