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)
fabian789
  • 8,348
  • 4
  • 45
  • 91
Jakub Zak
  • 1,212
  • 6
  • 32
  • 53
  • Don't cast, use `CFDataCreate()`. – Larme Oct 01 '15 at 08:54
  • 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, _ length: CFIndex) Its quite confusing... – Jakub Zak Oct 01 '15 at 09:08
  • `CFDataCreate(NULL, pkcs12Data.bytes, pkcs12Data.length)`? – Larme Oct 01 '15 at 09:09
  • 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!'` – Jakub Zak Oct 01 '15 at 09:11
  • 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' (aka 'UnsafePointer<()>') to expected argument type 'UnsafePointer'` – Jakub Zak Oct 01 '15 at 09:13

3 Answers3

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

Abizern
  • 146,289
  • 39
  • 203
  • 257
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
wzso
  • 3,482
  • 5
  • 27
  • 48
4

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

Volodymyr Kulyk
  • 6,455
  • 3
  • 36
  • 63
Joywek
  • 67
  • 1
  • 5