Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cast NSData as! CFDataRef in swift 2.0

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)
like image 383
Jakub Zak Avatar asked Oct 01 '15 08:10

Jakub Zak


3 Answers

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

like image 70
Abizern Avatar answered Nov 15 '22 00:11

Abizern


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
like image 44
Benjamin Wen Avatar answered Nov 15 '22 00:11

Benjamin Wen


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

like image 4
Joywek Avatar answered Nov 14 '22 23:11

Joywek