- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
在Swift中,当您传递值类型时,对函数说一个数组。制作数组副本供功能使用。
但是,https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/ClassesAndStructures.html#//apple_ref/doc/uid/TP40014097-CH13-XID_134上的文档还说:
上面的描述指的是字符串,数组和字符串的“复制”。
字典。您在代码中看到的行为将始终像
复制发生了。但是,Swift仅在后面执行实际复制
绝对必要时在场景中进行。斯威夫特管理所有
值复制以确保最佳性能,您不应避免
尝试抢先进行此优化。
那么这是否意味着仅在修改传递的值类型时才进行复制?
有没有办法证明这实际上是潜在的行为?
为什么这很重要?如果我创建一个大的不可变数组,并希望将其从一个函数传递到另一个函数,那么我当然不希望继续制作它的副本。在这种情况下,我应该只使用NSArrray还是Swift Array正常工作,只要我不尝试操纵传入的Array?
现在,只要我没有通过使用var或inout显式使函数中的变量可编辑,那么该函数无论如何都无法修改数组。那它仍然会复制吗?允许另一个线程可以在其他地方修改原始数组(仅在可变的情况下),并在调用该函数时创建一个副本(但仅在传入的数组是可变的情况下)。因此,如果原始数组是不可变的,并且该函数未使用var或inout,则Swift不会创建副本。对?那么,苹果这句话是什么意思呢?
最佳答案
TL; DR:
那么这是否意味着仅在修改传递的值类型时才进行复制?
是!
有没有办法证明这实际上是潜在的行为?
请参见写时复制优化部分中的第一个示例。
我应该在这种情况下使用NSArrray还是Swift Array可以正常工作
只要我不尝试操纵Array中传递的内容?
如果您将数组作为inout
传递,则将具有按引用传递语义,
因此显然避免了不必要的复制。
如果您将数组作为常规参数传递,
那么写时复制优化将开始进行,您应该不会注意到任何性能下降
同时仍然受益于NSArray
带来的更多类型安全性。
现在,只要我不显式使函数中的变量可编辑
通过使用var或inout,该函数无论如何都无法修改数组。
那它仍然会复制吗?
您将获得抽象意义上的“副本”。
实际上,由于写时复制机制,基础存储将被共享,
因此避免不必要的复制。
如果原始数组是不可变的,并且该函数未使用var或inout,
Swift创建副本没有任何意义。对?
确实如此,因此是写时复制机制。
那么,苹果这句话是什么意思呢?
从本质上讲,Apple意味着您不必担心复制值类型的“成本”,
Swift会在幕后为您优化它。
相反,您应该考虑值类型的语义,
这是您分配或将其用作参数后立即获得一份副本。
Swift的编译器实际生成的是Swift的编译器业务。
值类型语义
Swift确实确实将数组视为值类型(与引用类型相对),
以及结构,枚举和大多数其他内置类型
(即那些属于标准库而不是Foundation的库)。
在内存级别,这些类型实际上是不可变的普通旧数据对象(POD),
可以进行有趣的优化。
实际上,它们通常分配在堆栈上,而不是堆上[1],
(https://en.wikipedia.org/wiki/Stack-based_memory_allocation)。
这样,CPU可以非常有效地管理它们,
并在函数退出后立即自动释放其内存[2],
无需任何垃圾收集策略。
赋值或作为函数传递值时,将复制值。
这种语义有很多优点,
例如避免创建意外的别名,
而且还使编译器更容易保证值的生存期
存储在另一个对象中或由闭包捕获。
我们可以考虑管理好旧的C指针来理解原因有多么困难。
可能有人认为这是一个构思错误的策略,
因为它涉及每一次分配变量或调用函数时进行复制。
但是可能违反直觉,
复制小型字体通常比通过引用便宜很多。
毕竟,指针通常与整数大小相同...
但是,对于大型集合(即数组,集合和字典)而言,顾虑是合理的,
和大型结构(程度较小)[3]。
但是编译器有一个技巧来处理这些问题,即写时复制(请参阅后面)。
那么mutating
结构可以定义mutating
方法,
允许改变结构的字段。
这与值类型仅是不可变的POD并不矛盾,
因为实际上调用mutating
方法仅仅是一个巨大的语法糖
将变量重新分配为与先前值相同的全新值,
除了已突变的字段。
以下示例说明了这种语义对等:
struct S {
var foo: Int
var bar: Int
mutating func modify() {
foo = bar
}
}
var s1 = S(foo: 0, bar: 10)
s1.modify()
// The two lines above do the same as the two lines below:
var s2 = S(foo: 0, bar: 10)
s2 = S(foo: s2.bar, bar: s2.bar)
inout
inout
参数只不过是指向所需类型的读写指针。
inout
关键字)。
func f(x: inout [Int]) {
x.append(12)
}
var a = [0]
f(x: &a)
// Prints '[0, 12]'
print(a)
func f(x: inout NSArray) {
x = [12]
}
var a: NSArray = [0]
f(x: &a)
// Prints '(12)'
print(a)
let array1 = [1, 2, 3]
var array2 = array1
// Will print the same address twice.
array1.withUnsafeBytes { print($0.baseAddress!) }
array2.withUnsafeBytes { print($0.baseAddress!) }
array2[0] = 1
// Will print a different address.
array2.withUnsafeBytes { print($0.baseAddress!) }
array2
不会立即获得
array1
的副本,
array2
的突变触发的。
var array1 = [[1, 2], [3, 4]]
var array2 = array1
// Will print the same address twice.
array1[1].withUnsafeBytes { print($0.baseAddress!) }
array2[1].withUnsafeBytes { print($0.baseAddress!) }
array2[0] = []
// Will print the same address as before.
array2[1].withUnsafeBytes { print($0.baseAddress!) }
final class Wrapped<T> {
init(value: T) { self.value = value }
var value: T
}
struct CopyOnWrite<T> {
init(value: T) { self.wrapped = Wrapped(value: value) }
var wrapped: Wrapped<T>
var value: T {
get { return wrapped.value }
set {
if isKnownUniquelyReferenced(&wrapped) {
wrapped.value = newValue
} else {
wrapped = Wrapped(value: newValue)
}
}
}
}
var a = CopyOnWrite(value: SomeLargeObject())
// This line doesn't copy anything.
var b = a
isKnownUniquelyReferenced
文档会收到以下警告:
CopyOnWrite
实例,则会发生这种情况,
isKnownUniquelyReferenced
[4],
isKnownUniquelyReferenced
接受
inout
参数的原因,
关于swift - 快速值类型的复制何时发生,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56895905/
如何更改循环中变量的名称?比如 number1 、 number2 、 number3 、 number4 ? var array = [2,4,6,8] func ap ( number1: Int
我想设置 View 的背景颜色并在一定延迟后将其更改为另一种颜色。这是我的尝试方式: print("setting color 1") self.view.backgroundColor = UICo
我在使用 express-session 时遇到问题。 session 数据不会在请求之间持续存在。 正如您在下面的代码中看到的那样,/join 路由设置了一些 session 属性,但是当 /sur
我试图从叶渲染器获得一个非常简单的结果,用于快速 Steam 的 for 循环。 我正在上传叶文件 HTML,因为它不接受此处格式正确的代码 - 下面的pizza.swift代码- import
你们中有人有什么好的链接可以与我分享吗?我正在寻找一个 FAST 程序员编辑器,它可以非常快速地打开包含超过 100, 000 行代码的文件?我目前正在使用记事本自动取款机,打开一个 29000 行长
我现在正在处理眼动追踪数据,因此拥有一个巨大的数据集(想想数百万行),因此希望有一种快速的方法来完成此任务。这是它的简化版本。 数据告诉您眼睛在每个时间点正在查看的位置以及我们正在查看的每个文件。 X
我是新手,想为计时器或其他设备选择提示音。 如何打开此列表,以选择其中一种声音? Alert sound list 最佳答案 您将无法在应用中使用系统声音。 但是,您可以包括自己的声音文件,并将其显示
我编写了以下代码来构建具有顺序字符串的数组。 它的工作方式与我预期的一样,但我希望它能更快地运行。有没有更有效的方法在PowerShell中产生我想要的结果? 我是PowerShell的新手,非常感谢
我有一个包含一些非唯一行的矩阵,例如: x 尝试 y <- rle(apply(x, 1, paste, collapse = " ")) # y$lengths is the vector con
我的函数“keyboardWillShown”有问题。所以我想要的是菜单打开时,菜单正好出现在键盘上方。它可以在Iphone 8 plus,8、7、6上完美运行。但是,当我在模拟器上运行Iphone
我正在尝试通过Swift 5中的HTTP get方法从API提取数据。它在启动时成功加载了数据,但是当我刷新页面时,它说“索引超出范围”,这是因为数据是不再会在我的日志中读取,因此索引中没有任何内容。
我想做什么: 从我的数据库中获取时间戳并将其转换为用户的时区。 我的代码: let tryItNow = "\(model.timestampName)" let format = D
给定字体名称和字体大小,如何查找字符串的宽度(CGFloat)? (目标是将UIView的宽度设置为足以容纳字符串的宽度。) 我有两个字符串:一个重复“1”,重复36次,另一个重复“M”,重复36次。
我正在尝试解析此JSON ["Items": ( { AccountBalance = 0; AlphabetType = 3; Description = "\U0631\U
我在UINavigationBar内放置了一个UILabel。 我想根据navigationBar的高度增加该标签的字体大小。当navigationBar很大时,我希望字体大小更大;当滚动并缩小nav
我想将用户输入限制为仅有效数字并使用以下内容: func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, rep
目前我有一个包含超过 100.000 张图像的数据库,它们大小不一或类似,但我想为我的公司制作以下内容: 我插入/上传一张图片,系统返回最有可能相同的图片。我不知道使用什么算法,但它需要快速。我可以预
在我的 swift 项目中,我有一个按钮,我想在标签上打印按下该按钮的时间。 如何解决这个问题? 最佳答案 添加到DHEERAJ的答案中,您只需在func press(sender: UIButton
我必须发表评论,尝试在解析中导入数组。然而,有一个问题。 当我尝试从 Parse 加载数组时,我的输出是 ("Blah","Blah","Blah")这是一个元组...而不是一个数组 TT... 如何
我的应用程序有一个名为 MyDevice 的类,我用它来与硬件通信。该硬件是可选的,实例变量也是可选的: var theDevice:MyDevice = nil 然后,在应用程序中,我必须初始化设备
我是一名优秀的程序员,十分优秀!