【问题标题】:Swift cannot assign to self in a class init methodSwift 不能在类 init 方法中赋值给 self
【发布时间】:2014-12-13 22:29:09
【问题描述】:

我有一个班级叫Letter

class Letter
{    
    init() {}
}

我有这个类的扩展:

extension Letter
{
    convenience init(file_path:String) {
       self = Letter.loadFromFile(file_path)
    }

    class func loadFromFile(file_path:String)->Letter {...}
}

我需要使用文件路径创建和初始化,当我调用Letter(file_path) 时,我需要一个由函数loadFromFile 返回的新对象。如何在 init 方法中赋值或返回一个新对象?

它给出了错误:

无法赋值:'self' 是不可变的

【问题讨论】:

  • 你为什么有一个扩展?只需将您的便利初始化程序放入类中即可。那就是它所属的地方。
  • 恰恰相反,恕我直言。将便利初始化程序保留在扩展中,但从主类中删除 init(file_path:String) 初始化程序。 Letter 类的用户可以直接调用 Letter.loadFromFile()。
  • 它还说我不能分配给自己,Letter 类的用户可以直接调用 Letter.loadFromFile() -- 是的,但我想让它更容易理解)跨度>
  • 这个提议的 API 有点像 Objective-C 的 je ne sais quoi。我建议完全消除loadFromFile

标签: swift init


【解决方案1】:

返回该类实例的类函数在 Swift 中似乎是一种反模式。您会注意到像[NSString stringWithString:@"some other string"] 这样的“with”Objective-C 类方法将转换为“with”-less 便利初始化器:NSString(string: "some other string")

此外,您需要在便利初始化程序中 delegate to a designated initializer

此外,由于您 1) 定义了原始类,并且 2) 不需要范围与指定初始化程序不同的便利初始化程序,因此我认为没有任何理由将其放在扩展中。

把它们放在一起:

class Letter {
    init() { … }

    convenience init(filePath: String) {
        self.init()
        loadFromFile(filePath)
    }

    func loadFromFile(filePath: String) { … }
}

let letter1 = Letter()
letter1.loadFromFile("path1")

let letter2 = Letter(filePath: "path2")

总之,在 Swift 中赋值给 self 的类比是调用一个初始化器。

让我知道这是否适合你!

【讨论】:

  • 这本 Swift 书谈到了将便利初始化器移动到扩展中,这样您就不必实现一个空的 init() 方法。我认为扩展是个好主意。
  • 啊!我没有意识到他的init 真的是空的。但是,你说的好像不是真的? Here's a gist,如果需要,将其粘贴到 Playground 中
  • 啊啊啊。 “如果您希望您的自定义 value 类型可以使用默认初始化程序和成员初始化程序以及您自己的自定义初始化程序进行初始化,请将您的自定义初始化程序写入扩展而不是作为值类型原始的一部分执行。”我认为他们是在说便捷初始化仅适用于引用类型。
【解决方案2】:
  1. 便利构造器必须委托给指定构造器

它说convenience init(file_path:String) 应该调用其他初始化器

convenience init(file_path:String) {
  self.init()
  //here can set other properties
}
  1. 方便初始化器通常提供一些默认参数

便利初始化器旨在使创建类实例不那么复杂。这意味着您不需要将所有参数传递给构造函数。在您的示例中,该类应如下所示

  • 指定的初始化程序接受所有可能的参数。
  • 方便提供默认值

代码示例

// Create instance of a Letter
Letter()
Letter(file_path: "path.txt")
Letter(file_path: "path.txt", option: 0, other: 0)

//Class Implementation 

class Letter
{
  init(file_path: String , option: Int, other: Int) {
    // Instansiate class
  }
}


extension Letter {

  convenience init() {
    self.init(file_path:"a")
  }

  convenience init(file_path:String) {
    self.init(file_path: file_path , option: 0, other: 0)
  }

  class func loadFromFile(file_path:String) -> Letter {
    return Letter()
  }
}

现在您可以通过这种方式创建 Letter 实例 -

【讨论】:

    【解决方案3】:

    你不能分配给自己。像这样的东西呢:

    class Letter {
    }
    
    extension Letter {
        convenience init(filePath: String) {
            self.init()
            // code to load a Letter from a file goes here.
        }
    
        class func loadFromFile(filePath: String) -> Letter {
            return Letter(filePath: filePath)
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-20
      • 2021-10-20
      相关资源
      最近更新 更多