【问题标题】:Read once and then set to nil读取一次,然后设置为零
【发布时间】:2017-12-12 00:06:33
【问题描述】:

我想实现这样一个属性,它的值只能读取一次,然后属性应该设置为nil

我是这样实现的:

private var _readOnce: String?

var readOnce: String? {
    get {
        let value = _readOnce
        _readOnce = nil
        return value
        }
    set {
        _readOnce = newValue
    }
}

readOnce = "Andrej"

print("read once = \(readOnce)")  // prints read once = Optional("Andrej")\n"
print("read once = \(readOnce)")  // prints read once = nil\n"

但我觉得使用单独的属性 _readOnce 不是“迅速”/“最优雅”的方式。

有没有人知道一种不同的方式,不需要使用单独的属性?

我可以确认上面的代码有效,只是我觉得用更少的行来实现相同的行为会更优雅。

【问题讨论】:

  • 很好奇...你为什么要这样做?
  • 我认为我可以使用这种方法对推送通知做出反应,并确保我只做出一次反应。所以我一直在探索这种方法。但现在看来,我将不得不采取不同的方法,因为其他一些事情的表现与我预期的不完全一样。
  • 我不知道你的问题的确切问题。但我正在考虑多种其他方法可以解决这个问题 1. 只需具有布尔属性 somewhere 2. 在 iOS 10 中,不同的委托方法使管理您的意图变得更加容易。也就是说,如果您的通知有content-available : 1,那么您的application(_:didReceiveRemoteNotification:fetchCompletionHandler:) 将被调用。如果用户点击通知didreceivenotificationresponse 将被调用。如果用户在应用程序中,willPresentNotification 将被调用。
  • 棘手的部分是如果你有一个推送通知发送alert/sound,但也有content-available:1,这意味着你会得到2个回调。为此,应该理解并区分您的担忧。对于 iOS9,管理回调要困难得多。见here。至于管理推送通知方面的应用程序状态。见herehere

标签: swift properties


【解决方案1】:

我不知道有什么方法可以避免使用支持属性,但我可能会做一个辅助类型来包装行为。像这样的:

struct OneTimeValue<T>
{
    private var isUnread = true

    private let value : T

    init(_ value: T)
    {
        self.value = value
    }

    func get() -> T?
    {
        guard isUnread else {
            return nil
        }
        self.isUnread = false
        return self.value
    }
}

如果您愿意,您也可以稍微不同地写这个,例如,nilling out value inside get(),但总体计划仍然成立。

那么你的班级就变成了:

class Miser
{
    var readOnce : String?
    {
        return self._readOnce.get()
    }
    private let _readOnce = OneTimeValue("Can't touch this (twice)")
}

我也将此模式用于UserDefaultsValue(存储到/从用户默认值)和SynchronizedValue(属性上的读写锁),我认为它运作良好。

【讨论】:

    【解决方案2】:

    据我所知,没有第二个变量是不可能的。这是因为计算属性不存储它们所代表的变量的任何数据:

    除了存储的属性、类、结构和 枚举可以定义计算属性,但实际上并没有 存储一个值。

    对于非计算属性,您可以拥有的唯一观察者是基于变量的设置,而不是获取(即willSetdidSet

    希望有帮助!

    编辑: 如果你小心的话,可以使用闭包和属性观察器来完成: 这不需要其他变量(取而代之的是闭包捕获的值),但还不清楚——我不推荐它。

    var readOnce: () -> String? = {nil} {
        didSet{
            readOnce = { [weak self, readOnce] in
                self?.readOnce = {nil}
                return readOnce()
            }
        }
    }
    
    readOnce()        // returns nil
    readOnce = {"Hi"} 
    readOnce()        // returns optional wrapped "Hi"
    readOnce()        // returns nil
    

    为您提供更“快速”的答案:D

    【讨论】:

    • didSet 在您的第一个 set 之后,而不是在您的第一个 get /read 之后
    • @Honey 是的,同意——但是这个解决方案是基于在设置readOnce 之后将值更改为闭包的想法。 然后在读取变量时执行此闭包,并将 readOnce 重置为 {nil} 以使其不能被读取两次。上面的代码有效,但同样,由于涉及黑客,我不推荐。
    • 当然,非常有趣的方法,学到了一些新东西。 :) 也同意你的观点,这是一种 hackey,不会在与其他开发人员的项目中使用,因为目前还不清楚发生了什么。
    猜你喜欢
    • 1970-01-01
    • 2018-02-28
    • 1970-01-01
    • 1970-01-01
    • 2012-06-22
    • 2013-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多