185

I have a problem with Swift class. I have a swift file for UITableViewController class and UITableViewCell class. My problem is the UITableViewCell class, and outlets. This class has an error Class "HomeCell" has no initializers, and I don't understand this problem.

Thanks for your responses.

import Foundation
import UIKit

class HomeTable: UITableViewController, UITableViewDataSource, UITableViewDelegate {

    @IBOutlet var tableViex: UITableView!

    var items: [(String, String, String)] = [
        ("Test", "123", "1.jpeg"),
        ("Test2", "236", "2.jpeg"),
        ("Test3", "678", "3.jpeg")
    ]

    override func viewDidLoad() {
        super.viewDidLoad()

        var nib = UINib(nibName: "HomeCell", bundle: nil)
        tableView.registerNib(nib, forCellReuseIdentifier: "bookCell")
    }

    // Number row
    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.items.count
    }

    // Style Cell
    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

        var cell:UITableViewCell = self.tableView.dequeueReusableCellWithIdentifier("bookCell") as UITableViewCell

        // Style here

        return cell

    }

    // Select row
    override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        // Select
    }

}

// PROBLEM HERE
class HomeCell : UITableViewCell {

    @IBOutlet var imgBook: UIImageView
    @IBOutlet var titleBook: UILabel
    @IBOutlet var pageBook: UILabel

    func loadItem(#title: String, page: String, image:String) {
        titleBook.text = title
        pageBook.text = page
        imgBook.image = UIImage(named: image)
    }

}
Kevin Py
  • 2,459
  • 2
  • 22
  • 33

7 Answers7

262

You have to use implicitly unwrapped optionals so that Swift can cope with circular dependencies (parent <-> child of the UI components in this case) during the initialization phase.

@IBOutlet var imgBook: UIImageView!
@IBOutlet var titleBook: UILabel!
@IBOutlet var pageBook: UILabel!

Read this doc, they explain it all nicely.

mprivat
  • 21,582
  • 4
  • 54
  • 64
  • 21
    Your explanation, and that doc, all make sense to me, but not the error message! – coco Apr 26 '15 at 17:51
  • 4
    That's probably a question for Apple – mprivat Apr 28 '15 at 15:12
  • Also @IBOutlets should be marked as weak in order to avoid retain cycle. – Dennis Pashkov Jan 14 '16 at 16:46
  • @Dennis Pashkov As far as I know, it's only for IBOutlets that is in viewController's view hierarchy. Otherwise it will get released immediately because no one hold it. – Alston Jan 26 '16 at 08:22
  • 3
    I had this problem where I defined a Bool using `var myBool: Bool`. – jungledev Mar 23 '16 at 19:57
  • The responses to [this question](http://stackoverflow.com/q/24006975/885189) provide some good examples/explanations of using `Implicitly Unwrapped Optionals` as well. – JaredH May 09 '16 at 17:15
  • About "cope with circular dependencies". From this [link](https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html) do you mean this title: "Unowned References and Implicitly Unwrapped Optional Properties" and *under the hood* your imgBook, titleBook, pageBook are hooked with `unowned`? – mfaani Feb 16 '17 at 23:47
  • You can also define IBOutlets as weak properties since you don't want anyone hanging on to them once your Viewcontroller is deallocated. – C0D3 Jul 10 '17 at 14:08
  • The error message is pretty straightforward. If you initialize an object with a property that is **not** an optional, then it has to be set with the object. Anything initialized later has to be an optional, since it will be `nil` for a period of time in which you can access that property. That's the reason of the message: it doesn't have an initializer that sets the initial value for that particular property. – Alejandro Iván Apr 30 '18 at 15:00
101

Quick fix - make sure all variables which do not get initialized when they are created (eg var num : Int? vs var num = 5) have either a ? or !.

Long answer (reccomended) - read the doc as per mprivat suggests...

Byron Coetsee
  • 3,533
  • 5
  • 20
  • 31
  • To resolve this error you need to set up default value for ? variables, for example: let showUserPointViewDelegate : ShowUserPointsViewControllerControl? = nil – Vladimir Vodolazkiy Mar 18 '16 at 14:00
  • +1 `?` means it may be nil, but if it was then there is no problem with moving forward and doing nothing. `!` means if after unwrapping it was nil, then crash—both of these **satisfy the initiation requirement** —by you informing the compiler: I know/want that it will start form nil. – mfaani Jun 25 '16 at 15:43
  • Search for `var` and `let` in you view controller, and look for missing `!`s and `?`s – Wiingaard Jan 17 '17 at 14:24
33

This is from Apple doc

Classes and structures must set all of their stored properties to an appropriate initial value by the time an instance of that class or structure is created. Stored properties cannot be left in an indeterminate state.

You get the error message Class "HomeCell" has no initializers because your variables is in an indeterminate state. Either you create initializers or you make them optional types, using ! or ?

CodeHelp
  • 1,328
  • 5
  • 21
  • 37
33

My answer addresses the error in general and not the exact code of the OP. No answer mentioned this note so I just thought I add it.

The code below would also generate the same error:

class Actor {
    let agent : String? // BAD! // Its value is set to nil, and will always be nil and that's stupid so Xcode is saying not-accepted.  
    // Technically speaking you have a way around it, you can help the compiler and enforce your value as a constant. See Option3
}

Others mentioned that Either you create initializers or you make them optional types, using ! or ? which is correct. However if you have an optional member/property, that optional should be mutable ie var. If you make a let then it would never be able to get out of its nil state. That's bad!

So the correct way of writing it is:

Option1

class Actor {
    var agent : String? // It's defaulted to `nil`, but also has a chance so it later can be set to something different || GOOD!
}

Or you can write it as:

Option2

class Actor {
let agent : String? // It's value isn't set to nil, but has an initializer || GOOD!

init (agent: String?){
    self.agent = agent // it has a chance so its value can be set!
    }
}

or default it to any value (including nil which is kinda stupid)

Option3

class Actor {
let agent : String? = nil // very useless, but doable.
let company: String? = "Universal" 
}

If you are curious as to why let (contrary to var) isn't initialized to nil then read here and here

mfaani
  • 33,269
  • 19
  • 164
  • 293
12

In my case I have declared a Bool like this:

var isActivityOpen: Bool 

i.e. I declared it without unwrapping so, This is how I solved the (no initializer) error :

var isActivityOpen: Bool!
Anurag Sharma
  • 4,276
  • 2
  • 28
  • 44
1

Not a specific answer to your question but I had got this error when I hadn't set an initial value for an enum while declaring it as a property. I assigned a initial value to the enum to resolve this error. Posting here as it might help someone.

Alejandro Vargas
  • 1,327
  • 12
  • 26
0

simply provide the init block for HomeCell class

it's work in my case

anoop ghildiyal
  • 821
  • 10
  • 18