11
import Foundation
import MobileCoreServices

func checkFileExtension(fileName: NSString){
    println(fileName)

    var fileExtension:CFStringRef = fileName.pathExtension

    println(fileExtension)

    var fileUTI:CFStringRef = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, fileExtension, nil)

    println(fileUTI)

    let testBool = UTTypeConformsTo(fileUTI, kUTTypeImage) != 0

    if  testBool{
        println("image")
    }
}

I get this error

error : 'Unmanaged' is not convertible to 'CFStringRef'

at line

var fileUTI:CFStringRef = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, fileExtension, nil)

any ideas ?? Thanks

Matteo Pacini
  • 21,796
  • 7
  • 67
  • 74
pbeo
  • 399
  • 1
  • 4
  • 14

2 Answers2

24

UTTypeCreatePreferredIdentifierForTag passes back an Unmanaged<CFStringRef>, so you need to get the value out of the Unmanaged object before you can use it:

var unmanagedFileUTI = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, fileExtension, nil)
var fileUTI = unmanagedFileUTI.takeRetainedValue()

Note that I'm calling takeRetainedValue() since UTTypeCreatePreferredIdentifierForTag is returning an object that we are responsible for releasing. The comments on takeRetainedValue() say:

Get the value of this unmanaged reference as a managed reference and consume an unbalanced retain of it.

This is useful when a function returns an unmanaged reference and you know that you're responsible for releasing the result.

If you get an Unmanaged object back from a function where you are sure you aren't responsible for releasing that object, call takeUnretainedValue() instead.

Mike S
  • 41,895
  • 11
  • 89
  • 84
  • 9
    The choice of takeRetainedValue vs takeUnretainedValue depends only (as I understand the docs) on whether the Core Foundation function returns a (+1) retained object or not. UTTypeCreatePreferredIdentifierForTag() has "Create" in its name, so according to the memory management rules that returns a (+1) retained object which the caller has to release eventually. So you have to call takeRetainedValue here, otherwise the object would never be released and you have a leak. – Martin R Oct 29 '14 at 16:34
  • 2
    Compare "Create Rule" in https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFMemoryMgmt/Concepts/Ownership.html. – Martin R Oct 29 '14 at 16:38
  • thanks for the comprehensive answer! really helped me! – pbeo Oct 29 '14 at 16:39
  • 1
    @MartinR You're right, I mis-read the comments on `takeUnretainedValue()` and got it backwards. I'll fix that... – Mike S Oct 29 '14 at 16:41
  • Another very clear explanation is found here: https://stackoverflow.com/a/29049072/250164 – Wolfgang Schreurs Nov 01 '18 at 08:02
0

I just want to mention a little module I published that deals exactly with this kind of thing in a much nicer way. Your example would become:

import SwiftUTI

func checkFileExtension(fileURL: URL){

    let uti = UTI(withExtension: fileURL.pathExtension)

    if uti.conforms(to: .image) {

        print("image")
    }
}

It's available here: https://github.com/mkeiser/SwiftUTI

mkeiser
  • 965
  • 9
  • 17