Objective c 为什么从Swift使用NSArray时是可变的?

Objective c 为什么从Swift使用NSArray时是可变的?,objective-c,swift,nsarray,Objective C,Swift,Nsarray,我有一个具有以下属性的objective-c头 @property (nullable, nonatomic, strong) NSArray<CustomObject *> *customObjects; 如果我这样做的话 print(type(of: self.customObjects)) 我得到: Array<CustomObject> 数组 NSArray不是一成不变的吗?Swift是否会在我们编辑它时创建一个浅拷贝 您的属性(隐式)在ObjC中声明为r

我有一个具有以下属性的objective-c头

@property (nullable, nonatomic, strong) NSArray<CustomObject *> *customObjects;
如果我这样做的话

print(type(of: self.customObjects))
我得到:

Array<CustomObject>
数组
NSArray不是一成不变的吗?Swift是否会在我们编辑它时创建一个浅拷贝

您的属性(隐式)在ObjC中声明为
readwrite
。这意味着您可以通过编写一个新的
NSArray
实例来替换旧实例来更改属性(在这种情况下,新实例的常量可以通过首先读取另一个
NSArray
实例(即属性的现有值)来派生):

在Swift中,您的属性显示为
Swift.Array
(即Swift标准库中的
Array
类型),这是一种值类型。每个赋值在语义上都创建一个副本。(使用“写时复制”模式,执行复制的昂贵工作可以推迟。引用类型数组(如对象)复制引用而不是存储,因此它本质上是“浅层复制”。)

变异操作也可以做到这一点:

let currentObjects1 = self.customObjects
currentObjects1.remove(0) // compile error
// currentObjects1 is a `let` constant so you can't mutate it

var currentObjects = self.customObjects
currentObjects.remove(0) // ok

print(self.customObjects.count - currentObjects.count) 
// this is 1, because currentObjects is a copy of customObjects
// we mutated the former but not the latter so their count is different

self.customObjects = currentObjects
// now we've replaced the original with the mutated copy just as in the ObjC example
当您在Swift中拥有readwrite属性,并且该属性的类型是值类型,如
数组
(或者是桥接到值类型的ObjC类型,如
NSArray
),您可以直接在该属性上使用变异方法。这是因为调用mutating方法在语义上等同于读取(并复制)现有值,对副本进行mutating,然后写回更改后的副本

// all equivalent
self.customObjects.remove(0)
self.customObjects = self.customObjects.dropFirst(1)
var objects = self.customObjects; objects.remove(0); self.customObjects = objects


BTW:如果你在这里设计了Objc类的API,你可以考虑让你的<代码> CubObjs< /Cuff>属性为NULL——除非空数组和缺少数组之间有一个有意义的语义差异,否则你的Swift客户端会发现需要区分这两个数组。有一个称为NSMutableArray的可变版本。这是因为您没有将其用作

NSMutableArray
。您已经准确描述了当前Swift编译器的功能,但显然,删除不可变性并不是唯一的选择。您是否有关于这是定义行为的参考?(是的,我知道Swift没有正式的语义,但它的一些指示行为很好,比如这不仅仅是当前编译器的产物。)
let currentObjects1 = self.customObjects
currentObjects1.remove(0) // compile error
// currentObjects1 is a `let` constant so you can't mutate it

var currentObjects = self.customObjects
currentObjects.remove(0) // ok

print(self.customObjects.count - currentObjects.count) 
// this is 1, because currentObjects is a copy of customObjects
// we mutated the former but not the latter so their count is different

self.customObjects = currentObjects
// now we've replaced the original with the mutated copy just as in the ObjC example
// all equivalent
self.customObjects.remove(0)
self.customObjects = self.customObjects.dropFirst(1)
var objects = self.customObjects; objects.remove(0); self.customObjects = objects