ios - 如何在 Swift 中将 #file、#line、#column、#funcion 传递给我的 ErrorLogger

标签 ios swift

我构建了一个 ErrorLogger,如下所示,以确保所有错误消息和用户错误都将被统一记录。然而,在调用 ErrorLogger 时初始化 struts 此时非常冗长。

我想让它尽可能简单。

正如您在下面的示例中看到的,在我初始化 ErrorLocation 的调用中,我必须输入

ErrorLocation(文件路径:#file,行:#line,列:#column,funcName:#function)

我希望能够节省一些输入,而不必在我的 Service 类 中一遍又一遍地重新输入,每当我想记录错误时。

有更好的方法吗?我愿意接受建议。

使用ErrorLogger

func saveUserProfile(uid: String, user: Dictionary<String, String>,completion: @escaping (Result<String>) -> Void) {

        // Save user profile data to the Firebase database - A User is born.
        firebaseDatabase.child(kUSER).child(uid).updateChildValues(user, withCompletionBlock: { (error: Error?, ref: DatabaseReference) in
            if error != nil {
                // Uh-oh, an error occurred!

                let logError = LogError(errorCode: kSAVING_USER_PROFILE_ERROR_CODE, errorLocation: ErrorLocation(filePath: #file, line: #line, column: #column, funcName: #function), description: "An error occurred while writing the user profile data to the firebase database", errorMessage: "\(error.debugDescription)")
                let userError = UserError(errorMessage: kSAVING_USER_PROFILE_ERROR_MESSAGE)
                return completion(.Error(errorCode: kSAVING_USER_PROFILE_ERROR_CODE, logError: logError, userError: userError))
            } else {
                // The user has been written to the database - A User has been born.
                return completion(.Success("The user was successfully written to the database"))
            }
        })
    }

*控制台输出*

  2018-03-10 18:35:30 PM  ::Error::errorCode:: 4021 ::class::UserFBService.swift 
::functionName::fetchCurrentUserProfile(completion:) ::lineNumber::69 
::columnName162  ::UserID::ZE2837447f9tQ0i1z1AHHAFFFWACbg2  ::description::
An error occurred while fetching the current user's profile, some of the 
user's profile data was missing from Firebase  ::errorMessage::

ErrorLogger.swift

enum Result<T> {
    case Success(T)
    case Incomplete(T, errorCode: Int, logError: LogError, userError: UserError)
    case Error(errorCode: Int, logError: LogError?, userError: UserError?)
}

struct LogError {

    var timestamp: String
    var header: String
    var errorCode: Int
    var errorLocation: ErrorLocation
    var userID: String
    var description: String //describes the type of error
    var errorMessage: String //actual error returned by given function

    init(timestamp: String = "", header: String = "", errorCode: Int, errorLocation: ErrorLocation, userID: String = "", description: String, errorMessage: String) {

        self.timestamp = timestamp
        self.header = header
        self.errorCode = errorCode
        self.errorLocation = errorLocation
        self.userID = userID
        self.description = " ::description::" + description
        self.errorMessage = " ::errorMessage::" + errorMessage

        if timestamp.isEmpty {
            self.timestamp = Date().currentUTCTimestamp
        }

        if header.isEmpty {
            self.header = " ::Error::errorCode::"
        }
        if userID.isEmpty {
            self.userID = getUserID()
        }
    }

    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 toString() -> String {
        let fullErrorMessageStr: String = "\(timestamp) \(header) \(errorCode) \(errorLocation.toString()) \(userID) \(description) \(errorMessage)"
        return fullErrorMessageStr
    }
}

struct ErrorLocation {
    var filePath: String
    var line: Int
    var column: Int
    var funcName: String

    init(filePath: String, line: Int, column: Int, funcName: String) {
        self.filePath = filePath
        self.line = line
        self.column = column
        self.funcName = funcName
    }

    func getClassNameFromFilePath() -> String{
        var className: String = ""
        if !filePath.isEmpty {
            let components = filePath.components(separatedBy: "/")
            className = components.isEmpty ? "" : components.last!
        }
        return className
    }

    func toString() -> String {
        let errorLocationStr: String = "::class::\(getClassNameFromFilePath()) ::functionName::\(funcName) ::lineNumber::\(line) ::columnName\(column)"
        return errorLocationStr
    }
}

struct UserError {

    var errorTitle: String
    var errorMessage: String

    init(errorTitle: String, errorMessage: String) { //use this function overloading to specify
        //a different error title when necessary
        self.errorTitle = errorTitle
        self.errorMessage = errorMessage
    }

    init(errorMessage: String) {
        self.errorTitle = kOOPS_USER_ERROR_TITLE //error title defaults to "Oops!" for most cases
        self.errorMessage = errorMessage
    }
}

extension Date {
    var currentUTCTimestamp: String {
        let formatter = DateFormatter()
        formatter.timeZone = TimeZone(identifier: "UTC")
        formatter.dateFormat = "yyyy-MM-dd HH:mm:ss a"
        //formatter.dateFormat = "MMM dd, yyyy hh:mm a"
        return formatter.string(from: self)
    }
}

最佳答案

您可以使用默认参数值:

struct ErrorLocation {
    init(filePath: String = #file, line: Int = #line, column: Int = #column, funcName: String = #function) {

并调用不带参数的初始化程序:ErrorLocation()。编译器将从调用站点推断这些参数的值。

请注意,如果 ErrorLocation 实例化发生在调用层次结构的下方,您还需要转发这些参数,这意味着每个函数都应该具有这些参数和这些值,直到您脱离了记录器层次结构。

所以而不是

struct LogError {
    init(timestamp: String = "", header: String = "", errorCode: Int, errorLocation: ErrorLocation, userID: String = "", description: String, errorMessage: String) {

,你需要这样的东西

struct LogError {
    init(timestamp: String = "", header: String = "", errorCode: Int, userID: String = "", description: String, errorMessage: String, filePath: String = #file, line: Int = #line, column: Int = #column, funcName: String = #function) {
        let errorLocation = ErrorLocation(filePath: filePath, line: lone, column: column, funcName: funcName)
        // rest of the initializer

关于ios - 如何在 Swift 中将 #file、#line、#column、#funcion 传递给我的 ErrorLogger,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49212605/

相关文章:

ios - UITableView beginUpdate/endUpdate 导致滚动到顶部

iphone - 使用来自代码的 JavaScript 在 webview 中设置 HTML 内容。

iOS7-iPhone 呈现 View Controller - UIPickerView

ios - 试图使同一索引路径的多个单元格出队,这是不允许的。错误

ios - 当基于标签文本的宽度和高度时,如何将 UIVisualEffectView 发送到 UILabel 后面

ios - CrashLytics 在初始化后打印一些日志消息,并通过电子邮件发送崩溃日志

iphone - 当数组为空时阻止 Tableview 崩溃?

ios - 自定义 UITableViewCell 重叠对象

ios - swift CollectionView 单元格文本标签自动调整大小

ios - Swift 4 UITableView 单元格高度不起作用