如何在 Swift 中获取 C 指针的原始值?
How to Get a C Pointer's rawvalue in Swift?
我正在做一个使用 CoreText 的项目;我需要初始化一个 CTRunDelegateCallbacks
:
var imageCallback = CTRunDelegateCallbacks(version: kCTRunDelegateCurrentVersion, dealloc: { (refCon) -> Void in
print("RunDelegate dealloc")
}, getAscent: { ( refCon) -> CGFloat in
return 0
}, getDescent: { (refCon) -> CGFloat in
return 0
}) { (refCon) -> CGFloat in
return 0
}
参数refCon
是UnsafeMutablePointer<Void>
类型,在C中也叫void *
类型,我想得到指针的原始值。怎么做?
我不建议将指针转换为非指针类型。我会在这个答案的最后告诉你如何去做,但首先我会告诉你你应该如何真正处理 refCon
.
创建一个结构来保存您需要传递给回调的任何信息。示例:
struct MyRunExtent {
let ascent: CGFloat
let descent: CGFloat
let width: CGFloat
}
然后使用其 alloc
class 方法创建一个 UnsafeMutablePointer
,并初始化分配的存储空间:
let extentBuffer = UnsafeMutablePointer<MyRunExtent>.alloc(1)
extentBuffer.initialize(MyRunExtent(ascent: 12, descent: 4, width: 10))
在您的回调中,将指针参数转换为 UnsafePointer<MyRunExtent>
并从其 memory
中提取您需要的内容:
var callbacks = CTRunDelegateCallbacks(version: kCTRunDelegateVersion1, dealloc: { pointer in
pointer.dealloc(1)
}, getAscent: { pointer in
return UnsafePointer<MyRunExtent>(pointer).memory.ascent
}, getDescent: { pointer in
return UnsafePointer<MyRunExtent>(pointer).memory.descent
}, getWidth: { pointer in
return UnsafePointer<MyRunExtent>(pointer).memory.width
})
现在您可以使用 callbacks
和 extentBuffer
创建委托:
let delegate = CTRunDelegateCreate(&callbacks, extentBuffer)!
这是一个测试:
let richText = NSMutableAttributedString(string: "hello \u{FFFC} world")
richText.addAttribute(kCTRunDelegateAttributeName as String, value: delegate, range: NSMakeRange(6, 1))
let line = CTLineCreateWithAttributedString(richText)
let runs = (CTLineGetGlyphRuns(line) as [AnyObject]).map { [=14=] as! CTRun }
runs.forEach {
var ascent = CGFloat(0), descent = CGFloat(0), leading = CGFloat(0)
let width = CTRunGetTypographicBounds([=14=], CFRangeMake(0, 0), &ascent, &descent, &leading)
print("width:\(width) ascent:\(ascent) descent:\(descent) leading:\(leading)")
}
输出(在操场上):
2015-12-21 12:26:00.505 iOS Playground[17525:8055669] -[__NSCFType encodeWithCoder:]: unrecognized selector sent to instance 0x7f94bcb01dc0
width:28.6875 ascent:9.240234375 descent:2.759765625 leading:0.0
width:10.0 ascent:12.0 descent:4.0 leading:0.0
width:32.009765625 ascent:9.240234375 descent:2.759765625 leading:0.0
第一行输出是因为 playground 执行过程无法对委托进行编码以发送回 Xcode 进行显示,结果证明是无害的。无论如何,您可以看到中间 运行 的边界是使用我的回调和 extentBuffer
.
的内容计算的
现在,您一直在等待的那一刻……
您可以通过这种方式获取指针的“原始值”,如果指针和Int
在运行ning系统上的大小相同:
let rawValue = unsafeBitCast(refCon, Int.self)
如果它们的大小不同,您将在 运行 时收到致命错误。
你可以用这种方式将它转换为 CGFloat
,如果 指针和 CGFloat
的大小相同:
let float = unsafeBitCast(refCon, CGFloat.self)
我正在做一个使用 CoreText 的项目;我需要初始化一个 CTRunDelegateCallbacks
:
var imageCallback = CTRunDelegateCallbacks(version: kCTRunDelegateCurrentVersion, dealloc: { (refCon) -> Void in
print("RunDelegate dealloc")
}, getAscent: { ( refCon) -> CGFloat in
return 0
}, getDescent: { (refCon) -> CGFloat in
return 0
}) { (refCon) -> CGFloat in
return 0
}
参数refCon
是UnsafeMutablePointer<Void>
类型,在C中也叫void *
类型,我想得到指针的原始值。怎么做?
我不建议将指针转换为非指针类型。我会在这个答案的最后告诉你如何去做,但首先我会告诉你你应该如何真正处理 refCon
.
创建一个结构来保存您需要传递给回调的任何信息。示例:
struct MyRunExtent {
let ascent: CGFloat
let descent: CGFloat
let width: CGFloat
}
然后使用其 alloc
class 方法创建一个 UnsafeMutablePointer
,并初始化分配的存储空间:
let extentBuffer = UnsafeMutablePointer<MyRunExtent>.alloc(1)
extentBuffer.initialize(MyRunExtent(ascent: 12, descent: 4, width: 10))
在您的回调中,将指针参数转换为 UnsafePointer<MyRunExtent>
并从其 memory
中提取您需要的内容:
var callbacks = CTRunDelegateCallbacks(version: kCTRunDelegateVersion1, dealloc: { pointer in
pointer.dealloc(1)
}, getAscent: { pointer in
return UnsafePointer<MyRunExtent>(pointer).memory.ascent
}, getDescent: { pointer in
return UnsafePointer<MyRunExtent>(pointer).memory.descent
}, getWidth: { pointer in
return UnsafePointer<MyRunExtent>(pointer).memory.width
})
现在您可以使用 callbacks
和 extentBuffer
创建委托:
let delegate = CTRunDelegateCreate(&callbacks, extentBuffer)!
这是一个测试:
let richText = NSMutableAttributedString(string: "hello \u{FFFC} world")
richText.addAttribute(kCTRunDelegateAttributeName as String, value: delegate, range: NSMakeRange(6, 1))
let line = CTLineCreateWithAttributedString(richText)
let runs = (CTLineGetGlyphRuns(line) as [AnyObject]).map { [=14=] as! CTRun }
runs.forEach {
var ascent = CGFloat(0), descent = CGFloat(0), leading = CGFloat(0)
let width = CTRunGetTypographicBounds([=14=], CFRangeMake(0, 0), &ascent, &descent, &leading)
print("width:\(width) ascent:\(ascent) descent:\(descent) leading:\(leading)")
}
输出(在操场上):
2015-12-21 12:26:00.505 iOS Playground[17525:8055669] -[__NSCFType encodeWithCoder:]: unrecognized selector sent to instance 0x7f94bcb01dc0
width:28.6875 ascent:9.240234375 descent:2.759765625 leading:0.0
width:10.0 ascent:12.0 descent:4.0 leading:0.0
width:32.009765625 ascent:9.240234375 descent:2.759765625 leading:0.0
第一行输出是因为 playground 执行过程无法对委托进行编码以发送回 Xcode 进行显示,结果证明是无害的。无论如何,您可以看到中间 运行 的边界是使用我的回调和 extentBuffer
.
现在,您一直在等待的那一刻……
您可以通过这种方式获取指针的“原始值”,如果指针和Int
在运行ning系统上的大小相同:
let rawValue = unsafeBitCast(refCon, Int.self)
如果它们的大小不同,您将在 运行 时收到致命错误。
你可以用这种方式将它转换为 CGFloat
,如果 指针和 CGFloat
的大小相同:
let float = unsafeBitCast(refCon, CGFloat.self)