首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在Swift子类中添加方便的初始化器

在Swift子类中添加方便的初始化器
EN

Stack Overflow用户
提问于 2014-06-23 18:46:12
回答 4查看 17.6K关注 0票数 23

作为一个学习练习,我试图实现SKShapeNode的一个子类,它提供了一个新的方便初始化器,它接受一个数字,并构造一个ShapeNode,它是一个数字、宽度和高度的平方。

根据Swift Book

规则1 如果您的子类没有定义任何指定的初始化器,则它会自动继承其所有指定的超类初始化器。 规则2 如果您的子类提供了它指定的所有超类初始化器的实现--或者按照规则1继承它们,或者提供自定义实现作为其定义的一部分--那么它将自动继承所有超类方便初始化器。“

但是,下面的类无法工作:

代码语言:javascript
复制
class MyShapeNode : SKShapeNode {
    convenience init(squareOfSize value: CGFloat) {
        self.init(rectOfSize: CGSizeMake(value, value))
    }
}

相反,我得到了:

代码语言:javascript
复制
Playground execution failed: error: <REPL>:34:9: error: use of 'self' in delegating initializer before self.init is called
        self.init(rectOfSize: CGSizeMake(value, value))
    ^
<REPL>:34:14: error: use of 'self' in delegating initializer before self.init is called
    self.init(rectOfSize: CGSizeMake(value, value))
         ^
<REPL>:35:5: error: self.init isn't called on all paths in delegating initializer
}

我的理解是,MyShapeNode应该继承SKShapeNode的所有方便初始化器,因为我没有实现自己指定的任何初始化器,而且由于我的方便初始化器调用了另一个方便初始化器init(rectOfSize),这应该有效。我做错了什么?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2014-06-23 19:30:03

我对初始化器继承的理解和您的理解是一样的,我认为我们都与书中的内容很好地一致。我不认为这是解释问题,也不是对既定规则的误解。也就是说,我不认为你做错了什么。

我在一个游乐场中测试了以下内容,它的工作原理与预期一样:

代码语言:javascript
复制
class RectShape: NSObject {
    var size = CGSize(width: 0, height: 0)
    convenience init(rectOfSize size: CGSize) {
        self.init()
        self.size = size
    }
}

class SquareShape: RectShape {
    convenience init(squareOfSize size: CGFloat) {
        self.init(rectOfSize: CGSize(width: size, height: size))
    }
}

RectShape继承自NSObject,不定义任何指定的初始化器。因此,按照规则1,它继承了NSObject的所有指定初始化器。在为意图进行设置之前,实现中提供的方便初始化器I将正确地委托给指定的初始化器。

SquareShape继承自RectShape,不提供指定的初始化程序,而且按照规则1,它继承了SquareShape的所有指定初始化器。按照规则2,它还继承了RectShape中定义的方便初始化器。最后,SquareShape中定义的方便初始化器通过继承的方便初始化器正确地委托给继承的指定初始化器,后者又将继承的指定初始化器委托给继承的指定初始化器。

因此,考虑到你没有做错什么,而且我的例子如预期的那样有效,我推断出以下假设:

由于SKShapeNode是用Objective编写的,所以该语言没有强制执行“每个方便的初始化程序都必须从同一个类调用另一个初始化器”的规则。因此,可能SKShapeNode的方便初始化器实际上没有调用指定的初始化器。因此,即使子类MyShapeNode按预期继承了方便的初始化器,它们也没有正确地委托给继承的指定初始化器。

但是,再说一遍,这只是一个假设。我所能确定的是,在我自己创建的两个类上,力学就像预期的那样工作。

票数 15
EN

Stack Overflow用户

发布于 2014-07-02 16:54:38

这里有两个问题:

  • SKShapeNode只有一个指定的初始化程序:init()。这意味着,如果不调用init(),我们就无法脱离初始化程序。
  • SKShapeNode有一个属性path声明为CGPath!。这意味着,如果不以某种方式初始化path,我们就不想退出初始化程序。

这两件事的结合是问题的根源。简而言之,SKShapeNode写得不正确。它有一个必须初始化的属性path;因此,它应该有一个指定的初始化器来设置path。但事实并非如此(它的所有path-setting初始化器都是方便的初始化器)。那是窃听器。换句话说,问题的根源在于,不管方便与否,shapeNodeWith...方法根本不是真正的初始化器。

不过,您可以按照这两种顺序来完成您想做的事情--编写一个方便的初始化程序而不必编写任何其他初始化器--即按照以下方式编写:

代码语言:javascript
复制
class MyShapeNode : SKShapeNode {
    convenience init(squareOfSize value: CGFloat) {
        self.init()
        self.init(rectOfSize: CGSizeMake(value, value))
    }
}

这看起来是非法的,但事实并非如此。一旦我们调用了self.init(),我们就满足了第一个需求,现在我们可以自由地引用self (在self.init被称为“error”之前,我们不再在委托初始化器时使用'self‘)并满足第二个要求。

票数 26
EN

Stack Overflow用户

发布于 2017-02-22 09:09:31

在Matt的回答的基础上,我们必须包含一个额外的函数,否则编译器会抱怨调用一个没有参数的初始化程序。

下面是子类SKShapeNode的工作原理:

代码语言:javascript
复制
class CircleNode : SKShapeNode {

    override init() {
        super.init()
    }

    convenience init(width: CGFloat, point: CGPoint) {
        self.init()
        self.init(circleOfRadius: width/2)
        // Do stuff
     }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}
票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/24373142

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档