Преобразование CFString в NSString — Swift

Я пытаюсь написать программу, которая будет сканировать доступные последовательные порты и представлять их во всплывающем меню. Почему я не могу взять CFString прямо из функции IORegistryEntryCreateCFProperty() и добавить ее в меню через интерполяцию строк в следующей строке? По какой-то причине мое объявление переменной встречается с ошибкой:

«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
        }

    }
}

person user3185748    schedule 17.08.2014    source источник


Ответы (3)


По крайней мере, начиная с Swift 2.0 (проверьте с терминала с помощью swift --version), вы можете преобразовать CFString в собственный Swift String с помощью простого as 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; в строковом контексте это сообщает имя типа, но обратите внимание, что вы можете получить обратно имя частного внутреннего класса:

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

Тем не менее, вы можете трактовать это как CFString, как показывает вышеприведенный тест is.

Используйте _stdlib_getDemangledTypeName(), чтобы получить истинное имя базового класса:

_stdlib_getDemangledTypeName(cfStr) // -> "ObjectC.CFString"
_stdlib_getDemangledTypeName(kUTTypeUTF8PlainText) // ditto
person mklement0    schedule 23.10.2015

Swift.String и NSString соединяются бесплатно.

NSString и CFString могут быть приведены друг к другу, но вы не можете напрямую преобразовать строку Swift в 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
person Woodstock    schedule 17.08.2014
comment
Так что станет это? imgur.com/ecm3JHM Потому что у меня возвращается та же ошибка. - person user3185748; 17.08.2014
comment
IORegistryEntryCreateCFProperty возвращает CFTypeRef, поэтому вам нужно объявить тип var CFTypeRef, а не CFString. - person Woodstock; 17.08.2014
comment
@ user3185748 CFTypeRef похож на Any для Core Foundation - person Woodstock; 17.08.2014
comment
Во-первых, спасибо за ваше терпение, пока я пытаюсь обдумать это. Однако предлагаемый CFTypeRef не решает проблему: imgur.com/DxKrGiX - person user3185748; 17.08.2014
comment
@user3185748 user3185748 нет проблем, хорошо, теперь давайте посмотрим, с чем вы вызываете IORegistryEntryCreateCFProperty. Какой тип имеет kIOCalloutDeviceKey? Я думаю, что это должна быть CFString, приведите ее так: CFSTR(kIOCalloutDeviceKey) - person Woodstock; 17.08.2014
comment
Это кажется немного ближе, теперь это просто дает мне: Использование неразрешенного идентификатора «CFSTR». - person user3185748; 18.08.2014
comment
Давайте продолжим обсуждение в чате. - person Woodstock; 18.08.2014
comment
Возможно, недавние изменения в Swift изменили поведение: кажется, что, по крайней мере, в Swift версии 2.0 теперь вы можете конвертировать напрямую из CFString: var swiftString:String = cfStr as String. Вашему примеру var swiftString:String = nsTypeString теперь нужен суффикс as String для компиляции. - person mklement0; 23.10.2015

Что касается меня, я люблю делать расширения и использовать их потом. Вроде удобно и понятно читать:

Расширение:

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
        ]
person NeonGloss    schedule 17.09.2020