打开时崩溃nil可选

时间:2016-01-17 13:08:27

标签: ios swift macos generics optional

我创建了一个新的运算符,只有当值不为nil时才将值与目标关联,否则不执行任何操作。 基本上它是if let foo = foo { faa = foo }的合成糖:

infix operator =? {}
func =?<T>(inout lhs: T, rhs: T?) {
    if let rhs = rhs {
        lhs = rhs
    }
}
func =?<T>(inout lhs: T?, rhs: T?) {
    if let rhs = rhs {
        lhs = rhs
    }
}

这样我可以节省一些打字:

// instead this:
if let x = maybeX {
    z = x
}

// I can do this:
z =? x

我的问题是,当我到达执行行(z =? x)时,我甚至在进入实现函数之前崩溃,但异常:

fatal error: unexpectedly found nil while unwrapping an Optional value

即使实现接受x,Swift也会尝试强制解包T?

有什么想法吗?

2 个答案:

答案 0 :(得分:0)

这似乎是我的错误......我正在使用foo.z = ...,其中foo是nil UIImageView! ...来自nib的那些... ...

我很乐意在@RMenke建议后使用nil合并运算符更改我的实现,但据我所知,当x为nil时,这将导致将z设置为z的冗余操作... e.g:

var z = someFoo()
var x: Int? = nil
z = x ?? z
// will this re-write z's reference to z again or simply do nothing?

@MartinR发表了重要评论:

  

如果操作符(或函数)接受inout参数,那么即使您没有在运算符内分配新值,也会在返回时调用属性设置器

尝试解决此问题,我将以下扩展作为_ = foo.map...方法的更简洁版本:

extension Optional {
    public func use<U>(@noescape f: (Wrapped) throws -> U) rethrows {
        _ = try self.map(f)
    }
}

//then:
x.use{ z = $0 }

它可能更好,因为当x为零时它不会调用z的setter,但它是最干净/最清晰的方式吗?

答案 1 :(得分:-1)

您的运算符有效,但您应该使用链式选项:foo?.z = ...

但是,当foo为nil时,这会给你另一种错误,你可以通过添加

来解决
func =?<T>(lhs: T??, rhs: T?) -> ()
{}

这&#34;什么都不做&#34;运算符的版本吸收了在传递最后一个成员之前具有nil的可选链时获得的不可变参数版本。