Swift 2.0:在初始化存储属性之前在方法调用中使用 self

Swift 2.0: use of self in method call before stored properties are initialised

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

使用 var 并将 id 初始化为 "" 将修复 "use of self in method call before stored properties are initialised" 但当然它是可变的。我见过的与此类似的所有其他问题都是关于超级 class / 调用 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
}

我可以建议的一个修补程序是使 generateRandomID 成为 class func。所以让它像这样:

private class func generateRandomID() -> String {

然后这样调用:

id = MagicCard.generateRandomID()

generateRandomID()方法不使用或修改任何属性 的实例,所以一个可能的解决方案是使它成为 类型(class)方法:

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

并像

一样使用它
id = MagicCard.generateRandomID()

(我在写这篇文章时也写在另一个答案中)。

您也可以放弃该方法并使用 "immediately evaluated closure":

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

但是如果id属性的目的是制作对象 Equatable 那么 你根本不需要它。 类 是参考 类型和实例可以用 "identical to" 运算符进行比较:

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

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

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

分配一个临时值
id = ""
id = generateRandomID() // NOT THE SUGGESTED SOLUTION, see below.

但要做到这一点,您必须将其更改为 var,然后将 setter 从 public 中隐藏起来需要更多的努力。

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

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

这导致我们:

let id: NSUUID = NSUUID()

let id: String = NSUUID().UUIDString