Ios 类不实现其超类';这是必需的成员

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) {

所以我今天更新到Xcode 6 beta 5,注意到我在苹果类的几乎所有子类中都收到了错误

错误状态为:

类“x”未实现其超类的必需成员

这里是我选择的一个例子,因为这个类目前非常轻量级,所以很容易发布

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特定信息,我认为这有助于彻底澄清这一点

  • 如果协议将初始值设定项指定为必需的方法,则必须使用Swift的
    required
    关键字标记该初始值设定项
  • Swift有一套关于
    init
    方法的特殊继承规则
  • tl;dr这是:

    如果实现任何初始值设定项,则不再继承任何超类的指定初始值设定项

    您将继承的唯一初始值设定项(如果有)是超类便利初始值设定项,它指向您碰巧重写的指定初始值设定项

    所以。。。准备好长版本了吗


    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)