在Swift数组和NSArrays之间进行转换很容易。我找到了一个我认为不应编译的案例:
let doubleArray = [1.1, 2.22, 3.333, 4.4444, 5.55555,
6.666666, 7.7777777, 8.88888888, 9.999999999]
var objCArray = doubleArray as NSArray
第二行从我的Swift双精度数组中创建一个NSArray,但它将它存储在var
中。这测试了编译器改变数组内容的合法性。这意味着如果你试图改变数组,你会得到一个错误,即使objCArray被声明为var
:
objCArray[0] = 123
为什么行var objCArray = doubleArray as NSArray
合法?
答案 0 :(得分:5)
let doubleArray = [1.1, 2.22, 3.333, 4.4444, 5.55555, 6.666666, 7.7777777, 8.88888888, 9.999999999]
var objCArray = doubleArray as NSArray
为什么行var objCArray = doubleArray为NSArray legal
因为,与其他var
声明一样,它允许您替换变量的值。在这种情况下,您可以使用不同的 NSArray替换objCArray
的NSArray:
objCArray = [2.9]
然而,NSArray本身是不可改变的。这只是关于这个Objective-C类的一个事实。因此,例如,您无法分配到objCArray[0]
。这与let
与var
无关;这是关于NSArray本身是什么的事实:
objCArray[0] = 123 // error
现在,您可能会说:这与Swift结构的工作完全不同。非常真实!但是NSArray 不是一个Swift结构。它不是Swift,它不是结构。这是一个Objective-C课程! Swift Array是一个Swift结构,你应该使用它。
进一步讨论:这个问题显然是荒谬的,我们甚至可以通过专注于Swift结构来看到这一点:
如果结构引用本身是用var
声明的,则允许您在Swift 中分配结构的var
属性。
如果使用{声明结构引用本身, 允许在Swift中分配给结构的let
属性,甚至 {1}}。
但这并不意味着,只是因为结构只有var
属性,所以不能用let
声明它!那太荒谬了。然而,荒谬与你问题中的荒谬完全相同。
var
答案 1 :(得分:2)
这是有效的,因为var
只是意味着您可以稍后在评论中指出其他内容。 NSArray
是一个不可变对象。在NSArray
的基金会Swift模块中,subscript
仅标记为get
:
extension NSArray {
// ...
@available(iOS 6.0, *)
open subscript(idx: Int) -> Any { get }
// ...
}
至于为什么桥接合法,请参阅Swift Array模块中的这个注释:
/// Bridging Between Array and NSArray /// ================================== /// /// When you need to access APIs that expect data in an `NSArray` instance /// instead of `Array`, use the type-cast operator (`as`) to bridge your /// instance. For bridging to be possible, the `Element` type of your array /// must be a class, an `@objc` protocol (a protocol imported from Objective-C /// or marked with the `@objc` attribute), or a type that bridges to a /// Foundation type. /// /// The following example shows how you can bridge an `Array` instance to /// `NSArray` to use the `write(to:atomically:)` method. In this example, the /// `colors` array can be bridged to `NSArray` because its `String` elements /// bridge to `NSString`. The compiler prevents bridging the `moreColors` /// array, on the other hand, because its `Element` type is /// `Optional<String>`, which does *not* bridge to a Foundation type. /// /// let colors = ["periwinkle", "rose", "moss"] /// let moreColors: [String?] = ["ochre", "pine"] /// /// let url = NSURL(fileURLWithPath: "names.plist") /// (colors as NSArray).write(to: url, atomically: true) /// // true /// /// (moreColors as NSArray).write(to: url, atomically: true) /// // error: cannot convert value of type '[String?]' to type 'NSArray' /// /// Bridging from `Array` to `NSArray` takes O(1) time and O(1) space if the /// array's elements are already instances of a class or an `@objc` protocol; /// otherwise, it takes O(*n*) time and space. /// /// Bridging from `NSArray` to `Array` first calls the `copy(with:)` /// (`- copyWithZone:` in Objective-C) method on the array to get an immutable /// copy and then performs additional Swift bookkeeping work that takes O(1) /// time. For instances of `NSArray` that are already immutable, `copy(with:)` /// usually returns the same array in O(1) time; otherwise, the copying /// performance is unspecified. The instances of `NSArray` and `Array` share /// storage using the same copy-on-write optimization that is used when two /// instances of `Array` share storage. /// /// - Note: The `ContiguousArray` and `ArraySlice` types are not bridged; /// instances of those types always have a contiguous block of memory as /// their storage. /// - SeeAlso: `ContiguousArray`, `ArraySlice`, `Sequence`, `Collection`, /// `RangeReplaceableCollection`
答案 2 :(得分:0)
NSArray
是一个不可变对象。有一个名为NSArray
的{{1}}子类,允许您修改它包含的对象。如果您将代码更改为NSMutableArray
,则可以执行您要求的操作。
答案 3 :(得分:0)
类型转换是合法的,因为Swift不可变数组(doubleArray)通过自动(免费)桥接与NSArray兼容。因此,您对objCArray的赋值为您提供了对基础值类型(即不可变)的可变引用。
从那时起,objCArray被视为引用类型。
这意味着您可以执行对象类型(NSArray)允许的任何方法,并将新对象实例分配给变量(objCArray)。
在这种情况下,NSArray类旨在操作不可变数组,因此它不允许您为下标赋值。编译器根据NSArray的下标实现检测到这一点,而不是基于引用NSArray对象的变量的可变性。
这是引用类型(NSArray)和有价值类型(Swift Array)之间的差异之一,它可以按预期工作。当应用于有价值的类型时,Swift的“let”可以防止对变量内容进行任何修改。对引用类型使用“let”可以防止更改引用变量,但允许您修改引用对象的内容。