2017-09-24 13 views
2

Swift에서 시스템 구성 프레임 워크를 사용하여 macOS에서 네트워크 인터페이스 구성을 읽으려고합니다. 나는 실제로 CFDictionaryCFPropertyList을 얻고 있습니다. 각 사전 항목은 CFArray을 포함합니다. CFShow으로 예상 데이터를 받았는지 확인할 수있었습니다. 실제로 할 수없는 것은 사전 값에 액세스하는 것입니다. CFGetTypeId을 사용하면 CFArrayGetTypeID()과 같은 값을 반환하지 않습니다.CFPropertyList에서 값 읽기

import SystemConfiguration 

func readIP() { 

    let cfName = "Demo" as CFString 
    let dynamicStore = SCDynamicStoreCreate(nil, cfName, nil, nil) 

    let key = "State:/Network/Interface/en0/IPv4" as CFString 

    guard let plist: CFPropertyList = SCDynamicStoreCopyValue(dynamicStore, key) else {return} 

    print("CFShow(plist):") 
    CFShow(plist) 

    print("Key: \(key):") 
    print("Value: \(plist)") 

    let typeIdPList = CFGetTypeID(plist) 
    let typeIdDictionary = CFDictionaryGetTypeID() 

    print("typeIdPList: \(typeIdPList)") 
    print("typeIdDictionary: \(typeIdDictionary)") 

    guard typeIdPList == typeIdDictionary else {return} 

    let cfDict: CFDictionary = plist as! CFDictionary 

    let rawPointerToKeyAddresses = Unmanaged.passUnretained(kSCPropNetIPv4Addresses).toOpaque() 
    var rawPointerToValue: UnsafeRawPointer? 
    guard CFDictionaryGetValueIfPresent(cfDict, rawPointerToKeyAddresses, &rawPointerToValue) == true else {return} 

    let anyRef: CFTypeRef = rawPointerToValue as CFTypeRef 

    print("Value:") 
    CFShow(anyRef) 

    let typeIdValue = CFGetTypeID(anyRef) 
    let typeIdArray = CFArrayGetTypeID() 

    print("typeIdValue: \(typeIdValue)") 
    print("typeIdArray: \(typeIdArray)") 

    let cfArray: CFArray = anyRef as! CFArray 
    let typeId = CFGetTypeID(cfArray) 
    print("typeId: \(typeId)") 

    let desc = CFCopyDescription(anyRef) 
    let typeDesc = CFCopyTypeIDDescription(CFGetTypeID(anyRef)) 

    print("CFTypeRef description: \(desc!)") 
    print("CFTypeRef type description: \(typeDesc!)") 
} 

출력은 다음과 같다 : 여기

내가 속성 목록에서 IP 주소를 얻기 위해 노력 무엇

CFShow(plist): 
<CFBasicHash 0x610000069500 [0x7fffc4383da0]>{type = immutable dict, count = 3, entries => 
    0 : Addresses = <CFArray 0x610000069440 [0x7fffc4383da0]>{type = immutable, count = 1, values = (
    0 : <CFString 0x610000028980 [0x7fffc4383da0]>{contents = "192.168.139.24"} 
)} 
    1 : <CFString 0x610000044c20 [0x7fffc4383da0]>{contents = "BroadcastAddresses"} = <CFArray 0x610000069480 [0x7fffc4383da0]>{type = immutable, count = 1, values = (
    0 : <CFString 0x610000044c50 [0x7fffc4383da0]>{contents = "192.168.139.255"} 
)} 
    2 : <CFString 0x7fffc429d300 [0x7fffc4383da0]>{contents = "SubnetMasks"} = <CFArray 0x6100000694c0 [0x7fffc4383da0]>{type = immutable, count = 1, values = (
    0 : <CFString 0x6100000289a0 [0x7fffc4383da0]>{contents = "255.255.255.0"} 
)} 
} 
Key: State:/Network/Interface/en0/IPv4: 
Value: { 
    Addresses =  (
     "192.168.139.24" 
    ); 
    BroadcastAddresses =  (
     "192.168.139.255" 
    ); 
    SubnetMasks =  (
     "255.255.255.0" 
    ); 
} 
typeIdPList: 18 
typeIdDictionary: 18 
Value: 
0x0000610000069440 
typeIdValue: 1 
typeIdArray: 19 
typeId: 1 
CFTypeRef description: 0x0000610000069440 
CFTypeRef type description: CFType 

답변

0

CFPropertyList 이미 첨자를 지원을, 그래서 필요에가 없습니다 CFDictionary 및 원시 포인터로 번거 로움을 덜기 위해 코드를 간단하게 할 수 있습니다.

let cfName = "Demo" as CFString 
let dynamicStore = SCDynamicStoreCreate(nil, cfName, nil, nil) 
let key = "State:/Network/Interface/en0/IPv4" as CFString 

guard let plist = SCDynamicStoreCopyValue(dynamicStore, key) else {return} 
print(plist) 

if let addresses = plist[kSCPropNetIPv4Addresses] as? [String] { 
    print(addresses) 
} 
당신이 당신의 CFDictionary/ CFArray 기반의 접근 방식 작동하게하는 방법을 정말 호기심이 경우

는하지만 : 문제는있는 CFTypeRef (일명 AnyObject)에있는

let anyRef: CFTypeRef = rawPointerToValue as CFTypeRef 

포인터 값입니다. 당신이 원하는 무엇 는 캐스트 포인터입니다 : 내가 이해하는 것은

let anyRef = Unmanaged<CFTypeRef>.fromOpaque(rawPointerToValue!).takeUnretainedValue() 
+0

let anyRef = unsafeBitCast(rawPointerToValue!, to: CFTypeRef.self) guard CFGetTypeID(anyRef) == CFArrayGetTypeID() else { return } let cfArray = anyRef as! CFArray // ... 

포인터 캐스팅을하는 또 다른 (상응하는) 방법입니다 CFDictionary'와'NSDictionary와'사이의 가교 '는 "수신자 부담"입니다. Swift 사전에 브리징하는 것은 어떤 경우에 문제가 될 수있는 오버 헤드가 있습니다. 뷰 요소와 업데이트 만 있기 때문에 설명 된 유스 케이스에서는 그렇지 않을 수도 있습니다. – Bokeh

+0

@Bokeh : CFPropertyList가 이미 하위 스크립트를 지원하는 것으로 보입니다. 따라서 'guard let plist = SCDynamicStoreCopyValue (dynamicStore, key) else {return}'도 대문자로 사용하지 않아도됩니다. - 스위프트 브리징의 비용이 적절하다고 생각하지 않습니다. Apple Swift 블로그의 예제 (https://developer.apple.com/swift/blog/?id=37)를 비교하십시오. –

+0

사실 저는 Core Foundation 콜렉션과 원시 포인터로 모든 번거로운 작업을 수행하는 방법을 알고 싶습니다. 나는 여러 번 그들과 우연히 마주 쳤다. 다른 경우에는 성능상의 이유로 CF 인터페이스를 직접 사용해야 할 수도 있습니다. – Bokeh