当前位置: 首页 > 面试题库 >

如何在Swift中在没有代码重复的情况下实现具有相同内容的两个init?

雍马鲁
2023-03-14
问题内容

假定派生自UIView以下类的类:

class MyView: UIView {
    var myImageView: UIImageView

    init(frame: CGRect) {
        super.init(frame: frame)
    }

    init(coder aDecoder: NSCoder!) {
        super.init(coder: aDecoder)
    }

    ...

如果我想在两个初始化器中都使用相同的代码,例如

self.myImageView = UIImageView(frame: CGRectZero)
self.myImageView.contentMode = UIViewContentMode.ScaleAspectFill

并且 不要 在类实现中 重复 两次 该代码 ,我将如何构造init方法?

尝试的方法:

  • 创建一个func commonInit()super.init-> Swift编译器myImageView在调用之前给出有关未初始化变量的错误之后调用的方法super.init
  • func commonInit()之前的调用super.init显然失败,并出现编译器错误 “ super.init调用之前使用了’self’

问题答案:

正如GoZoner所说,将变量标记为可选将起作用。这不是一种非常优雅的方法,因为您每次访问该值时都必须解开该值。

我将向Apple提出增强请求,也许我们可以得到类似“
beforeInit”方法的信息,该方法在每次可以分配变量的init之前调用,因此我们不必使用可选的var。

在此之前,我将所有分配都放到commonInit方法中,该方法从专用的初始化程序中调用。例如:

class GradientView: UIView {
    var gradientLayer: CAGradientLayer?  // marked as optional, so it does not have to be assigned before super.init

    func commonInit() {
        gradientLayer = CAGradientLayer()
        gradientLayer!.frame = self.bounds
        // more setup 
    }

    init(coder aDecoder: NSCoder!)  {
        super.init(coder: aDecoder)
        commonInit()
    }

     init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        gradientLayer!.frame = self.bounds  // unwrap explicitly because the var is marked optional
    }
}

多亏了戴维(David),我再次看了一本书,发现了一些不必使用可选变量hack就能对重复数据删除工作有所帮助的东西。可以使用闭包来初始化变量。

使用闭包或函数设置默认属性值

如果存储的属性的默认值需要一些自定义或设置,则可以使用闭包或全局函数为该属性提供自定义的默认值。每当初始化属性所属类型的新实例时,都会调用闭包或函数,并将其返回值分配为属性的默认值。这些类型的闭包或函数通常会创建与属性相同类型的临时值,定制该值以表示所需的初始状态,然后返回该临时值以用作属性的默认值。

这是有关如何使用闭包提供默认属性值的框架概述:

class SomeClass {
let someProperty: SomeType = {
    // create a default value for someProperty inside this closure
    // someValue must be of the same type as SomeType
    return someValue
    }()
}

请注意,闭包的末大括号后跟一对空括号。这告诉Swift立刻执行关闭。如果省略这些括号,则尝试将闭包本身分配给属性,而不是闭包的返回值。

注意

如果使用闭包来初始化属性,请记住在执行闭包时实例的其余部分尚未初始化。这意味着您无法从闭包内部访问任何其他属性值,即使这些属性具有默认值也是如此。您也不能使用隐式的self属性,或调用实例的任何方法。

摘录自:苹果公司“ The Swift Programming
Language”。iBooks。https://itun.es/de/jEUH0.l

从现在开始,我将使用这种方式,因为它不会绕过不允许对变量使用nil的有用功能。对于我的示例,它将如下所示:

class GradientView: UIView {
    var gradientLayer: CAGradientLayer = {
        return CAGradientLayer()
    }()

    func commonInit() {
        gradientLayer.frame = self.bounds
        /* more setup */
    }

    init(coder aDecoder: NSCoder!)  {
        super.init(coder: aDecoder)
        commonInit()
    }

    init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
}


 类似资料:
  • 所以我在和烦人的问题作斗争。我想同时运行2个动画,但如果没有: 这让一切都变得波涛汹涌,我想要根除这一点。 当我在两个动画控制器中删除并运行此函数时: 它只运行第一个动画控制器,而不运行第二个。动画是简单的tween,彼此相反,所以我想做一些东西,用一个tween,对于第二个属性,我做一些反函数,但我想不出任何解,所以它实际上是可行的。也许我错过了一些简单的东西。 以下是我的完整代码: 如有任何帮

  • 我们有一个应用程序,将部署在具有不同IP的服务器上。JNLP是在构建时生成的。因此,我们定义了没有代码库的JNLP: 然而,当第二次启动这个应用程序时(从第一次启动时创建的桌面图标),代码库被设置为本地文件系统,这是绝对无用的。我希望Java Webstart在第一次启动应用程序时使用实际的源地址设置代码库。这似乎不是真的。 我如何准备一个通用的JNLP,它可以在不同的服务器上使用而无需修改?

  • 我一直在做一个倒计时程序,我想到了这个。 在最后的while循环中,如果里面没有print/println语句,倒计时代码就不会执行。为什么?不过,该程序与print语句配合得非常好。

  • 问题内容: 我正在查看数据库中的一个表(我没有创建该表),我发现有两个完全相同的索引(我不知道为什么这样做)只是命名不同,这可以对桌子有负面影响吗? 拿这个例子表: 问题答案: 是的,它可以起作用。 当然,如果使用这两个索引,它们会占用磁盘和内存的额外空间。 但是,它们还会使查询优化器做更多的工作来计算每个SELECT期间每个索引的收益。您拥有的索引越多,需要比较的案例就越多。因此,消除真正的冗余

  • 你好,我有个问题。以下是代码示例: 我有一个多选表格: 这是我的开关盒: 代码的工作原理是,如果用户选择例如GB11,结果将是: 工厂GB11 ZMD_LPLCNMAT_GB11 ZMD_LPQAMAT_GB11 ZMD_LSOCNMAT_GB11 ZMD_PLNTMAT_GB11 ZMD_SLSVMAT_GB11 当我选择GB10和GB20时,我不想选择得到结果,例如“测试”,而不是它们的组合。

  • 问题内容: 在Python中查看两个文件在内容方面是否相同的最简单方法是什么。 我可以做的一件事是对每个文件md5进行比较。有没有更好的办法? 问题答案: 是的,我认为如果必须比较多个文件并存储哈希以供以后比较,则对文件进行哈希处理将是最好的方法。由于哈希可能会发生冲突,因此可能会根据用例进行逐字节比较。 通常,逐字节比较将是足够且高效的,哪个filecmp模块也已经执行了其他操作。 参见http