Как исправить ошибку компиляции: свойство не инициализировано при вызове super.init? [Дубликат]

Перед использованием переменной $result вы должны использовать функции $row = mysql_fetch_array($result) или mysqli_fetch_assoc().

Нравится это:

$row = mysql_fetch_array($result);

и использовать массив $row как вам нужно.

155
задан Josh Caswell 6 June 2014 в 19:20
поделиться

11 ответов

Цитата из Swift Язык программирования, который отвечает на ваш вопрос:

«Компилятор Swift выполняет четыре полезные проверки безопасности, чтобы убедиться, что двухфазная инициализация завершена без ошибок:«

Проверка безопасности 1 «Назначенный инициализатор должен гарантировать, что все« свойства, введенные его классом, будут инициализированы до того, как он делегирует до инициализатора суперкласса ».

Выдержка из: Apple Inc." Быстрый язык программирования. "IBooks. https://itunes.apple.com/us/book/swift-programming-language/id881256329?mt=11

142
ответ дан Ruben 28 August 2018 в 13:34
поделиться

Из docs

Проверка безопасности 1

Назначенный инициализатор должен гарантировать, что все свойства, введенные его классом, будут инициализированы до он делегирует до инициализатора суперкласса.


Зачем нам нужна проверка безопасности, как это?

Чтобы ответить, это позволяет перейти хотя процесс инициализации в быстрый .

Двухфазная инициализация

Инициализация класса в Swift является двухфазным процессом. На первом этапе каждому сохраненному свойству присваивается начальное значение классом, который его представил. Как только начальное состояние для каждого сохраненного свойства определено, начинается вторая фаза, и каждому классу предоставляется возможность настраивать свои сохраненные свойства еще до того, как новый экземпляр считается готовым к использованию.

Использование двухэтапный процесс инициализации делает инициализацию безопасной, но при этом дает полную гибкость каждому классу в иерархии классов. Двухфазная инициализация запрещает доступ к значениям свойств до их инициализации и не позволяет неожиданно устанавливать значения свойств на другое значение другим инициализатором.

Итак, чтобы убедиться, что два шага процесс инициализации выполняется, как определено выше, существует четыре проверки безопасности, один из которых:

Проверка безопасности 1

Назначенный инициализатор должен гарантировать, что все введенные свойства по его классу инициализируются до того, как он делегирует до инициализатора суперкласса.

Теперь двухфазная инициализация никогда не говорит о порядке, но эта проверка безопасности вводит super.init для заказа после инициализация всех свойств.

Проверка безопасности 1 может показаться неуместной, поскольку Двухфазная инициализация запрещает доступ к значениям свойств до их инициализации , без этой безопасности проверьте 1.

Как в этом примере

class Shape {
    var name: String
    var sides : Int
    init(sides:Int, named: String) {
        self.sides = sides
        self.name = named
    }
}

class Triangle: Shape {
    var hypotenuse: Int
    init(hypotenuse:Int) {
        super.init(sides: 3, named: "Triangle") 
        self.hypotenuse = hypotenuse
    }
}

Triangle.init инициализируется, каждое свойство перед использованием. Поэтому проверка безопасности 1 кажется несущественной,

Но тогда может быть другой сценарий, немного сложный,

class Shape {
    var name: String
    var sides : Int
    init(sides:Int, named: String) {
        self.sides = sides
        self.name = named
        printShapeDescription()
    }
    func printShapeDescription() {
        print("Shape Name :\(self.name)")
        print("Sides :\(self.sides)")
    }
}

class Triangle: Shape {
    var hypotenuse: Int
    init(hypotenuse:Int) {
        self.hypotenuse = hypotenuse
        super.init(sides: 3, named: "Triangle")
    }

    override func printShapeDescription() {
        super.printShapeDescription()
        print("Hypotenuse :\(self.hypotenuse)")
    }
}

let triangle = Triangle(hypotenuse: 12)

Выход:

Shape Name :Triangle
Sides :3
Hypotenuse :12

Здесь если бы мы назовет super.init перед установкой hypotenuse, то вызов super.init затем вызвал бы printShapeDescription(), и поскольку он был переопределен, он сначала вернется к реализации класса треугольника printShapeDescription(). printShapeDescription() класса Triangle получает доступ к hypotenuse не факультативному свойству, которое еще не было инициализировано. И это недопустимо как . Двухфазная инициализация запрещает доступ к значениям свойств до их инициализации

. Поэтому убедитесь, что двухфазная инициализация выполнена, как определено, необходимо, чтобы конкретный порядок вызова super.init, то есть после инициализации всех свойств, введенных классом self, нам нужна проверка безопасности 1

23
ответ дан BangOperator 28 August 2018 в 13:34
поделиться

swift принуждает вас инициализировать каждый член var до того, как он когда-либо будет использоваться. Так как он не может быть уверен, что произойдет, когда он перевернется, он ошибается: лучше безопасно, чем жаль

8
ответ дан Daij-Djan 28 August 2018 в 13:34
поделиться

Swift имеет очень четкую, определенную последовательность операций, выполняемую в инициализаторах. Начнем с некоторых базовых примеров и переходим к общему случаю.

Возьмем объект A. Мы определим его следующим образом.

class A {
    var x: Int
    init(x: Int) {
        self.x = x
    }
}

Заметим, что A не имеет суперкласса, поэтому он не может вызвать функцию super.init (), поскольку он не существует.

OK, поэтому теперь давайте подкласс A с новым классом с именем B.

class B: A {
    var y: Int
    init(x: Int, y: Int) {
        self.y = y
        super.init(x: x)
    }
}

Это отклонение от Objective-C, где [super init] обычно вызывается сначала перед чем-либо еще. Не так в Свифт. Вы несете ответственность за то, чтобы ваши переменные экземпляра находились в согласованном состоянии до того, как вы сделаете что-либо еще, включая методы вызова (который включает инициализатор вашего суперкласса).

70
ответ дан Dylan Hand 28 August 2018 в 13:34
поделиться

Это ошеломляюще глупый дизайн.

Рассмотрим что-то вроде этого:

.
.
.
var playerShip:PlayerShip
var deltaPoint = CGPointZero

init(size: CGSize)
{
    super.init(size: size)
    playerShip = PlayerShip(pos: CGPointMake(self.size.width / 2.0, 100))
    playerLayerNode.addChild(playerShip)        
}
.
.
.

Это неверно, как указано выше. Но так же:

.
.
.
var playerShip:PlayerShip = PlayerShip(pos: CGPointMake(self.size.width / 2.0, 100))
var deltaPoint = CGPointZero

init(size: CGSize)
{
    super.init(size: size)
    playerLayerNode.addChild(playerShip)        
}
.
.
.

Поскольку «я» не инициализируется.

Я искренне надеюсь, что эта ошибка будет исправлена ​​в ближайшее время.

(Да, я знаю, что я могу создать пустой объект, а затем установить размер, но это просто глупо).

-4
ответ дан Edward Kenworthy 28 August 2018 в 13:34
поделиться

Извините за уродливое форматирование. Просто поставьте символ вопроса после объявления, и все будет в порядке. Вопрос сообщает компилятору, что это значение является необязательным.

class Square: Shape {
    var sideLength: Double?   // <=== like this ..

    init(sideLength:Double, name:String) {
        super.init(name:name) // Error here
        self.sideLength = sideLength
        numberOfSides = 4
    }
    func area () -> Double {
        return sideLength * sideLength
    }
}

Edit1:

Существует лучший способ пропустить эту ошибку. Согласно комментарию jmaschad, нет причин использовать опциональные в вашем случае опции, которые не удобны в использовании, и вам всегда нужно проверять, не является ли опциональным нет низа, прежде чем обращаться к нему. Итак, все, что вам нужно сделать, это инициализировать член после объявления:

class Square: Shape {
    var sideLength: Double=Double()   

    init(sideLength:Double, name:String) {
        super.init(name:name)
        self.sideLength = sideLength
        numberOfSides = 4
    }
    func area () -> Double {
        return sideLength * sideLength
    }
}

Edit2:

После того, как два минуса вошли в этот ответ, я нашел еще лучший способ. Если вы хотите, чтобы член класса был инициализирован в вашем конструкторе, вы должны назначить ему начальное значение внутри contructor и перед вызовом super.init (). Например:

class Square: Shape {
    var sideLength: Double  

    init(sideLength:Double, name:String) {
        self.sideLength = sideLength   // <= before super.init call..
        super.init(name:name)
        numberOfSides = 4
    }
    func area () -> Double {
        return sideLength * sideLength
    }
}

Удачи в изучении Swift.

13
ответ дан fnc12 28 August 2018 в 13:34
поделиться

Swift не позволит вам инициализировать суперкласс с инициализацией свойств, обратной Obj C. Таким образом, вы должны инициализировать все свойства перед вызовом super.init.

Перейдите к http://blog.scottlogic.com/2014/11/20/swift-initialisation.html . Это дает хорошее объяснение вашей проблеме.

6
ответ дан jishnu bala 28 August 2018 в 13:34
поделиться

Добавьте nil в конец объявления.


// Must be nil or swift complains
var someProtocol:SomeProtocol? = nil

// Init the view
override init(frame: CGRect)
    super.init(frame: frame)
    ...

Это сработало для моего случая, но может не работать для ваших

3
ответ дан Michael 28 August 2018 в 13:34
поделиться

«super.init ()» следует вызывать после инициализации всех ваших переменных экземпляра.

В видеоролике Apple «Intermediate Swift» (вы можете найти ее на странице видеоресурсов разработчика Apple https://developer.apple.com/videos/wwdc/2014/), примерно в 28:40, явно сказано, что все инициализаторы в суперклассе должны быть вызваны ПОСЛЕ того, как вы инициализируете переменные экземпляра.

В Objective-C это было наоборот. В Swift, поскольку все свойства должны быть инициализированы до его использования, нам нужно сначала инициализировать свойства. Это означает предотвращение вызова функции переопределения из метода «init ()» супер класса без первоначальной инициализации свойств.

Таким образом, реализация «Квадрат» должна быть:

class Square: Shape {
    var sideLength: Double

    init(sideLength:Double, name:String) {
        self.sideLength = sideLength
        numberOfSides = 4
        super.init(name:name) // Correct position for "super.init()"
    }
    func area () -> Double {
        return sideLength * sideLength
    }
}
30
ответ дан Shuyang 28 August 2018 в 13:34
поделиться

Вы просто инициируете неправильный порядок.

     class Shape2 {
        var numberOfSides = 0
        var name: String
        init(name:String) {
            self.name = name
        }
        func simpleDescription() -> String {
            return "A shape with \(numberOfSides) sides."
        }
    }

    class Square2: Shape2 {
        var sideLength: Double

        init(sideLength:Double, name:String) {

            self.sideLength = sideLength
            super.init(name:name) // It should be behind "self.sideLength = sideLength"
            numberOfSides = 4
        }
        func area () -> Double {
            return sideLength * sideLength
        }
    }
1
ответ дан ylgwhyh 28 August 2018 в 13:34
поделиться

Edward,

Вы можете изменить код в своем примере следующим образом:

var playerShip:PlayerShip!
var deltaPoint = CGPointZero

init(size: CGSize)
{
    super.init(size: size)
    playerLayerNode.addChild(playerShip)        
}

Это использование неявно развернутого необязательного.

В документации мы можем прочитать:

«Как и в случае с необязательными, если вы не укажете начальное значение, когда объявляете неявно разворачиваемую необязательную переменную или свойство, это значение автоматически по умолчанию равно нулю».

7
ответ дан zizoujab 28 August 2018 в 13:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: