Swift 相当于 Objective-C FourCharCode 单引号文字(例如"TEXT")



我正在尝试在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:

允许对需要文字值的参数进行编译时检查间隔

相关内容

最新更新