我正在尝试在Swift中复制一些Objective C cocoa。一切都很好,直到我遇到以下内容:
// Set a new type and creator:
unsigned long type = 'TEXT';
unsigned long creator = 'pdos';
我如何从像这样的单引号字符字面量创建int64(或正确的Swift等效)?
类型:
public typealias AEKeyword = FourCharCode
public typealias OSType = FourCharCode
public typealias FourCharCode = UInt32
我在我的Cocoa脚本应用程序中使用这个,它认为字符> 0x80正确
func OSTypeFrom(string : String) -> UInt {
var result : UInt = 0
if let data = string.dataUsingEncoding(NSMacOSRomanStringEncoding) {
let bytes = UnsafePointer<UInt8>(data.bytes)
for i in 0..<data.length {
result = result << 8 + UInt(bytes[i])
}
}
return result
}
编辑:或者
func fourCharCodeFrom(string : String) -> FourCharCode
{
assert(string.count == 4, "String length must be 4")
var result : FourCharCode = 0
for char in string.utf16 {
result = (result << 8) + FourCharCode(char)
}
return result
}
或swiftier
func fourCharCode(from string : String) -> FourCharCode
{
return string.utf16.reduce(0, {$0 << 8 + FourCharCode($1)})
}
我从Swift API中找到了以下类型:
typealias FourCharCode = UInt32
typealias OSType = FourCharCode
和以下函数:
func NSFileTypeForHFSTypeCode(hfsFileTypeCode: OSType) -> String!
func NSHFSTypeCodeFromFileType(fileTypeString: String!) -> OSType
这应该允许我创建等效的代码:
let type : UInt32 = UInt32(NSHFSTypeCodeFromFileType("TEXT"))
let creator : UInt32 = UInt32(NSHFSTypeCodeFromFileType("pdos"))
但是这些4个字符的字符串不起作用并且返回0
。
如果你在'
单引号'
中包装每个字符串并调用相同的函数,你将得到正确的返回值:
let type : UInt32 = UInt32(NSHFSTypeCodeFromFileType("'TEXT'"))
let creator : UInt32 = UInt32(NSHFSTypeCodeFromFileType("'pdos'"))
采用ExpressibleByStringLiteral
协议直接使用四字串字量:
extension FourCharCode: ExpressibleByStringLiteral {
public init(stringLiteral value: StringLiteralType) {
if let data = value.data(using: .macOSRoman), data.count == 4 {
self = data.reduce(0, {$0 << 8 + Self($1)})
} else {
self = 0
}
}
}
现在你可以传递一个字符串字面值作为FourCharCode
/OSType
/UInt32
参数:
let record = NSAppleEventDescriptor.record()
record.setDescriptor(NSAppleEventDescriptor(boolean: true), forKeyword: "test")
在Swift 4或更高版本中,我使用以下代码-如果字符串的大小不是4个字符,它将返回一个osttype (0):
extension String {
public func osType() -> OSType {
var result:UInt = 0
if let data = self.data(using: .macOSRoman), data.count == 4
{
data.withUnsafeBytes { (ptr:UnsafePointer<UInt8>) in
for i in 0..<data.count {
result = result << 8 + UInt(ptr[i])
}
}
}
return OSType(result)
}
}
let type = "APPL".osType() // 1095782476
// check if this is OK in a playground
let hexStr = String(format: "0x%lx", type) // 0x4150504c -> "APPL" in ASCII
Swift 5更新:
extension String {
func osType() -> OSType {
return OSType(
data(using: .macOSRoman)?
.withUnsafeBytes {
$0.reduce(into: UInt(0)) { $0 = $0 << 8 + UInt($1) }
} ?? 0
)
}
}
下面是一个简单的函数
func mbcc(foo: String) -> Int
{
let chars = foo.utf8
var result: Int = 0
for aChar in chars
{
result = result << 8 + Int(aChar)
}
return result
}
let a = mbcc("TEXT")
print(String(format: "0x%lx", a)) // Prints 0x54455854
对于适合Int类型的字符串有效。一旦它们变长,它就开始从顶部失去数字。
如果使用
result = result * 256 + Int(aChar)
你应该得到崩溃当字符串变得太大,而不是
使用NSHFSTypeCodeFromFileType
确实工作,但仅适用于用单引号包装的4字符字符串,即6字符字符串。对于未加引号的4字符字符串,它返回0
。
所以在传递给函数之前,在'
'
中包装你的4个字符的字符串:
extension FourCharCode: ExpressibleByStringLiteral {
public init(stringLiteral value: StringLiteralType) {
switch (value.count, value.first, value.last) {
case (6, "'", "'"):
self = NSHFSTypeCodeFromFileType(value)
case (4, _, _):
self = NSHFSTypeCodeFromFileType("'(value)'")
default:
self = 0
}
}
}
使用上述扩展名,您可以使用4个字符或单引号6个字符的字符串字面量:
let record = NSAppleEventDescriptor.record()
record.setDescriptor(NSAppleEventDescriptor(boolean: true), forKeyword: "4444")
record.setDescriptor(NSAppleEventDescriptor(boolean: true), forKeyword: "'6666'")
在编译时将字符串字面值限制为4个字符的字符串会更好。这似乎目前还不可能,但正在讨论Swift:
允许对需要文字值的参数进行编译时检查间隔