Maria 9905
Maria 9905

Reputation: 207

How to pass default value when initializing a struct in swift

I have this struct defined to be used in my ErrorLogger. However, some of the parameters such as Timestamp I'd like to get right away with the functions listed. How can I pass a default value instead of nil for the parameters: header, errorLocation, userId? In order to signal that a default value will be used if no other value is provided.

The idea is that if I pass some default value to these parameters then the struct functions would be called to get the values or else the values would be overwritten by whatever the user passes during initialization.

I am also getting the error:

self used before all stored properties are initialized

on this line:

self.errorLocation = getErrorLocation()

Initializing struct from viewController:

let logError = LogError(header: nil, errorLocation: nil, userID: nil, description: "An error occurred while verifying if the user profile exists", errorMessage: "\(error?.localizedDescription ?? "")")

struct in ErrorLogger:

struct LogError {
    var header: String
    var errorLocation: String
    var userID: String
    var description: String //describes the type of error
    var errorMessage: String //actual error returned by given function

    //TODO: add timestamp to lofError
    //TODO: add logEvent (enum: Error, Info) For example: data validation errors can be of event Info

    init(header: String?, errorLocation: String?, userID: String?, description: String, errorMessage: String) {
        if header != nil {
            self.header = header!
        } else {
            self.header = " ::Error::"
        }
        if errorLocation != nil  {
            self.errorLocation = errorLocation!
        } else {
            self.errorLocation = getErrorLocation()
        }
        if userID != nil {
            self.userID = userID!
        } else {
            self.userID = getUserID()
        }
        self.description = " ::description::" + description
        self.errorMessage = " ::errorMessage::" + errorMessage
    }

    func getUserID() -> String {
        var userUID: String = ""
        if Auth.auth().currentUser != nil {
            userUID = (Auth.auth().currentUser!.uid.isEmpty ? "" : Auth.auth().currentUser!.uid)
        } else {
            userUID = ""
        }
        let userUIDStr: String = " ::UserID::" + userUID
        return userUIDStr
    }

    func getErrorLocation() -> String {

        // Get class name
        let filePath: String = #file
        let components = filePath.components(separatedBy: "/")
        let className: String = components.isEmpty ? "" : components.last!

        // Get line number
        let line: Int = #line

        // Get column number
        let column: Int = #column

        // Get function name
        let funcName: String = #function

        let errorLocationStr: String  = " ::className::\(className)::lineNumber\(line)::columnNumber\(column)::funcName::\(funcName)"

        return errorLocationStr
    }

    func toString() -> String {
        let completeLogErrorMessageStr: String = header + errorLocation + userID + description + errorMessage
        return completeLogErrorMessageStr
    }
}

Upvotes: 1

Views: 7027

Answers (1)

rmaddy
rmaddy

Reputation: 318774

You have to give all of the properties a valid before you can call methods. I would refactor your init to something like this:

init(header: String?, errorLocation: String?, userID: String?, description: String, errorMessage: String) {
    self.header = header ?? " ::Error::"
    self.errorLocation = errorLocation ?? ""
    self.userID = userID ?? ""
    self.description = " ::description::" + description
    self.errorMessage = " ::errorMessage::" + errorMessage

    if errorLocation == nil  {
        self.errorLocation = getErrorLocation()
    }
    if userID == nil {
        self.userID = getUserID()
    }
}

That will fix the "self used before all stored properties are initialized" error.

To use default values, update the signature:

init(header: String? = nil, errorLocation: String? = nil, userID: String? = nil, description: String, errorMessage: String) {
    // nothing else changes
}

Now you can call the initializer without the nil parameters.

For example:

let logError = LogError(header: nil, errorLocation: nil, userID: nil, description: "An error occurred while verifying if the user profile exists", errorMessage: "\(error?.localizedDescription ?? "")")

becomes:

let logError = LogError(description: "An error occurred while verifying if the user profile exists", errorMessage: "\(error?.localizedDescription ?? "")")

Upvotes: 2

Related Questions