- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
以下是我的猜测。请大家指出我理解错误的部分。
如果我有一个类,其中一个实例占用128位,叫做Class128Bits
.我的程序在 64 位计算机上运行。
首先,我调用 let pointer = UnsafeMutablePointer<Calss128Bits>.allocate(capacity: 2)
内存布局应该是这样的:
000-063 064 bits chaos
064-127 064 bits chaos
128-255 128 bits chaos
256-383 128 bits chaos
如果我调用 pointer.pointee = aClass128Bits
,它崩溃了,因为前两个网格中的指针还没有被初始化。访问它们指向的内容会导致不可预测的结果。
但是如果我调用 pointer.initialize(to: aClass128Bits, count: 2)
,指针可以像这样初始化:
000-063 address to offset 128
064-127 address to offset 256
128-255 a copy of aClass128Bits
256-383 a copy of aClass128Bits
那么任何访问都是安全的。然而,这不能解释为什么 UnsafeMutablePointer<Int>
不会崩溃。
指向Int
的指针工作正常,但是 String
的那个崩溃。我知道我需要像这样初始化它:
但我看不出为什么我需要通过 "42"
两次。在 C 中,我可能会做类似这样的事情:
char *pointer = (char *)malloc(3 * sizeof(char));
memcpy(pointer, "42", 3);
free(pointer)
如果allocate
等于 malloc
, free
等于 deallocate
, memcpy
等于 pointee{ set }
,然后做什么initialize
和 deinitialize
实际上呢?为什么我的代码会崩溃?
最佳答案
let pointer0 = UnsafeMutablePointer<String>.allocate(capacity: 1)
let pointer1 = UnsafeMutablePointer<Int>.allocate(capacity: 1)
让我们检查两者的大小
MemoryLayout.size(ofValue: pointer0) // 8
MemoryLayout.size(ofValue: pointer1) // 8
让我们检查 .pointee 的值
pointer0.pointee // CRASH!!!
同时
pointer1.pointee // some random value
为什么?答案很简单。我们分配了 8 个字节,独立于“关联”类型。现在很清楚了,内存中的 8 个字节不足以存储任何字符串。必须间接引用底层内存。但是那里有大约 8 个随机字节......加载内存中的内容,地址由 8 个随机字节表示为字符串,很可能会崩溃:-)
为什么第二种情况没有崩溃? Int值是8字节长,地址可以用Int值表示。
让我们在 Playground 上试试
import Foundation
let pointer = UnsafeMutablePointer<CFString>.allocate(capacity: 1)
let us = Unmanaged<CFString>.passRetained("hello" as CFString)
pointer.initialize(to: us.takeRetainedValue())
print(pointer.pointee)
us.release()
// if this playground crash, try to run it again and again ... -)
print(pointer.pointee)
看看它给我打印了什么 :-)
hello
(
"<__NSCFOutputStream: 0x7fb0bdebd120>"
)
背后没有奇迹。 pointer.pointee 试图表示内存中的内容,哪个地址存储在我们的指针中,作为其关联类型的值。它永远不会为 Int 崩溃,因为内存中某处的每 8 个连续字节都可以表示为 Int。
Swift 使用 ARC,但创建 Unsafe[Mutable]Poiner 不会为 T 的实例分配任何内存,销毁它也不会为其释放任何内存。
类型化内存必须在使用前初始化,使用后反初始化。这是分别使用 initialize 和 deinitialize 方法完成的。只有非平凡类型才需要取消初始化。也就是说,包括去初始化是一种让代码面向 future 的好方法,以防您更改为不平凡的东西
为什么赋值给具有 Int 值的 .pointee 不会崩溃?
如果不初始化它很可能会崩溃,只是通过在某个随机地址处仅修改内存中的 8 个字节来降低概率。
试试这个
import Darwin
var k = Int16.max.toIntMax()
typealias MyTupple = (Int32,Int32,Int8, Int16, Int16)
var arr: [MyTupple] = []
repeat {
let p = UnsafeMutablePointer<MyTupple>.allocate(capacity: 1)
if k == 1 {
print(MemoryLayout.size(ofValue: p), MemoryLayout.alignment(ofValue: p),MemoryLayout.stride(ofValue: p))
}
arr.append(p.pointee)
k -= 1
defer {
p.deallocate(capacity: 1)
}
} while k > 0
let s = arr.reduce([:]) { (r, v) -> [String:Int] in
var r = r
let c = r["\(v.0),\(v.1),\(v.2),\(v.3)"] ?? 0
r["\(v.0),\(v.1),\(v.2),\(v.3)"] = c + 1
return r
}
print(s)
我收到了
8 8 8
["0,0,-95,4104": 6472, "0,0,0,0": 26295]
Program ended with exit code: 0
看起来不是很随意,是吗?这就解释了为什么指向 Int 的类型化指针发生崩溃的可能性很小。
关于ios - `UnsafeMutablePointer.initialize()`到底是做什么的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39716984/
IO 设备如何知道属于它的内存中的值在memory mapped IO 中发生了变化? ? 例如,假设内存地址 0 专用于保存 VGA 设备的背景颜色。当我们更改 memory[0] 中的值时,VGA
我目前正在开发一个使用Facebook sdk登录(通过FBLoginView)的iOS应用。 一切正常,除了那些拥有较旧版本的facebook的人。 当他们按下“使用Facebook登录”按钮时,他
假设我有: this - is an - example - with some - dashesNSRange将使用`rangeOfString:@“-”拾取“-”的第一个实例,但是如果我只想要最后
Card.io SDK提供以下详细信息: 卡号,有效期,月份,年份,CVV和邮政编码。 如何从此SDK获取国家名称。 - (void)userDidProvideCreditCardInfo:(Car
iOS 应用程序如何从网络服务下载图片并在安装过程中将它们安装到用户的 iOS 设备上?可能吗? 最佳答案 您无法控制应用在用户设备上的安装,因此无法在安装过程中下载其他数据。 只需在安装后首次启动应
我曾经开发过一款企业版 iOS 产品,我们公司曾将其出售给大型企业,供他们的员工使用。 该应用程序通过 AppStore 提供,企业用户获得了公司特定的配置文件(包含应用程序配置文件)以启用他们有权使
我正在尝试将 Card.io SDK 集成到我的 iOS 应用程序中。我想为 CardIO ui 做一个简单的本地化,如更改取消按钮标题或“在此保留信用卡”提示文本。 我在 github 上找到了这个
我正在使用 CardIOView 和 CardIOViewDelegate 类,没有可以设置为 YES 的 BOOL 来扫描 collectCardholderName。我可以看到它在 CardIOP
我有一个集成了通话工具包的 voip 应用程序。每次我从我的 voip 应用程序调用时,都会在 native 电话应用程序中创建一个新的最近通话记录。我在 voip 应用程序中也有自定义联系人(电话应
iOS 应用程序如何知道应用程序打开时屏幕上是否已经有键盘?应用程序运行后,它可以接收键盘显示/隐藏通知。但是,如果应用程序在分屏模式下作为辅助应用程序打开,而主应用程序已经显示键盘,则辅助应用程序不
我在模拟器中收到以下错误: ImageIO: CGImageReadSessionGetCachedImageBlockData *** CGImageReadSessionGetCachedIm
如 Apple 文档所示,可以通过 EAAccessory Framework 与经过认证的配件(由 Apple 认证)进行通信。但是我有点困惑,因为一些帖子告诉我它也可以通过 CoreBluetoo
尽管现在的调试器已经很不错了,但有时找出应用程序中正在发生的事情的最好方法仍然是古老的 NSLog。当您连接到计算机时,这样做很容易; Xcode 会帮助弹出日志查看器面板,然后就可以了。当您不在办公
在我的 iOS 应用程序中,我定义了一些兴趣点。其中一些有一个 Kontakt.io 信标的名称,它绑定(bind)到一个特定的 PoI(我的意思是通常贴在信标标签上的名称)。现在我想在附近发现信标,
我正在为警报提示创建一个 trigger.io 插件。尝试从警报提示返回数据。这是我的代码: // Prompt + (void)show_prompt:(ForgeTask*)task{
您好,我是 Apple iOS 的新手。我阅读并搜索了很多关于推送通知的文章,但我没有发现任何关于 APNS 从 io4 到 ios 6 的新更新的信息。任何人都可以向我提供 APNS 如何在 ios
UITabBar 的高度似乎在 iOS 7 和 8/9/10/11 之间发生了变化。我发布这个问题是为了让其他人轻松找到答案。 那么:在 iPhone 和 iPad 上的 iOS 8/9/10/11
我想我可以针对不同的 iOS 版本使用不同的 Storyboard。 由于 UI 的差异,我将创建下一个 Storyboard: Main_iPhone.storyboard Main_iPad.st
我正在写一些东西,我将使用设备的 iTunes 库中的一部分音轨来覆盖 2 个视频的组合,例如: AVMutableComposition* mixComposition = [[AVMutableC
我创建了一个简单的 iOS 程序,可以顺利编译并在 iPad 模拟器上运行良好。当我告诉 XCode 4 使用我连接的 iPad 设备时,无法编译相同的程序。问题似乎是当我尝试使用附加的 iPad 时
我是一名优秀的程序员,十分优秀!