【问题标题】:Prevent forced optional unwrapping after object initialization防止对象初始化后强制可选展开
【发布时间】:2016-08-03 11:43:38
【问题描述】:

我想知道在使用这样的代码时是否可以删除强制展开 (Swift):

var currentProductRequest : SKProductsRequest?

public func requestProducts() -> Bool {
    currentProductRequest = SKProductsRequest(productIdentifiers: Set<String>(identifiers))
    currentProductRequest!.delegate = self
    currentProductRequest!.start()
}

在这种情况下 currentProductRequest 将 100% 不为零;然而,它是可选的,在上述上下文中,编译器不知道它不会为 nil,它需要强制展开。 由于初始化 SKProductsRequest 永远不会产生 nil 我不能使用

if let request = SKProductsRequest(productIdentifiers: Set<String>(identifiers)) {
    ....
}

我知道的一种方法是让 currentProductRequest 的声明像 var currentProductRequest : SKProductsRequest! 一样隐式展开。然而,这会使编译器认为 currentProductRequest 永远不会是 nil,而事实可能并非如此。

我知道强制展开永远不会导致问题(在这种情况下),但它对我来说似乎很难看。有谁知道是否有办法让编译器知道 currentProductRequest 不会是 nil 从而消除强制解包。

【问题讨论】:

    标签: swift swift2 forced-unwrapping


    【解决方案1】:

    在这种情况下,我更喜欢定义具有相同名称的局部常量,并使用 self 关键字将其分配给属性,就像我们在初始化程序中所做的那样:

    var currentProductRequest : SKProductsRequest?
    
    public func requestProducts() -> Bool {
        let currentProductRequest = SKProductsRequest(productIdentifiers: Set<String>(identifiers))
        self.currentProductRequest = currentProductRequest
        currentProductRequest.delegate = self
        currentProductRequest.start()
        return true
    }
    

    【讨论】:

    • 感谢您的回复,该解决方案已经由 Abizern 发布(除了重载名称和使用 self.)。不过还是谢谢你!
    【解决方案2】:

    我通常这样做的方式是创建一个非可选对象,对其进行配置,然后将其设置为参数:

    var currentProductRequest : SKProductsRequest?
    
    public func requestProducts() -> Bool {
        let productRequest = SKProductsRequest(productIdentifiers: Set<String>(identifiers))
        productRequest.delegate = self
        productRequest.start()
        currentProductRequest = productRequest
    }
    

    编辑添加

    还有另一种方法可以做到这一点,但有点做作:创建一个公共变量,透明地解开可选项并返回它,这样您就不必处理可选项:

    private var _currentProductRequest : SKProductsRequest?
    
    public var currentProductRequest: SKProductsRequest = {
        return _currentProductRequest!
    }()
    
    public func requestProducts() -> Bool {
        let productRequest = SKProductsRequest(productIdentifiers: Set<String>(identifiers))
        productRequest.delegate = self
        productRequest.start()
        _currentProductRequest = productRequest
    }
    

    但这可能有点过头了。

    【讨论】:

    • 这是一个很好的解决方法。如果没有针对我的要求设计的其他语法,我肯定会使用这种方法
    【解决方案3】:

    如果您的identifiers 不是可选的,您可以从lazy var 中受益:

    lazy var currentProductRequest: SKProductsRequest = {
            let productRequest = SKProductsRequest(productIdentifiers: Set<String>(identifiers))
            productRequest.delegate = self
            return productRequest
        }()
    
    public func requestProducts() -> Bool {
        currentProductRequest!.start()
    }
    

    【讨论】:

    • 这是一个很好的解决方案,但是我的标识符是可变的(按设计)。然而,它是许多其他情况的解决方案:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多