0

我正在尝试创建一个独立的类/库,它可以自行运行并在内部处理错误,但也会向前端提供反馈(状态)以进行可能的用户交互。在 Android 中,我会使用 Listener 来解决这个问题:

    class Status(errCode:Int=0, msg:String=""){
    var errCode:Int=0
    var text:String=""
    private var listener: ChangeListener? = null

    init {
        this.errCode=errCode
        this.text=msg
    }

    fun set(errCode:Int, msg:String) {
        this.errCode=errCode
        this.text=msg
        if (listener != null) listener!!.onChange()
    }

    fun getListener(): ChangeListener? {
        return listener
    }

    fun setListener(listener: ChangeListener?) {
        this.listener = listener
    }

    interface ChangeListener {
        fun onChange()
    }
}

每当我想更新它时,例如在异常上,我都会调用:

catch (e: IOException) {
            this.status.set(109,"someException: $e")
        }

在 MainActivity 我只需要处理这些更改:

myObj.status.setListener(object : Status.ChangeListener {
            override fun onChange() {
                when(myObj!!.status.errCode) {
                    //errors
                    109 -> log(myObj!!.status.text) //some Exception
                    111 -> myObj!!.restart() //another exc
                    112 -> myObj!!.checkAll() //some other error
...

在 Swift 中,我发现 didSet 看起来很相似。我读到您可以将其附加到结构上,因此只要结构中的某些内容发生更改,就会调用它。所以我将我的“struct Status”添加到我的“struct myObj”中,如下所示:

struct myObj {
var status:Status=Status(errCode: 0, msg: "Init")

struct Status {
    var errCode:Int
    var msg:String
    
    mutating func set(err:Int, txt:String){
        errCode=err
        msg=txt
    }
}

在我的代码中,我初始化了一个新的 myObj 实例

var mObj:myObj=myObj.init() {
        didSet{
            switch myObj.status.errCode{
            case 1:
                promptOkay()
            case 113:
                obj.errorHandling()
            default:
                log(txt: mObj.status.msg)
            }
        }
    }

然而,它永远不会触发 didSet,即使内部函数应该改变状态。我读到在初始化时没有触发 didSet,但是在初始化应该完全独立运行的类对象后,我现在没有运行任何东西。我想在我走得更远之前验证该方法是否可行,并且必须再次解开所有内容。

4

1 回答 1

2

didSet必须在属性上声明,而不是在初始化期间:

class MyObj {
    var status: Status = Status(errCode: 0, msg: "Init") {
        didSet {
            // status did change
            print("new error code: \(status.errCode)")
        }
    }
    
    struct Status {
        var errCode:Int
        var msg:String
        
        mutating func set(err:Int, txt:String){
            errCode = err
            msg = txt
        }
    }
}

let obj = MyObj()
obj.status.set(err: 10, txt: "error 10") // prints "new error code: 10"

此时,您可以obj.statusdidSetClosure.

编辑——从类外对 didSet 做出反应

如果您想响应 外部的更改MyObj,我建议使用闭包:

class MyObj {
    var status: Status = Status(errCode: 0, msg: "Init") {
        didSet {
            statusDidChange?(status)
        }
    }
    
    // closure to call when status changed
    var statusDidChange: ((Status) -> Void)? = nil
    
    struct Status {
        var errCode:Int
        var msg:String
        
        mutating func set(err:Int, txt:String){
            errCode = err
            msg = txt
        }
    }
}

这样,您可以从外部分配一个闭包来执行自定义操作:

let obj = MyObj()
obj.statusDidChange = { status in
    // status did change
    print("new error code: \(status.errCode)")
}

obj.status.set(err: 10, txt: "error 10") // prints "new error code: 10"

编辑 2 — 直接从初始化调用 didSet 闭包

您也可以statusDidChange在初始化期间手动调用闭包。

class MyObj {
    var status: Status = Status(errCode: 0, msg: "Init") {
        didSet {
            statusDidChange(status)
        }
    }
    
    // closure to call when status changed
    var statusDidChange: (Status) -> Void
    
    init(status: Status, statusDidChange: @escaping (Status) -> Void) {
        self.status = status
        self.statusDidChange = statusDidChange
        self.statusDidChange(status)
    }
}

let obj = MyObj(status: MyObj.Status(errCode: 9, msg: "error 09")) { status in
    // status did change
    print("new error code: \(status.errCode)")
}

obj.status.set(err: 10, txt: "error 10")

这将打印

new error code: 9
new error code: 10
于 2020-12-07T11:46:05.953 回答