programing

Swift 클래스 오류: super.init 호출 시 속성이 초기화되지 않았습니다.

codeshow 2023. 4. 12. 22:41
반응형

Swift 클래스 오류: super.init 호출 시 속성이 초기화되지 않았습니다.

는 두 수업이 .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)

가 왜가팅 why해 why를 해야 요?self.sideLength를 호출하기 super.init

Swift Programming Language를 인용하면 다음과 같은 질문에 답변할 수 있습니다.

"Swift의 컴파일러는 2단계 초기화가 오류 없이 완료되도록 하기 위해 4가지 안전 검사를 수행합니다."

안전 점검 1 "지정 이니셜라이저는 "슈퍼 클래스 이니셜라이저에 위임하기 전에 클래스별로 도입된 모든 속성이 초기화되었는지 확인해야 합니다."

출처: Apple Inc.에서 발췌.'스위트 프로그래밍 언어' 아이북스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() 함수를 호출할 수 없습니다.

자, 그럼 이제 클래스 A에 새로운 클래스 B를 추가해 보겠습니다.

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

한 것으로, 여기서의 「C」는 「C」입니다.[super init]이치노스위프트에서는 그렇지 않다.콜 메서드(슈퍼클래스의 이니셜라이저 포함)를 포함한 다른 작업을 수행하기 전에 인스턴스 변수가 일관된 상태인지 확인해야 합니다.

문서에서

안전 점검 1

대표 이니셜라이저는 슈퍼클래스 이니셜라이저에 위임하기 전에 클래스에 의해 도입된 모든 속성이 초기화되어 있는지 확인해야 합니다.


왜 이런 안전 점검이 필요한 거죠?

이것에 응답하려면 , 초기화 프로세스를 신속히 진행합시다.

2상 초기화

Swift에서의 클래스 초기화는 2단계 프로세스입니다.첫 번째 단계에서는 각 저장된 속성은 해당 속성을 도입한 클래스에 의해 초기값이 할당됩니다.저장된 모든 속성의 초기 상태가 결정되면 두 번째 단계가 시작되고 각 클래스는 새 인스턴스가 사용 가능한 것으로 간주되기 전에 저장된 속성을 추가로 커스터마이즈할 수 있는 기회가 주어집니다.

2단계 초기화 프로세스를 사용하면 초기화가 안전하면서도 클래스 계층의 각 클래스에 완전한 유연성을 제공합니다.2상 초기화에서는 속성 값이 초기화되기 전에 액세스되는 것을 방지하고 속성 값이 다른 이니셜라이저에 의해 예기치 않게 다른 값으로 설정되는 것을 방지합니다.

따라서 2단계 초기화 프로세스가 위에서 정의한 대로 수행되도록 하기 위해 4가지 안전 점검이 있으며, 그 중 하나는 다음과 같습니다.

안전 점검 1

대표 이니셜라이저는 슈퍼클래스 이니셜라이저에 위임하기 전에 클래스에 의해 도입된 모든 속성이 초기화되어 있는지 확인해야 합니다.

이 이 에서는 순서는 .super.init모든 속성을 초기화한 후 주문해야 합니다.

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사용 전 모든 속성이 초기화되었습니다.은 관계가 것 .

하지만 다른 시나리오가 있을 수도 있어요 조금 복잡하지만

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.inithypotenuse , . . . . . . . .super.init 콜이 '콜'로 불리게 .printShapeDescription()에 먼저 클래스의 「Triangle」에.printShapeDescription() . 。printShapeDescription()의 Triangle에 .hypotenuse아직 초기화되지 않은 비선택적 속성.또한 2단계 초기화에서는 속성 값이 초기화되기 전에 액세스할없기 때문에 이는 허용되지 않습니다.

정의된또, 「Two phase initialization」에는, 「Two phase initialization」이 의 콜 합니다.구체적인 호출 순서가 필요합니다.super.init 에 의해 한 후 " " " 입니다self클래스, 따라서 우리는 안전 점검 1이 필요합니다.

모든 인스턴스 변수를 초기화한 후에 "super.init()"를 호출해야 합니다.

Apple의 "Intermediate Swift" 비디오(Apple Developer video resource 페이지 https://developer.apple.com/videos/wwdc/2014/), 약 28:40에 있음)에서는 인스턴스 변수를 초기화한 후 슈퍼 클래스의 모든 이니셜라이저를 호출해야 한다고 명시되어 있습니다.

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의 코멘트에 따르면 옵션 사용이 불편하기 때문에 옵션을 사용할 이유가 없습니다.옵션에 액세스하기 전에 항상 옵션이 0이 아닌지 확인해야 합니다.따라서 선언 후 멤버를 초기화하기만 하면 됩니다.

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)        
}

이것은 암묵적으로 언랩된 옵션을 사용하고 있습니다.

문서에서는 다음을 읽을 수 있습니다.

옵션과 마찬가지로 암묵적으로 래핑되지 않은 옵션 변수 또는 속성을 선언할 때 초기값을 제공하지 않으면 값은 자동으로 0으로 설정됩니다.

Swift는 Obj C와 반대로 속성을 초기화하지 않고 슈퍼 클래스를 초기화할 수 없습니다.따라서 "super.init"을 호출하기 전에 모든 속성을 초기화해야 합니다.

http://blog.scottlogic.com/2014/11/20/swift-initialisation.html 에 접속해 주세요.그것은 당신의 문제를 잘 설명해 줍니다.

선언의 말미에 0을 추가합니다.


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

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

내 경우엔 효과가 있었지만 자네 경우에는 효과가 없을 수도 있어

다음과 같이 해야 합니다.

init(sideLength:Double, name:String) {
    self.sideLength = sideLength
    super.init(name:name)
    numberOfSides = 4
}

다음 링크를 보세요.https://swiftgg.gitbook.io/swift/swift-jiao-cheng/14_initialization#two-phase-initialization

당신은 단지 잘못된 순서로 입력하고 있을 뿐이다.

     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
        }
    }

@Janos 속성을 옵션으로 하면 초기화할 필요가 없습니다.

이건 나한테 효과가 있었어.

언급URL : https://stackoverflow.com/questions/24021093/error-in-swift-class-property-not-initialized-at-super-init-call

반응형