【问题标题】:Convert CFString to NSString - Swift将 CFString 转换为 NSString - Swift
【发布时间】:2014-08-17 17:38:05
【问题描述】:

我正在尝试编写一个程序来扫描可用的串行端口并将它们显示在弹出菜单中。为什么我不能直接从IORegistryEntryCreateCFProperty() 函数中获取CFString 并通过下一行的字符串插值将其添加到菜单中?由于某种原因,我的变量声明遇到了错误:

“NSString 不是 CFString 的子类型”。

import Foundation

import Cocoa

import IOKit
import IOKit.serial


@objc class Serial {

    init() {
    }

    @IBOutlet var serialListPullDown : NSPopUpButton!

    func refreshSerialList(defaultprompt: String) {


        let masterPort: mach_port_t = kIOMasterPortDefault
        let classesToMatch: CFDictionary =     IOServiceMatching(kIOSerialBSDServiceValue).takeUnretainedValue()
        var matchingServices: io_iterator_t = 0

        // remove everything from the pull down list
        serialListPullDown?.removeAllItems()

        // ask for all the serial ports
        let kernResult = IOServiceGetMatchingServices(masterPort, classesToMatch, &matchingServices)
        if kernResult == KERN_SUCCESS {
            // success
            while (io_object_t() == IOIteratorNext(matchingServices)) {
                var serialport = IORegistryEntryCreateCFProperty(io_object_t(), kIOCalloutDeviceKey, kCFAllocatorDefault, 0)

                serialListPullDown?.addItemWithTitle("\(serialport)")
            }
        }
        else {
            // error
        }

    }
}

【问题讨论】:

    标签: string swift serial-port iokit


    【解决方案1】:

    Swift.String 和 NSString 是免费桥接的。

    NSString 和 CFString 可以相互转换,但不能直接从 Swift String 转换为 CFString,反之亦然。

    按照以下步骤从 Core Foundation 字符串转换为 Swift 字符串:

    var cfStr:CFString = "Soon, I'll be a Swift String"
    var nsTypeString = cfStr as NSString
    var swiftString:String = nsTypeString
    

    CFTypeRef 示例:

    var cfStr:CFTypeRef = "Soon, I'll be a Swift String"
    var nsTypeString = cfStr as NSString
    var swiftString:String = nsTypeString
    

    【讨论】:

    • 所以会变成这样? imgur.com/ecm3JHM 因为它给我返回了同样的错误。
    • IORegistryEntryCreateCFProperty 返回一个 CFTypeRef,所以你需要声明你的 var 类型 CFTypeRef 而不是 CFString
    • @user3185748 CFTypeRef 就像 Any for Core Foundation
    • 首先,感谢您在我试图解决这个问题时的耐心等待。然而,建议的 CFTypeRef 似乎无法解决问题:imgur.com/DxKrGiX
    • @user3185748 没问题,接下来让我们看看你用什么调用 IORegistryEntryCreateCFProperty。 kIOCalloutDeviceKey 是什么类型的?我认为它需要是一个 CFString,这样转换:CFSTR(kIOCalloutDeviceKey)
    【解决方案2】:

    至少从 Swift 2.0 开始(从带有 swift --version 的终端验证),您可以使用简单的 as StringCFString 转换为原生 Swift String

    这就足够了,因为 Swift 的 String 类型可以在任何需要 NSString 的地方使用。

    一个带有kUTType* 常量的示例kUTType* 常量由 CoreServices 定义并且是CFStrings):

    // Get UTF8 plain text from the pasteboard.
    import AppKit
    let str = NSPasteboard.generalPasteboard().stringForType(kUTTypeUTF8PlainText as String)
    

    更详细的示例

    // Import at least the Foundation framework.
    // Since Cocoa includes Foundation, `import Cocoa` works too.
    // (Note that `import CoreServices`, even though it defines type `CFString`,
    // is NOT enough - the conversion will fail.)
    import Foundation
    
    // Create a CFString.
    // The fact that initializing from a `String` literal here works implies that
    // the *reverse* cast - String -> CFString - also works.
    var cfStr:CFString = "Cast me."
    
    // Convert it to String.
    var swiftStr = cfStr as String
    

    测试您正在处理的类型

    cfStr is CFString // true
    swiftStr is String // true
    

    获取字符串的类型,请使用.dynamicType;在字符串上下文中,这会报告 type name 但请注意,您可能会得到 private internal 类的名称:

    "cfStr is a \(cfStr.dynamicType) instance."
    // -> "cfStr is a _NSContiguousString instance." !!
    

    不过,您可以将其视为CFString,如上面的is 测试所示。

    使用_stdlib_getDemangledTypeName() 获取真正的底层类名

    _stdlib_getDemangledTypeName(cfStr) // -> "ObjectC.CFString"
    _stdlib_getDemangledTypeName(kUTTypeUTF8PlainText) // ditto
    

    【讨论】:

      【解决方案3】:

      就我而言,我喜欢扩展并在之后使用它们。 读起来似乎方便又清晰:

      扩展:

      extension CFString {
          var string: String {
              return self as String
          }
      }
      

      用法:

      let specificQueryPart: [String: NSObject] = [
                  kSecReturnData.string: true as NSObject,
                  kSecAttrService.string: key as NSObject,
                  kSecMatchLimit.string: kSecMatchLimitOne
              ]
      

      【讨论】:

        猜你喜欢
        • 2015-10-28
        • 2014-07-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多