Я новичок в кодировании и использовании SwiftUI в Xcode, и я не вижу, что не так с этим кодом:
class NormalSpace {
var name = ""
var value = 0
var rent = 0
var owned = false
}
var newRoad = NormalSpace()
newRoad.name = "New Road"
newRoad.value = 600
newRoad.rent = 25
newRoad.owned = false
ошибка «Ожидаемое ключевое слово func в объявлении метода экземпляра» отображается только в строке newRoad.name. В той же строке также есть ошибка: Недопустимое повторное объявление «newRoad».
Что я сделал не так?
Это в его собственном файле
Тогда вы не сможете открыто присвоить значение свойствам. Они должны быть частью структуры/класса и внутри метода (func).
Извините, я имел в виду, что это само по себе в структуре. Так это все еще должно быть в func?
Да, у вас не может быть такого кода на верхнем уровне структуры или класса. И, возможно, также не класс, объявленный внутри структуры, хотя технически это разрешено.
Внутри struct
можно объявлять переменные, константы и функции, но нельзя запускать код, который «висит» внутри. То, что висит внутри struct
или class
, создается сразу, но если у вас есть код, который нужно запускать последовательно, вы должны использовать функцию/инициализатор.
В обычном проекте это недопустимо:
class NormalSpace {
var name = ""
var value = 0
var rent = 0
var owned = false
}
var newRoad = NormalSpace()
newRoad.name = "New Road"
newRoad.value = 600
newRoad.rent = 25
newRoad.owned = false
Вы можете сделать это на игровой площадке (где он просто запускает этот код напрямую), но в приложении код (например, настройка свойств) принадлежит функции или инициализатору.
Этот код инициализации необходимо поместить в некоторый контекст. Давайте представим, что он находится внутри struct
. Но это все еще недействительно:
class NormalSpace {
var name = ""
var value = 0
var rent = 0
var owned = false
}
struct Foo {
var newRoad = NormalSpace()
newRoad.name = "New Road"
newRoad.value = 600
newRoad.rent = 25
newRoad.owned = false
}
Свойство newRoad
подходит, а значения — нет. Вам нужно обернуть его внутри func
(отсюда и ошибка) или init
. Например, это инициализирует newRoad
во время init
struct
:
struct Foo {
let newRoad: NormalSpace
init() {
newRoad = NormalSpace()
newRoad.name = "New Road"
newRoad.value = 600
newRoad.rent = 25
newRoad.owned = false
}
}
Или вы можете инициализировать его в func
:
struct Foo {
var newRoad: NormalSpace?
mutating func bar() {
let road = NormalSpace()
road.name = "New Road"
road.value = 600
road.rent = 25
road.owned = false
newRoad = road
}
}
Или, в качестве альтернативы, вы можете инициализировать это свойство замыканием (обратите внимание на лишний ()
в конце):
struct Foo {
let newRoad: NormalSpace = {
let road = NormalSpace()
road.name = "New Road"
road.value = 600
road.rent = 25
road.owned = false
return road
}()
}
Но код, в котором вы инициализируете свойства, должен быть помещен в некоторый контекст, чтобы компилятор знал, когда следует запускать эти строки кода.
Обратите внимание, что обычно мы даем NormalSpace
«членный инициализатор», например:
class NormalSpace {
let name: String
let value: Int
let rent: Int
let owned: Bool
init(name: String, value: Int, rent: Int, owned: Bool) {
self.name = name
self.value = value
self.rent = rent
self.owned = owned
}
}
Или, если struct
(а мы обычно предпочитаем, чтобы наши объекты модели struct
имели тип значения, а не class
ссылочный тип), для вас будет создан этот поэлементный инициализатор:
struct NormalSpace {
let name: String
let value: Int
let rent: Int
let owned: Bool
}
В любом случае вы можете указать все желаемые значения во время инициализации, например:
struct Foo {
let newRoad = NormalSpace(name: "New Road", value: 600, rent: 25, owned: false)
}
Обратите внимание, что я удалил значения «по умолчанию», потому что они действительно не подходят. Если бы вы хотели сказать, что их не нужно предоставлять, то вы бы сделали их «необязательными». Но обычно существует большая разница между, скажем, нулевой арендной платой (т. е. это дом моей бабушки, и она не берет с меня плату) и тем, что арендная плата не указана. В Swift мы обычно избегаем использования «дозорных» значений, таких как ""
или 0
, для «значение не указано».
Кроме того, теперь, когда у нас есть поэлементный инициализатор, я также сделал свойства неизменяемыми (let
, а не var
). Если вам нужно сделать их изменяемыми (например, позволить кому-то изменить арендную плату позже), хорошо, вернитесь к var
. Но делайте свойства изменяемыми только в том случае, если вам действительно нужно изменить их позже.
Спасибо, Роб. Итак, если я хочу создать, скажем, 20 разных экземпляров NormalSpace (я не на 100% придерживаюсь терминологии), последний вариант будет лучшим? А затем, чтобы сослаться на него в другой структуре, это будет Foo.newRoad.owned = false или что-то в этом роде?
Итак, я бы определенно выбрал этот шаблон «членная инициализация». Итак, вопрос в том, что является «моделью» приложения: судя по вашему описанию, это будет массив экземпляров NormalSpace
...
В основном думаю Монополия. «Игрок» перемещается по экземплярам NormalSpace
и покупает или платит арендную плату. План состоит в том, чтобы использовать struct
для инициализации всех различных экземпляров, а затем еще один struct
для получения таких значений, как newRoad.rent
, и использовать их для изменения количества денег игроков или того, принадлежит ли NormalSpace
.
Я действительно не понимаю идею «одной структуры для инициализации экземпляров; другой для извлечения/изменения свойств», но вы можете делать все, что хотите. Но по крайней мере теперь вы видите, как работает инициализация…
Где объявлен этот класс? Внутри другого класса или в новом отдельном файле?