【问题标题】:Swift 2.0: use of self in method call before stored properties are initialisedSwift 2.0:在初始化存储属性之前在方法调用中使用 self
【发布时间】:2015-08-02 11:16:45
【问题描述】:

这个周末刚开始研究 Swift。我正在为我的班级创建一个 id 以快速比较对象。我想要一个不可变的 id,所以应该使用 let。

使用 var 并将 id 初始化为 "" 将修复 “在初始化存储属性之前在方法调用中使用 self” 但当然它是可变的。我见过的与此类似的所有其他问题都是关于超级类/调用 super.init,我没有。这很令人沮丧,我不知道为什么它不直截了当。

class MagicCard {

    let id:String
    let name: String
    let manaCost: Int
    let description: String
    let attack: Int
    let defence: Int

    init (name: String, manaCost: Int, description: String, attack: Int, defence: Int) {
        self.name = name
        self.manaCost = manaCost
        self.description = description
        self.attack = attack
        self.defence = defence
        id = generateRandomID()
    }

    private func generateRandomID() -> String {
        let charSet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
        let charSetArray = Array(charSet.characters)
        var id:String = ""
        for _ in (0..<10) {
            id.append(charSetArray[Int(arc4random()) % charSetArray.count])
        }
        return id
    }
}

func == (lhs: MagicCard, rhs: MagicCard) -> Bool {
    return lhs.id == rhs.id
}

【问题讨论】:

  • 为什么需要将属性传递给函数?这是一个类方法,因此可以访问 id。在初始化程序中,您可以调用generateRandomID(),它可以访问id
  • @Mark:那是行不通的,因为如果 let 将其声明为 constant,则无法从方法中修改 id
  • 考虑使用现有的NSUUID 正确生成唯一标识符;您可以通过删除整个 generateRandomID() 来简化代码(这可能并不总是唯一的)。您还有使用arc4random() % n 而不是arc4random_uniform(n) 的问题——当n 不划分生成的随机数范围时,产生的随机性会有所不同,在这种情况下它不会(差异可能这么小的n 可以忽略不计,但绝不会少)。

标签: swift swift2 swift-playground


【解决方案1】:

我可以建议的一个热修复是使generateRandomID 成为一个类函数。所以就这样吧:

private class func generateRandomID() -> String {

然后这样调用:

id = MagicCard.generateRandomID()

【讨论】:

    【解决方案2】:

    generateRandomID() 方法不使用或修改任何属性 的实例,因此一种可能的解决方案是使其成为 类型(类) 方法:

    private class func generateRandomID() -> String {
        // ...
        return id
    }
    

    并像使用它

    id = MagicCard.generateRandomID()
    

    (正如我在写这篇文章时在另一个答案中所写的那样)。

    您也可以删除该方法并使用“立即评估的闭包”:

    id = { () -> String in
        // ...
        return id
    }()
    

    但是如果 id 属性的目的是使对象 Equatable 然后你根本不需要它。类是参考 类型和实例可以用“identical to”操作符进行比较:

    func == (lhs: MagicCard, rhs: MagicCard) -> Bool {
        return lhs === rhs
    }
    

    这使得 idgenerateRandomID() 方法过时了。

    【讨论】:

    • 为那个马丁干杯。我发现整个事情很奇怪,我从未在我使用过的任何其他 OO 语言中遇到过类似的事情。我想让类 Equatable 以便我可以扩展数组类以具有“removeObject:object”函数。
    • @SparkyRobinson 我认为发生这种情况是因为如果您允许您的 init 方法调用其他方法,检查您的所有变量是否被初始化一次且仅一次是一个无法确定的问题,潜在的变异方法。其他强制相同约束的 OO 语言也会有同样的问题。
    【解决方案3】:

    调用成员函数generateRandomID 包含一个隐含的self.,所以在对象完全初始化之前你确实不能这样做。一个简单的解决方案是首先为 id 分配一个临时值:

    id = ""
    id = generateRandomID() // NOT THE SUGGESTED SOLUTION, see below.
    

    但要做到这一点,您必须将其更改为 var,然后需要更多的努力才能将 setter 隐藏在公众面前。

    但是,generateRandomID() 中的任何内容都取决于对象的状态,因此它也可能是一个 static 类函数,然后您可以将其称为 MagicCard.generateRandomID()。但更进一步,从概念上讲,随机 id 的生成与万智牌卡没有任何关系,因此您甚至可以将其设为全局函数或将其隔离为自己的类……

    ...一旦我们走到这一步,为什么不直接使用现有的 NSUUID 类型来表示您的 id?将id 的类型更改为NSUUID 并使用id = NSUUID() 对其进行初始化以获得随机UUID,或者将其保留为String 并指定为id = NSUUID().UUIDString。 UUID 已经解决了唯一 id 的问题,因此您不必想出自己的生成器。 =)

    这导致我们:

    let id: NSUUID = NSUUID()
    

    let id: String = NSUUID().UUIDString
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-11-09
      • 1970-01-01
      • 2016-04-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多