-1

I wrote the code below. The error I'm getting is at the end of my convenience initializer when I attempt to call self.init. What's wrong with my logic or syntax? Or how would I debug this? The error Xcode is giving is "cannot invoke with an argument list of type".

Thank you for any help on this

import Foundation
import UIKit

class Item: NSObject {

    var name: String
    var valueInDollars: Int
    var serialNumber: String?
    let dateCreated: NSDate
    var stolen: Bool?

    init(name: String, valueInDollars: Int, serialNumber: String?, dateCreated: NSDate, stolen: Bool?) {
        self.name = name
        self.valueInDollars = valueInDollars
        self.serialNumber = serialNumber
        self.dateCreated = NSDate()
        self.stolen = stolen

        //below why did I have to call super.init for this custom class that inherits from NSObject? Doesn't it automatically get called anyway once the custom object is initialized since it inherits from NSObject?  It just seems like more work on my behalf which isn't fair.  it should do it automatically.  Why wouldn't it do it automatically if it inherits from NSObject?
        super.init()
    }

    convenience init(random: Bool = false) {
        if random {
            let adjectives = ["Fluffy", "Rusty", "Shiny"]
            let nouns = ["MacBook Pro", "Red Tribe Bike", "Vegan Pizzas"]
            //take a variable that's random; the highest value for this random number will be the number of ojbects in the adjectives array
            var idx = arc4random_uniform(UInt32(adjectives.count))
            //now use this random variable and let it be the index of the adjectives array...so basically it'll be a random object from the adjectives array
            let randomAdjective = adjectives[Int(idx)]

            //AWESOME!! Now that the random adjective is stored in the randomAdjective constant, let's re-use the idx variable...Ayyyyeeeee re-use!

            //we'll re-use it by doing the same process or close to the same process for nouns
            idx = arc4random_uniform(UInt32(nouns.count))
            let randomNoun = nouns[Int(idx)]

            //now let's concatenate these two clever words, shall we!!
            let randomName = "\(randomAdjective) \(randomNoun)"

            //yayyy we're programmmminnngg!

            //now let's ....whad de fuk....
            let randomValue = Int(arc4random_uniform(100))
            let randomSerialNumber = NSUUID().uuidString.components(separatedBy: "-").first!

            let betterNotBeStolen: Bool = false

            self.init(name: randomName, valueInDollars: randomValue, serialNumber: randomSerialNumber, stolen: betterNotBeStolen)


        }
    }
}
Laurence Wingo
  • 3,912
  • 7
  • 33
  • 61

1 Answers1

1

You got the error

"Cannot invoke 'Item.init' with an argument list of type '(name: String, valueInDollars: Int, serialNumber: String, stolen: Bool)'"

because you missed the the dateCreated param in the self.init(params...).

So you need to replace this line

self.init(name: randomName, valueInDollars: randomValue, serialNumber: randomSerialNumber, stolen: betterNotBeStolen)

with this one

self.init(name: randomName, valueInDollars: randomValue, serialNumber: randomSerialNumber,dateCreated: NSDate(), stolen: betterNotBeStolen)

The next error which you will see after is

Self.init isn't called on all paths before returning from initializer

So you need to add else statement because the initializer don't know what to do when the random param is false.

convenience init(random: Bool = false) {
        if random {
            let adjectives = ["Fluffy", "Rusty", "Shiny"]
            let nouns = ["MacBook Pro", "Red Tribe Bike", "Vegan Pizzas"]
            //take a variable that's random; the highest value for this random number will be the number of ojbects in the adjectives array
            var idx = arc4random_uniform(UInt32(adjectives.count))
            //now use this random variable and let it be the index of the adjectives array...so basically it'll be a random object from the adjectives array
            let randomAdjective = adjectives[Int(idx)]

            //AWESOME!! Now that the random adjective is stored in the randomAdjective constant, let's re-use the idx variable...Ayyyyeeeee re-use!

            //we'll re-use it by doing the same process or close to the same process for nouns
            idx = arc4random_uniform(UInt32(nouns.count))
            let randomNoun = nouns[Int(idx)]

            //now let's concatenate these two clever words, shall we!!
            let randomName = "\(randomAdjective) \(randomNoun)"

            //yayyy we're programmmminnngg!

            //now let's ....whad de fuk....
            let randomValue = Int(arc4random_uniform(100))
            let randomSerialNumber = NSUUID().uuidString.components(separatedBy: "-").first!

            let betterNotBeStolen: Bool = false

            self.init(name: randomName, valueInDollars: randomValue, serialNumber: randomSerialNumber,dateCreated: NSDate(), stolen: betterNotBeStolen)


        } else {

           self.init(name: "SomeName", valueInDollars: 3, serialNumber: "123", dateCreated: NSDate(), stolen: true)
        }
    }
Dmitry
  • 2,963
  • 2
  • 21
  • 39
  • 1
    1. Your answer addresses the new error that will happen once they fix the problem in the code posted in the question. 2. Don't use `NSDate` in Swift, use `Date`. – rmaddy Apr 27 '18 at 01:35
  • 1
    @rmaddy 1.What the error is? 2.NSDate is used in designated initializer, to avoid casting I used NSDate initialization, I'm agree with you that there is no reason using NSDate. – Dmitry Apr 27 '18 at 01:45
  • The error in the question is passing the wrong arguments in the call to `self.init(...` in the convenience initializer. – rmaddy Apr 27 '18 at 01:52
  • @rmaddy the first error is that the initializer was called without dateCreated param that caused the "Cannot invoke 'Item.init' with an argument list of type '(name: String, valueInDollars: Int, serialNumber: String, stolen: Bool)'" error. After the error is fixed we get second error "Self.init isn't called on all paths before returning from initializer". So in the answer fixed both errors. – Dmitry Apr 27 '18 at 01:58
  • Yes, I know but your answer is written as if the 1st error never happened. You should explain the fix for the original issue, then point out that it will result in the new error and then explain the fix for that new error. – rmaddy Apr 27 '18 at 01:59
  • @rmaddy why shouldn't we use NSDate but use Date instead? – Laurence Wingo Apr 27 '18 at 15:49
  • 1
    @CosmicArrows `NSDate` (and many other `NS*` classes) are for Objective-C. Swift provides `Date` (and many other non-NS class/struct replacements). – rmaddy Apr 27 '18 at 15:51
  • @rmaddy how come in my convenience initializer I didn't have to call super.init? Or does the convenience initializer caller the designated initializer regardless after its finished? – Laurence Wingo Apr 27 '18 at 15:56
  • 1
    @CosmicArrows Please read the [Initialization](https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Initialization.html#//apple_ref/doc/uid/TP40014097-CH18-ID203) chapter in the Swift book. Focus on the "Class Inheritance and Initialization" section. Convenience initializers must call `self` initializers. – rmaddy Apr 27 '18 at 16:00