나는 두 개의 수업이 Shape
있고Square
class Shape {
var numberOfSides = 0
var name: String
init(name:String) {
self.name = name
}
func simpleDescription() -> String {
return "A shape with \(numberOfSides) sides."
}
}
class Square: Shape {
var sideLength: Double
init(sideLength:Double, name:String) {
super.init(name:name) // Error here
self.sideLength = sideLength
numberOfSides = 4
}
func area () -> Double {
return sideLength * sideLength
}
}
위의 구현으로 오류가 발생합니다.
property 'self.sideLength' not initialized at super.init call
super.init(name:name)
self.sideLength
전화하기 전에 왜 설정 해야 super.init
합니까?
답변
귀하의 질문에 대답하는 Swift Programming Language에서 인용하십시오 :
“Swift의 컴파일러는 4 단계의 유용한 안전 점검을 수행하여 오류없이 2 단계 초기화가 완료되었는지 확인합니다.”
안전 점검 1 “지정된 이니셜 라이저는 클래스에 의해 도입 된 모든 속성이 수퍼 클래스 이니셜 라이저로 위임되기 전에 초기화되어야합니다.”
발췌 : Apple Inc.“Swift Programming Language.” iBooks.
https://itunes.apple.com/us/book/swift-programming-language/id881256329?mt=11
답변
Swift에는 초기화 프로그램에서 수행되는 매우 명확하고 구체적인 작업 순서가 있습니다. 몇 가지 기본 예제로 시작하여 일반적인 경우까지 진행해 보겠습니다.
객체 A를 봅시다. 다음과 같이 정의하겠습니다.
class A {
var x: Int
init(x: Int) {
self.x = x
}
}
A에는 수퍼 클래스가 없으므로 super.init () 함수가 존재하지 않으므로이를 호출 할 수 없습니다.
자 이제 B라는 새로운 클래스로 A를 서브 클래스하자.
class B: A {
var y: Int
init(x: Int, y: Int) {
self.y = y
super.init(x: x)
}
}
이것은 Objective-C에서 출발하여 [super init]
일반적으로 다른 것보다 먼저 호출됩니다. 스위프트에서는 그렇지 않습니다. 메소드 호출 (수퍼 클래스의 이니셜 라이저 포함)을 포함하여 다른 작업을 수행하기 전에 인스턴스 변수가 일관된 상태인지 확인해야합니다.
답변
로부터 문서
안전 점검 1
지정된 이니셜 라이저는 클래스가 도입 한 모든 속성이 수퍼 클래스 이니셜 라이저로 위임되기 전에 초기화되어야합니다.
왜 이런 안전 점검이 필요한가요?
이에 대한 답을 얻으려면 초기화 과정을 신속하게 진행하십시오.
2 단계 초기화
Swift의 클래스 초기화는 2 단계 프로세스입니다. 첫 번째 단계에서는 저장된 각 속성에 속성을 도입 한 클래스에 의해 초기 값이 할당됩니다. 모든 저장된 속성의 초기 상태가 결정되면 두 번째 단계가 시작되고 새 클래스를 사용할 준비가 된 것으로 간주되기 전에 각 클래스에 저장된 속성을 사용자 지정할 수있는 기회가 주어집니다.
2 단계 초기화 프로세스를 사용하면 클래스 계층 구조의 각 클래스에 완전한 유연성을 제공하면서 초기화가 안전 해집니다. 2 단계 초기화는 속성 값이 초기화되기 전에 속성 값에 액세스 하지 못하게하고 다른 초기화 프로그램이 속성 값을 예기치 않게 다른 값으로 설정하지 못하게합니다.
따라서 2 단계 초기화 프로세스가 위에 정의 된대로 수행되도록하기 위해 4 가지 안전 점검이 있습니다.
안전 점검 1
지정된 이니셜 라이저는 클래스가 도입 한 모든 속성이 수퍼 클래스 이니셜 라이저로 위임되기 전에 초기화되어야합니다.
이제 2 단계 초기화는 순서에 대해 이야기하지 않지만이 안전 검사 super.init
는 모든 속성을 초기화 한 후에 순서를 지정합니다.
안전 점검 1은 2 단계 초기화로 인해이 안전 점검 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
, 그 이후에는 우선의 삼각형 클래스 구현으로 대체 될 것입니다 . 삼각형 클래스 액세스는 비 선택적 특성 아직 초기화되지 않았습니다. 그리고 2 단계 초기화로 인해 속성 값이 초기화되기 전에 액세스 할 수 없으므로 허용되지 않습니다.super.init
printShapeDescription()
printShapeDescription()
printShapeDescription()
hypotenuse
따라서 2 단계 초기화가 정의 된대로 수행되고, 특정 호출 순서 가 있어야하며, 즉 클래스에 super.init
의해 도입 된 모든 속성을 초기화 한 후 안전 점검이self
필요합니다.
답변
모든 인스턴스 변수를 초기화 한 후 “super.init ()”를 호출해야합니다.
약 28:40에 Apple의 “Intermediate Swift”비디오 (Apple 개발자 비디오 리소스 페이지 https://developer.apple.com/videos/wwdc/2014/ 에서 찾을 수 있음 )에서 모든 초기화 프로그램이 인스턴스 변수를 초기화 한 후 수퍼 클래스를 호출해야합니다.
Objective-C에서는 그 반대였습니다. Swift에서는 모든 속성을 사용하기 전에 초기화해야하므로 먼저 속성을 초기화해야합니다. 이는 속성을 먼저 초기화하지 않고 수퍼 클래스의 “init ()”메서드에서 재정의 된 함수를 호출하지 못하도록하기위한 것입니다.
따라서 “Square”의 구현은 다음과 같아야합니다.
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
}
}
답변
못생긴 형식으로 죄송합니다. 선언 후에 질문 문자를 넣으면 모든 것이 정상입니다. 질문은 컴파일러에게 값이 선택적이라는 것을 알려줍니다.
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
}
}
편집 1 :
이 오류를 건너 뛰는 더 좋은 방법이 있습니다. 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
}
}
편집 2 :
이 대답에 두 가지 마이너스를 얻은 후에 더 나은 방법을 찾았습니다. 생성자에서 클래스 멤버를 초기화하려면 생성자 내부와 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를 배우는 행운을 빕니다.
답변
swift는 모든 멤버를 사용하기 전에 var를 초기화하도록합니다. 슈퍼 턴일 때 어떤 일이 발생하는지 확신 할 수 없기 때문에 오류가 발생합니다. 죄송합니다.
답변
에드워드,
예제에서 다음과 같이 코드를 수정할 수 있습니다.
var playerShip:PlayerShip!
var deltaPoint = CGPointZero
init(size: CGSize)
{
super.init(size: size)
playerLayerNode.addChild(playerShip)
}
이것은 암시 적으로 랩핑되지 않은 옵션을 사용하고 있습니다.
문서에서 우리는 읽을 수 있습니다 :
“선택적 옵션과 마찬가지로 암시 적으로 래핑되지 않은 선택적 변수 또는 속성을 선언 할 때 초기 값을 제공하지 않으면 자동으로 값이 nil로 설정됩니다.”