Klasa „ViewController” nie ma inicjatorów w języku swift

123

Otrzymuję skargę od kompilatora, kiedy to robię

class ViewController: UIViewController {

    var delegate : AppDelegate
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        //self.appDelegate = UIApplication.sharedApplication().delegate;

    }

    @IBAction func getData(sender : AnyObject) {

    }

    @IBAction func LogOut(sender : AnyObject) {
    }
}

Jeśli jednak dodam ? na końcu AppDelegate jak poniżej i błąd zniknął.

class ViewController: UIViewController {

    var delegate : AppDelegate?
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        //self.appDelegate = UIApplication.sharedApplication().delegate;

    }

    @IBAction func getData(sender : AnyObject) {

    }

    @IBAction func LogOut(sender : AnyObject) {
    }
}

Nie widzę optionalsłowa kluczowego związanego z tym błędem, chyba że się mylę.

tranvutuan
źródło

Odpowiedzi:

240

Błąd można poprawić, ale problem z pierwszą wersją polega na tym, że masz zmienną składową, delegate , która nie ma wartości domyślnej. Wszystkie zmienne w Swift muszą zawsze mieć wartość. Oznacza to, że musisz ustawić go w inicjatorze, którego nie masz lub możesz podać mu domyślną wartość w linii.

Gdy ustawisz ją jako opcjonalną, zezwalasz na to, aby była nildomyślnie, eliminując potrzebę jawnego nadawania jej wartości lub inicjowania.

drewag
źródło
45

Swift Programming Language stwierdza:

Klasy i struktury muszą ustawić wszystkie swoje przechowywane właściwości na odpowiednią wartość początkową do czasu utworzenia wystąpienia tej klasy lub struktury. Nie można pozostawić przechowywanych właściwości w stanie nieokreślonym.

Wartość początkową przechowywanej właściwości można ustawić w inicjatorze lub przypisując domyślną wartość właściwości jako część definicji właściwości.

Dlatego możesz napisać:

class myClass {

    var delegate: AppDelegate //non-optional variable

    init() {
        delegate = UIApplication.sharedApplication().delegate as AppDelegate
    }

}

Lub:

class myClass {

    var delegate = UIApplication.sharedApplication().delegate as AppDelegate //non-optional variable

    init() {
        println("Hello")
    }

}

Lub:

class myClass {

    var delegate : AppDelegate! //implicitly unwrapped optional variable set to nil when class is initialized

    init() {
        println("Hello")
    }

    func myMethod() {
        delegate = UIApplication.sharedApplication().delegate as AppDelegate
    }

}

Ale nie możesz napisać tego:

class myClass {

    var delegate : AppDelegate //non-optional variable

    init() {
        println("Hello")
    }

    func myMethod() {
        //too late to assign delegate as an non-optional variable
        delegate = UIApplication.sharedApplication().delegate as AppDelegate
    }

}
Imanou Petit
źródło
22

Czasami ten błąd pojawia się również, gdy masz zmienną lub let, która nie została zainicjowana.

Na przykład

class ViewController: UIViewController {
    var x: Double
    // or
    var y: String
    // or
    let z: Int
}

W zależności od tego, co ma robić twoja zmienna, możesz ustawić ten typ zmiennej jako opcjonalny lub zainicjować go wartością podobną do poniższej

class ViewController: UIViewCOntroller {
    // Set an initial value for the variable
    var x: Double = 0
    // or an optional String
    var y: String?
    // or
    let z: Int = 2
}
Oliver S.
źródło
więc jakie jest rozwiązanie tego problemu?
Martian2049,
czy można je zamiast tego zainicjować w funkcji init?
Martian2049,
13

Ten problem pojawia się zwykle, gdy jedna ze zmiennych nie ma wartości lub gdy zapomnisz dodać znak „!” aby zmusić tę zmienną do przechowywania nil, dopóki nie zostanie ustawiona.

W twoim przypadku problem jest tutaj:

var delegate: AppDelegate

Powinien być zdefiniowany jako var delegate: AppDelegate! aby był opcjonalny i przechowuje wartość nil i nie rozpakowuje zmiennej, dopóki wartość nie zostanie użyta.

To smutne, że Xcode podświetla całą klasę jako błąd zamiast podświetlać konkretny wiersz kodu, który go spowodował, więc zrozumienie tego zajmuje trochę czasu.

Ivan V
źródło
To eliminuje dla mnie komunikat o błędzie w przypadku IBOutlet, ale nie w przypadku standardowych zmiennych.
Tim Vermeulen
To rozwiązuje mój problem. Kiedy próbowałem to zrobić: var fetchedResultsController: NSFetchedResultsController Otrzymałem błąd kompilacji. Poprzez dodanie "!" błąd zniknął, podobnie jak var fetchedResultsController: NSFetchedResultsController!
Jervisbay
dzięki za twoje odpowiedzi! To jest dla mnie bardzo pomocne, właśnie poznałem „?” do wartości opcjonalnej, ale „!” Nie wiedziałem wcześniej. Ustawiłem "!" w ten sposób: var time: NSTimer!
AmyNguyen
10

jeśli zgubiłeś „!” w swoim kodzie, tak jak w poniższym kodzie, również pojawi się ten błąd.

import UIKit

class MemeDetailViewController : UIViewController {

    @IBOutlet weak var memeImage: UIImageView!

    var meme:Meme! // lost"!"

    override func viewWillAppear(animated: Bool) {

        super.viewWillAppear(animated)
        self.memeImage!.image = meme.memedImage
    }

    override func viewDidDisappear(animated: Bool) {
        super.viewDidDisappear(animated)
    }

}
saneryee
źródło
3

Zastąp zgodnie var appDelegate : AppDelegate?ze let appDelegate = UIApplication.sharedApplication().delegatewskazówkami w drugiej skomentowanej linii viewDidLoad().

Słowo kluczowe „opcjonalne” odnosi się dokładnie do użycia. ?Zobacz to, aby uzyskać więcej informacji.

user2118161
źródło
1

Używam Xcode 7 i Swift 2. Na koniec:

class ViewController: UIViewController {var time: NSTimer // tutaj błąd}

Następnie naprawiam: class ViewController: UIViewController {

var time: NSTimer!
override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

override func viewWillAppear(animated: Bool) {
    //self.movetoHome()
    time = NSTimer.scheduledTimerWithTimeInterval(5.0, target: self, selector: #selector(ViewController.movetoHome), userInfo: nil, repeats: false)
    //performSegueWithIdentifier("MoveToHome", sender: self)
    //presentViewController(<#T##viewControllerToPresent: UIViewController##UIViewController#>, animated: <#T##Bool#>, completion: <#T##(() -> Void)?##(() -> Void)?##() -> Void#>)
}

func movetoHome(){
    performSegueWithIdentifier("MoveToHome", sender: self)
}

}

AmyNguyen
źródło
Twoja odpowiedź nie jest całkiem jasna, ale to był mój problem; Nie określiłem opcjonalności zmiennej składowej (wymuszona / opcjonalna); kiedy to zrobiłem, a później dostosowałem kod, ViewController nie narzekał już na brak inicjatora.
James Perih,
0

Dla mnie była to deklaracja niekompletna. Na przykład:

var isInverted: Bool

Zamiast tego we właściwy sposób:

var isInverted: Bool = false
Alessandro Mattiuzzi
źródło