[swift-users] getResourceValue

Rod Brown rodney.brown6 at icloud.com
Fri Jan 6 08:19:53 CST 2017


> On 7 Jan 2017, at 12:50 am, Rien <Rien at balancingrock.nl> wrote:
> 
> Hmm, that is interesting to know. I had not realised that URL is in fact NOT a NSURL but a new type that is based on NSURL (and can be toll-free bridged I assume?).

URL a new Type, which internally wraps a NSURL reference. It is practically toll free bridged, as URL is simply a struct wrapper placed around the internal reference.

NSURL is a class and has reference semantics. That is, if you change the URL, it would change all URLs with the same reference. This is why NSURL doesn’t allow mutation. If you look at the NSURL API, it has a lot of methods like “URLByAppendingPathComponent” which import into Swift 3 as “appendingPathComponent()”. These return *copies* of the NSURL reference, with the applied mutation.

URL is a struct and has value semantics. That is, if you change the URL, it only changes the struct at this place and has no wider effects. Thus, there are new mutating methods on this struct, love “appendPathExtension()” and “appendPathComponent()” that allow mutation, because it only affects this local copy. These methods internally actually use the appendingPathComponent() method to get a replacement NSURL instance internal of the struct.

The URL struct mutating behaviour makes URL manipulation much more convenient in Swift 3.

> I also presume that the same is true for Data/NSData, Date/NSDate etc?

Correct. Except Date/NSDate is actually a slight edge case.

Instead of Date simply wrapping an NSDate, it actually only wraps the NSDate’s timeIntervalSinceReferenceDate. This is because there’s no point wrapping the internal reference to the NSDate, it’s more performant simply to wrap the NSTimeInterval (a Double) and get true struct properties. You should note that this means when you cast from Date to NSDate, you need to create a new reference each time.

This becomes a bigger issue for IndexPath/NSIndexPath which also does this. Casting between NSIndexPath and IndexPath can be somewhat less performant, as it can hold an arbitrarily large number of integers. It’s also interesting to note that NSIndexPath has an optimisations that could make it perform better than IndexPath: NSIndexPath uses tagged pointers for row/item and section conveniences on iOS, and IndexPath does not. This should really not concern you generally, but you should avoid casting backwards and forwards between the Struct and Reference types a lot as this could cause unnecessary performance problems.

If you want to see the struct overlay for Foundation for yourself, take a look here:
https://github.com/apple/swift/tree/master/stdlib/public/SDK/Foundation <https://github.com/apple/swift/tree/master/stdlib/public/SDK/Foundation>

> 
> (Failure on my part, as I did of course know that the .path method/var is in fact different on URL and NSURL)
> 
> Regards,
> Rien
> 
> Site: http://balancingrock.nl
> Blog: http://swiftrien.blogspot.com
> Github: http://github.com/Swiftrien
> Project: http://swiftfire.nl
> 
> 
> 
> 
>> On 06 Jan 2017, at 14:39, Rod Brown via swift-users <swift-users at swift.org> wrote:
>> 
>> Hi Jan,
>> 
>> The Swift 3 URL struct has a modernized version of the NSURL API which works far better in Swift. This replaces “getResourceValue(…)” with the API you mentioned: “resourceValues(forKeys:)”.
>> 
>> 
>> Previously, in Swift 2, you had to use an separate value, use AutoreleasingUnsafeMutablePointers, conditionally cast and then hope you got the value, and that you used the correct typecast for the key you were asking for:
>> 
>> let url = NSURL(fileURLWithPath: "/Users/me/Desktop/File.png")
>> 
>> var fileType: AnyObject? = nil
>> do {
>>    try url.getResourceValue(&fileType, forKey: NSURLTypeIdentifierKey)
>> 
>>    if let type = fileType as? String {
>>        // Use the file type here
>>    } else {
>>        // Handle error
>>    }
>> } catch {
>>    // Handle error
>> }
>> 
>> 
>> In Swift 3 with the new Swift URL, the resourceValues(forKeys:) creates a struct with optional type safe properties representing each resource key type, and returns it, allowing you to use if let syntax:
>> 
>> let url = URL(fileURLWithPath: "/Users/me/Desktop/File.png")
>> if let resourceValues = try? url.resourceValues(forKeys: [.typeIdentifierKey]),
>>   let fileType = resourceValues.typeIdentifier {
>>       // Use the file type here
>> }
>> 
>> 
>> This is a much cleaner, clearer, and type-safe API.
>> 
>> If you want to use the old API, you can simply cast back to NSURL if you require the old behaviour. That said, the new one should serve all your needs and make things so much easier so I recommend you give it a go.
>> 
>> Hope this helps,
>> 
>> Rod
>> 
>> 
>> 
>> 
>>> On 6 Jan 2017, at 6:36 am, J.E. Schotsman via swift-users <swift-users at swift.org> wrote:
>>> 
>>> Hello,
>>> 
>>> Is getResourceValue a method or URL or only on NSURL?
>>> After migrating a project to Swift 3 I have code like
>>> 
>>> var file:URL
>>> file.getResourceValue(...) // compiles!
>>> 
>>> From the documentation and the headers I get the impression that this should not compile!
>>> 
>>> TIA,
>>> 
>>> Jan E.
>>> _______________________________________________
>>> swift-users mailing list
>>> swift-users at swift.org
>>> https://lists.swift.org/mailman/listinfo/swift-users
>> 
>> _______________________________________________
>> swift-users mailing list
>> swift-users at swift.org
>> https://lists.swift.org/mailman/listinfo/swift-users
> 

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-users/attachments/20170107/b7f9987a/attachment.html>


More information about the swift-users mailing list