New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[SR-2388] Forming a CFDictionary from a Swift Dictionary is now really difficult #44995
Comments
To work around the second problm, you can do |
I think |
Not yet, unfortunately, we still only allow explicit |
You can bridge `CFString` to `NSString` using `as NSString`. If you must make `CFString` `Hashable`, you can add this extension as a workaround: extension CFString: Hashable {
public static func ==(a: CFString, b: CFString) -> Bool {
return CFEqual(a, b)
}
} |
@jckarter That compiles (thank you!) but it doesn't actually work. Without the explicit The reason is that merely saying |
@mattneub What type is |
For example, this prints `true` for me: let w = 1024
let d1 : [CFString: Any] = [
kCGImageSourceShouldAllowFloat : true,
kCGImageSourceCreateThumbnailWithTransform : true,
kCGImageSourceCreateThumbnailFromImageAlways : true,
kCGImageSourceThumbnailMaxPixelSize : w
]
let d2 : [CFString: AnyObject] = [
kCGImageSourceShouldAllowFloat : true as NSNumber,
kCGImageSourceCreateThumbnailWithTransform : true as NSNumber,
kCGImageSourceCreateThumbnailFromImageAlways : true as NSNumber,
kCGImageSourceThumbnailMaxPixelSize : w as NSNumber
]
print((d1 as NSDictionary).isEqual(to: d2 as NSDictionary)) |
@jckarter It comes out as an NSDictionary but, as I said, it doesn't make it as a valid CFDictionary that ImageIO can understand. That is the bridge we are not crossing. Here's the full code (along with your CFString extension): let url = Bundle.main.url(forResource:"colson", withExtension: "jpg")!
let src = CGImageSourceCreateWithURL(url as CFURL, nil)!
let scale = UIScreen.main.scale
let w = self.iv.bounds.width * scale
// have to cross over to Objective-C manually
let d : [CFString:Any] = [
kCGImageSourceShouldAllowFloat : true as NSNumber,
kCGImageSourceCreateThumbnailWithTransform : true as NSNumber,
kCGImageSourceCreateThumbnailFromImageAlways : true as NSNumber,
kCGImageSourceThumbnailMaxPixelSize : w as NSNumber
]
let imref = CGImageSourceCreateThumbnailAtIndex(src, 0, d as CFDictionary)! I've attached my test project; launch, then tap the second button to view the image in the interface. I crash at that moment if all four |
It does, but CFBoolean is a distinct type from CFNumber at the CF layer, so it very well could be related. |
Ah, that could definitely be it then. |
@mattneub If you do |
Comment by Wil Shipley (JIRA) When I used this form (this is what the auto-updating stuff in Xcode ended up spitting out) it compiled but I do NOT get an actual image — the load fails. let thumbnailSideLength = 512
let optionsDictionary = [
kCGImageSourceCreateThumbnailFromImageIfAbsent as NSString: true,
kCGImageSourceThumbnailMaxPixelSize as NSString: thumbnailSideLength,
] as CFDictionary
guard let thumbnail = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, optionsDictionary) else {
print("\(#function) failed to load thumbnail for \(name)/\(maker)/\(productLine)")
throw PlatonicPieceOfFurnitureError.cannotCreateImageFromThumbnailImageSource
} When I change my dictionary to this it succeeds: let optionsDictionary = [
kCGImageSourceCreateThumbnailFromImageIfAbsent as NSString: true as NSNumber,
kCGImageSourceThumbnailMaxPixelSize as NSString: thumbnailSideLength as NSNumber,
] as CFDictionary |
Confirmed that with #4366 this succeeds without the |
CF types have been made Hashable in #4417 If there are any more improvements / fixes we can make around CF, let's put them in separate bug reports. |
@swift-ci create |
CF types have been remade Hashable in #4568 #finally |
And merged into Swift 4.0 in #9401 |
@belkadan @gparker42 @jckarter I am now reaping the rewards of this change. I can say let result = CGImageSourceCopyPropertiesAtIndex(src, 0, nil)! as! [AnyHashable:Any] and this works because CFString is AnyHashable. And I can say let d : [AnyHashable:Any] = [
kCGImageSourceShouldAllowFloat : true ,
kCGImageSourceCreateThumbnailWithTransform : true ,
kCGImageSourceCreateThumbnailFromImageAlways : true ,
kCGImageSourceThumbnailMaxPixelSize : w
]
let imref = CGImageSourceCreateThumbnailAtIndex(src, 0, d as CFDictionary)! That's convenient and intuitive. Thanks! |
Attachment: Download
Environment
Xcode Version 8.0 beta 6 (8S201h)
Additional Detail from JIRA
md5: 0803c238279e54d409d7b137b9e8c7d0
Issue Description:
Before seed 6, I used to be able to say this:
Now I have to take everything across the bridge by hand. All the CFString keys have to be cast as String or NSString. We don't get any automatic bridge-crossing, so we have to tell Swift explicitly what the value types are, and then we have to cast the resulting dictionary to CFDictionary as well. Even if we get past the compiler, it is still possible to do this wrong and thus end up with an invalid CFDictionary so that at runtime CGImageSourceCreateThumbnailAtIndex yields nil. The only way I've found to get things right is like this:
This is absolutely horrible.
The situation is compounded by the fact that no one seems to have told NSDictionary that its Swift equivalent is now [AnyHashable : Any]. We see that in the APIs and it works, but when you try to cast a CFDictionary to it, the compiler complains:
In my opinion, Swift now goes too far with its refusal to help things get across the bridges, the Swift to Objective-C bridge and the CFTypeRef toll-free bridge. (In fact, there now seems to be rather a heavy toll on that bridge.🙂 )
The text was updated successfully, but these errors were encountered: