【问题标题】:Why is NSArray mutable when used from Swift?为什么在 Swift 中使用时 NSArray 是可变的?
【发布时间】:2019-03-15 18:51:57
【问题描述】:

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

@property (nullable, nonatomic, strong) NSArray<CustomObject *> *customObjects;

如果我创建该类的快速扩展,我现在可以从 NSArray 中删除对象:

self.customObjects?.remove(at: 0)

如果我这样做了

print(type(of: self.customObjects))

我明白了:

Array<CustomObject>

NSArrays 不是不可变的吗? Swift 是否会在我们编辑时创建一个浅拷贝?

【问题讨论】:

标签: objective-c swift nsarray


【解决方案1】:

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

NSArray *currentObjects = self.customObjects;
// one of many ways to derive one immutable array from another:
NSArray *newArray = [currentObjects subarrayWithRange:NSMakeRange(1, currentObjects.count - 1)];
self.customObjects = newArray;

在 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 中有一个读写属性,并且该属性的类型是像 Array 这样的值类型(或者是桥接到值类型的 ObjC 类型,比如 NSArray),你可以使用变异方法直接在物业上。这是因为调用变异方法在语义上等同于读取(和复制)现有值,变异副本,然后写回更改的副本。

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

顺便说一句:如果您在这里为所讨论的 ObjC 类设计 API,您可能会考虑使您的 customObjects 属性为非空 - 除非空数组和缺失数组之间存在有意义的语义差异,否则您的 Swift 客户端将觉得需要区分两者很麻烦。

【讨论】:

  • 您已经准确地描述了当前 Swift 编译器的功能,但显然移除不变性并不是这里唯一可以做出的选择。您对此有 defined 行为的参考吗? (是的,我知道 Swift 没有正式的语义,但它对像这样的一些指示行为很好,这不仅仅是当前编译器的产物。)
猜你喜欢
  • 2015-05-25
  • 2015-12-01
  • 1970-01-01
  • 2023-03-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多