46

I have the following class, with an init method:

class user {
  var name:String
  var address:String

  init(nm: String, ad: String) {
    name = nm
    address = ad
  }
}

I'm trying to subclass this class but I keep getting errors on the super.init() part:

class registeredUser : user {
     var numberPriorVisits: Int

     // This is where things start to go wrong - as soon as I type 'init' it 
     // wants to autocomplete it for me with all of the superclass' arguments, 
     // and I'm not sure if those should go in there or not:
     init(nm: String, ad: String) {  
        // And here I get errors:
        super.init(nm: String, ad: String) 

     // etc....

Apple's iBook has examples of subclassing, but none those feature classes that have an init() method with any actual arguments in it. All their init's are devoid of arguments.

So, how do you do this?

sirab333
  • 3,662
  • 8
  • 41
  • 54
  • 3
    I think you can (and should) make your code cleaner by declaring the class in uppercase right ? – Anina Sep 19 '15 at 10:32

4 Answers4

42

In addition to Chuck's answer, you also have to initialize your new introduced property before calling super.init

A designated initializer must ensure that all of the properties introduced by its class are initialized before it delegates up to a superclass initializer. (The Swift Programming Language -> Language Guide -> Initialization)

Thus, to make it work:

init(nm: String, ad: String) {
    numberPriorVisits = 0  
    super.init(nm: nm, ad: ad) 
}

This simple initialization to zero could have been done by setting the property's default value to zero too. It's also encouraged to do so:

var numberPriorVisits: Int = 0

If you don't want such a default value it would make sense to extend your initializer to also set a new value for the new property:

init(name: String, ads: String, numberPriorVisits: Int) {
    self.numberPriorVisits = numberPriorVisits
    super.init(nm: name, ad: ads)
}
Jens Wirth
  • 17,110
  • 4
  • 30
  • 33
  • Well, I was indeed hoping to *not* have to put a default value of 0 to `numberPriorVisits` - but you're saying that its actually encouraged? Can you share where you learned that its encouraged? Also, in general, I'm trying to understand what the best practice is when it comes to `init's` in Swift. Is it better to give all your properties a default value and leave your init method argument-free? Or is it best to **NOT** have any default values and have it all done through passing arguments into `init`? – sirab333 Jul 02 '14 at 03:14
  • @sirab: With encouraged I mean that if you want to initialize it to a certain value, then the way of using a default value for the property is encouraged rather than setting the property to that value inside the initializer. Well, if your solution works with default values then there is no need for initializer parameters. – Jens Wirth Jul 02 '14 at 03:25
  • @sirab: I learned that it is encouraged by reading the language guide. Same chapter as I mentioned in my answer. It says "If a property always takes the same initial value, provide a default value rather than setting a value within an initializer. The end result is the same, but ..." Go and read :-) – Jens Wirth Jul 02 '14 at 03:29
  • 1
    ok, it makes sense - but only for properties that do indeed always take the same default initial value. But I would think that User name or Address don't quite lend themselves to a nice handy default value - unless you wanna go with a blank space, as in: "". But that seems kind of crude. Like "well lets just make it blank so we at least have *something*, and can therefore avoid writing an `init` method - know what I mean? The question is: would you think having blank spaces as default values for String properties is Best Practice? (I'm really trying to figure out the best approach here.) – sirab333 Jul 02 '14 at 03:44
  • 1
    @sirab: It absolutely depends on your needs. So, there is no best practice. IMHO, for your example it looks quite obvious to set name and address inside the initializer according to the parameters and set the number of visits to a default of 0 or 1 because the user new. – Jens Wirth Jul 02 '14 at 03:58
  • Agreed. Its important for me to know how to do it both ways though so I can pick and choose as needed. And also just to get a better understanding of Swift's methodology and inner-workings (not to mention syntax!) Thanks very much for your help :-) – sirab333 Jul 02 '14 at 04:06
12

In swift 2.0 and Later it works like this (all cases)

init(newString:String) {
    super.init(string:newString)
    // Designed initialiser 
}
override init(someString: String) {
    super.init(mainString: someString)
    // Override initialiser when subclass some class 
}
required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
    // Some boilerplate code to handle error (needed when override)
}
convenience init(newString:String, withParameters:Dictionary<String,String>) {
    self.init(someString:newString)
    //Convenience initialiser 
}
Donnelle
  • 5,689
  • 3
  • 27
  • 31
Roman Safin
  • 704
  • 7
  • 16
4

You pass arguments to an initializer much like you pass arguments to a normal method:

init(nm: String, ad: String) {  
    super.init(nm: nm, ad: ad) 
}

For reference, this is shown in the Designated and Convenience Initializers In Action section of the Swift Language Guide.

Chuck
  • 234,037
  • 30
  • 302
  • 389
2

Have you tried setting a value to numberPriorVisits and changing the types for the calls to super

class user {
    var name:String
    var address:String

    init(nm: String, ad: String) {
        name = nm
        address = ad
    }
}


class registeredUser : user {
    var numberPriorVisits: Int;

    init(nm: String, ad: String) {
        self.numberPriorVisits = 0;
        super.init(nm: nm, ad: ad)
    }
}