Cast NSData as! CFDataRef in swift 2.0
Asked Answered
H

3

5

I have a line in a code which became deprecated, there are suggestions in XCode what to replace it with, but I can't get my head around the difference, these are my three lines which worked:

let path = NSBundle.mainBundle().pathForResource("example", ofType: ".p12")
let pkcs12Data = NSData.dataWithContentsOfMappedFile(path!)
let cf: CFDataRef = pkcs12Data as! CFDataRef

Now according to warning and suggestions I changed my code to:

let path = NSBundle.mainBundle().pathForResource("example", ofType: ".p12")
let pkcs12Data = NSData(contentsOfFile: path!)
let cf: CFDataRef = pkcs12Data as! CFDataRef

Which gives me an error:

EXC_BAD_INSTRUCTION (CODE=EXC_I386_INVOP SUBCODE=0x0)
Hatchel answered 1/10, 2015 at 8:50 Comment(5)
Don't cast, use CFDataCreate().Redmer
I was trying that, I must say I am learning swift and working with it for 8th day, and I was struggling to put together all the parameters the method needs. CFDataCreate(_ allocator: CFAllocator!, _ bytes: UnsafePointer<UInt8>, _ length: CFIndex) Its quite confusing...Hatchel
CFDataCreate(NULL, pkcs12Data.bytes, pkcs12Data.length)?Redmer
Well I can see why you would naturally expect that to work. However it throws another error: /Users/user/code/xyz/CryptoOperations/CryptographyOperations/IdentityFileReader.swift:30:42: Cannot convert value of type '()' to expected argument type 'CFAllocator!'Hatchel
And then there is a second one for the second parameter: /Users/user/code/xyz/CryptoOperations/CryptographyOperations/IdentityFileReader.swift:30:66: Cannot convert value of type 'UnsafePointer<Void>' (aka 'UnsafePointer<()>') to expected argument type 'UnsafePointer<UInt8>'Hatchel
H
10

A slightly safer version:

guard
    let url = NSBundle.mainBundle().URLForResource("example", withExtension: ".p12"),
    let data = NSData(contentsOfURL: url)
    else { // Do something because you couldn't get the file or convert it to NSData }

    let dataPtr = CFDataCreate(kCFAllocatorDefault, UnsafePointer<UInt8>(data.bytes), data.length)

Note, using file based URLs instead of string paths.

When deciding which routines to call, choose ones that let you specify paths using NSURL objects over those that specify paths using strings. Most of the URL-based routines were introduced in OS X v10.6 and later and were designed from the beginning to take advantage of technologies like Grand Central Dispatch. This gives your code an immediate advantage on multicore computers while not requiring you to do much work.

From File System Programming Guide

Homolographic answered 1/10, 2015 at 9:38 Comment(0)
T
6

In Swift 4, however, you should do it this way:

Xcode 9.2 seems to treat the NSData as Data automatically when the two optionals are put in the same guard-let clause. I have to put the two optionals in separate guard-let clause, as bellow:

//        guard let url = Bundle.main.url(forResource: "example", withExtension: ".p12"),
//            let data = NSData(contentsOf: url) else {
//            return
//        }

guard let url = Bundle.main.url(forResource: "example", withExtension: ".p12") else {
    return
}
guard let data = NSData(contentsOf: url) else {
    return
}
let bytes = data.bytes.assumingMemoryBound(to: UInt8.self)
let cfData = CFDataCreate(kCFAllocatorDefault, bytes, data.length) // CFData object you want
Temporize answered 3/2, 2018 at 4:47 Comment(0)
D
4

@Abizern’s answer works, but using CFDataCreateWithBytesNoCopy instead of CFDataCreate is more effective.

Dich answered 19/11, 2015 at 3:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.