How to access CFDictionary in Swift 3?
If you don't have to deal with other Core Foundation functions expecting an CFDictionary
, you can simplify it by converting to Swift native Dictionary
:
if let dict = cfDict as? [String: AnyObject] {
print(dict["key"])
}
CFDictionary get Value for Key in Swift3
Don't use CFDictionary
in Swift. (It is possible, but not worth the effort, see below.)
CFDictionary
is toll-free
bridged withNSDictionary
, which in turn can be cast to a SwiftDictionary
.- The value of the
kDADiskDescriptionVolumeNetworkKey
key is aCFBoolean
which can be cast to a SwiftBool
.
Example:
if let session = DASessionCreate(kCFAllocatorDefault),
let mountedVolumes = FileManager.default.mountedVolumeURLs(includingResourceValuesForKeys: []) {
for volume in mountedVolumes {
if let disk = DADiskCreateFromVolumePath(kCFAllocatorDefault, session, volume as CFURL),
let diskinfo = DADiskCopyDescription(disk) as? [NSString: Any] {
if let networkValue = diskinfo[kDADiskDescriptionVolumeNetworkKey] as? Bool {
print(networkValue)
}
}
}
}
Just for the sake of completeness: This is the necessary pointer
juggling to call CFDictionaryGetValue
in Swift 3:
if let session = DASessionCreate(kCFAllocatorDefault),
let mountedVolumes = FileManager.default.mountedVolumeURLs(includingResourceValuesForKeys: []) {
for volume in mountedVolumes {
if let disk = DADiskCreateFromVolumePath(kCFAllocatorDefault, session, volume as CFURL),
let diskinfo = DADiskCopyDescription(disk) {
if let ptr = CFDictionaryGetValue(diskinfo, Unmanaged.passUnretained(kDADiskDescriptionVolumeNetworkKey).toOpaque()) {
let networkValue = Unmanaged<NSNumber>.fromOpaque(ptr).takeUnretainedValue()
print(networkValue.boolValue)
}
}
}
}
Cast Swift Dictionary to CFDictionary
Yes you can do that. your solution will work and you can also do it like this.
var dictionary = [
key:value
] as CFDictionary
You can refer further from here
Cannot access CFDictionary elements from Swift3
To fix your specific problem, replace metadata as? [String:Any]["{Exif}"]
with (metadata as! [String:Any])["{Exif}"]
The problem you are encountering is that metadata as? [String:Any]
is of type [String: Any]?
, since you are using the conditional cast as!
.
However, the idiomatic way to do this in Swift is to use guard-let
statements like so:
guard let metadata:CFDictionary = CGImageSourceCopyPropertiesAtIndex(source!,0,nil) else {
fatalError("Cannot get image properties!")
}
guard let dictionary = metadata as? [String: Any] else {
fatalError("Cannot convert metadata to dictionary!")
}
guard let exifData = dictionary["{Exif}"] as? [SomeCFType: Int] else { //I'm not sure what type PixelXDimension, PixelYDimension, and ColorSpace are
fatalError("Cannot get EXIF data!")
}
Swift 3 - Working with UnsafePointerCFDictionary?
Swift's CFDictionary
isn't itself a data structure; it's a pointer to a data structure, and it is equivalent to Objective-C's CFDictionaryRef
. In other words, it behaves like a Swift class
, not a struct
.
The value written into outDataPointer
is not a pointer to a CFDictionary
; it is a CFDictionary
. You're dereferencing it one too many times, causing the data stored in the dictionary to be treated as a pointer to a dictionary. On my system, the resulting memory address was 0x001dffffc892e2f1
, which Objective-C treats as a tagged pointer, resulting in the NSAtom
message.
To fix the problem, declare outDataPointer
as a CFDictionary?
instead of an UnsafePointer<CFDictionary>?
:
// Get metadata
var outDataPointer: CFDictionary? = nil
possibleError = AudioFileGetProperty(audiofile!, kAudioFilePropertyInfoDictionary, &outDataSize, &outDataPointer)
assert(possibleError == noErr)
let outData = outDataPointer! as NSDictionary
dump(outData)
Output:
▿ 1 key/value pair #0
▿ (2 elements)
- .0: approximate duration in seconds #1
- super: __NSCFString
- super: NSMutableString
- super: NSString
- super: NSObject
- .1: 187.387 #2
- super: NSString
- super: NSObject
reading value in CFDictionary with swift
I've found it much easier to access the properties by 'converting' the CFDictionary to a Swift dictionary.
let imageSource = CGImageSourceCreateWithURL(imageURL, nil)
let imageProperties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nil) as Dictionary
let dpiWidth = imageProperties[kCGImagePropertyDPIWidth] as NSNumber
Quick update for Swift 2.0 (excuse all the if let
s - I just quickly crafted this code):
import UIKit
import ImageIO
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
if let imagePath = NSBundle.mainBundle().pathForResource("test", ofType: "jpg") {
let imageURL = NSURL(fileURLWithPath: imagePath)
if let imageSource = CGImageSourceCreateWithURL(imageURL, nil) {
if let imageProperties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nil) as Dictionary? {
let pixelWidth = imageProperties[kCGImagePropertyPixelWidth] as! Int
print("the image width is: \(pixelWidth)")
}
}
}
}
}
Creating a CFDictionary
Here is your working code:
func processImage(jpgImagePath: String, thumbSize: CGSize) {
if let path = NSBundle.mainBundle().pathForResource(jpgImagePath, ofType: "") {
if let imageURL = NSURL(fileURLWithPath: path) {
if let imageSource = CGImageSourceCreateWithURL(imageURL, nil) {
let maxSize = max(thumbSize.width, thumbSize.height) / 2.0
let options : [NSString : AnyObject] = [
kCGImageSourceThumbnailMaxPixelSize: maxSize,
kCGImageSourceCreateThumbnailFromImageIfAbsent: true
]
let scaledImage = UIImage(CGImage: CGImageSourceCreateThumbnailAtIndex(imageSource, 0, options))
// do other stuff
}
}
}
}
From Docs:
The implicit conversions from bridged Objective-C classes
(NSString/NSArray/NSDictionary) to their corresponding Swift value
types (String/Array/Dictionary) have been removed, making the Swift
type system simpler and more predictable.
The problem in your case are the CFStrings
like kCGImageSourceThumbnailMaxPixelSize
. These are not automatically converted to String anymore.
reference from HERE.
Swift 3 - Trying to cast a dictionary to CFDictionary
You can use below code to convert the dictionary to CFDictionary
as mention below:
let attrs = [kCVPixelBufferCGImageCompatibilityKey as String :kCFBooleanTrue,
kCVPixelBufferCGBitmapContextCompatibilityKey as String:kCFBooleanTrue] as
CFDictionary
Hope This will helps
Related Topics
iOS 13, Custom Image, Title and Subtitle in the Presented Uiactivityviewcontroller
Swift Alternative to Respondstoselector:
Typealias of Generic Class in Swift
How to Cast a Metaclass Object to a Protocol Type in Swift
Symbol Is Considered to Be an Identifier, Not an Operator
Swift/Scenekit Problems Getting Touch Events from Scnscene and Overlayskscene
iOS 12 Errors: Appears to Be from a Different Nsmanagedobjectmodel Than This Context'S
How to Use Enumeratedate in Swift 3 to Find All Sundays the Last 50 Years
Swift:How to Handle a Lot of Textures in Memory
How to Check Whether an Object Is Kind of a Dynamic Class Type in Swift
How to Make Player Move to Opposite Side While Is in a Path
Use Different Googleservice-Info.Plist for Single Project in Xcode Using Swift4
Swiftui: Navigationlink Not Working If Not in a List
Different Colors for Bars in Barchart Depend on Value
Nsurlsessiondatadelegate Method Didreceivedata and Others Are Not Called
Swift Codable - Parse JSON Array Which Can Contain Different Data Type