Swift tricks系列收集Swift牛逼的patterns和让你代码更加Swifty的tricks,持续更新中……
开始今天的话题前,我们先来看几行代码:
let unsafemutablepointer : UnsafeMutablePointer<Int>
unsafemutablepointer = UnsafeMutablePointer.alloc(3)
unsafemutablepointer[0] = 1
unsafemutablepointer[1] = 2
unsafemutablepointer[2] = 3
///////////
let intArray : Array<Int> = [1,2,3]
intArray[1] = 3
****上面代码有什么问题?****
可能你已经想到了,编译器会报错,因为我们在尝试修改一个常量数组。
“If you create an instance of a structure and assign that instance to a constant, you cannot modify the instance’s properties, even if they were declared as variable properties”
“This behavior is due to structures being value types. When an instance of a value type is marked as a constant, so are all of its properties.”
那么,另外一个问题来了:同样是用下标访问,同样是值类型(Value Type),为什么UnsafeMutablePointer
不会报错?
UnsafeMutablePointer
和Array
都是struct
,存储的类型也一样都是Int
,额……
Array:
public subscript (index: Int) -> Element
UnsafeMutablePointer:
public subscript (i: Int) -> Memory { get nonmutating set }
nonmutating
是什么东西?!
nonmutating
nonmutating
是swift的一个关键字,它和mutating
一样用来修饰方法,只不过nonmutating
一般用来修饰setter方法。
当用nonmutating
修饰setter方法的时候,swift编译器会知道该方法并不会改变常量变量,因此不会报错。
使用nonmutating有一定的危险性,因为它跳过了swift编译器的安全检查机制。不过我们可以在合适的情况下使用它,写出更加灵活的代码
假设我们想通过下标访问NSUserDefaults
,我们会这么做:
extension NSUserDefaults {
subscript(key: String) -> AnyObject? {
get { return objectForKey(key) }
set { setObject(newValue, forKey: key) }
}
}
var defaults: NSUserDefaults = NSUserDefaults.standardUserDefaults()
defaults["key"] = "value"
不幸的是,defaults
是mutable的,这就意味着它可以被别人重新赋值,进而引发问题。使用nonmutating
,我们就可以这样做:
protocol NSUserDefaultsSubscipt {
subscript(key: String) -> AnyObject? { get nonmutating set }
}
extension NSUserDefaults:NSUserDefaultsSubscipt {
subscript(key: String) -> AnyObject? {
get { return objectForKey(key) }
set { setObject(newValue, forKey: key) }
}
}
let defaults: NSUserDefaults = NSUserDefaults.standardUserDefaults()
defaults["key"] = "value"
现在再看defaults
是不是有点class的感觉?