Swift 2.0: использование self в вызове метода перед сохраненными свойствами инициализируется
Просто начал смотреть на Свифт в эти выходные. Я создаю 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
}
Ответы
Ответ 1
Метод generateRandomID()
не использует и не изменяет никаких свойств
экземпляра, поэтому одним из возможных решений могло бы стать
тип (класс):
private class func generateRandomID() -> String {
// ...
return id
}
и используйте его как
id = MagicCard.generateRandomID()
(как также написано в другом ответе, когда я писал это).
Вы также можете отказаться от метода и использовать "немедленно оцененное закрытие":
id = { () -> String in
// ...
return id
}()
Но, если целью свойства id является создание объектов
Equatable
, а затем он вам вообще не нужен. Классы являются справочными
типы и экземпляры можно сравнить с оператором "идентично":
func == (lhs: MagicCard, rhs: MagicCard) -> Bool {
return lhs === rhs
}
что делает метод id
и generateRandomID()
устаревшим.
Ответ 2
Горячее исправление, которое я могу предложить, - сделать generateRandomID
класс func. Так сделайте так:
private class func generateRandomID() -> String {
И вызывается вот так:
id = MagicCard.generateRandomID()
Ответ 3
Вызов функции-члена generateRandomID
включает неявный self.
, поэтому вы не можете сделать это до того, как объект будет полностью инициализирован. Простым решением было бы сначала назначить временное значение id
:
id = ""
id = generateRandomID() // NOT THE SUGGESTED SOLUTION, see below.
Но для этого вам придется изменить его на var
, а затем потребуется больше усилий, чтобы скрыть сеттер от публики.
Однако ничто в generateRandomID()
не зависит от состояния объекта, поэтому оно может также быть функцией класса static
, которую вы тогда называете MagicCard.generateRandomID()
. Но для того, чтобы сделать это еще больше, концептуально генерация случайного идентификатора не имеет ничего общего с магической картой, поэтому вы могли бы даже сделать ее глобальной функцией или изолировать ее до своего класса...
... и как только мы доберемся до этого, почему бы просто не использовать существующий тип NSUUID
для представления вашего идентификатора? Либо измените тип id
на NSUUID
и инициализируйте его id = NSUUID()
для случайного UUID, либо сохраните его String
и назначьте как id = NSUUID().UUIDString
. UUID уже решают проблему уникальных идентификаторов, поэтому вам не нужно придумывать собственный генератор. =)
Это приводит нас к:
let id: NSUUID = NSUUID()
или
let id: String = NSUUID().UUIDString