getResourceValue


(J.E. Schotsman) #1

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.


(Rien) #2

What is your real question?
Obviously the doc says that this is fine, so what are you asking? what is your problem?

Regards,
Rien

Site: http://balancingrock.nl
Blog: http://swiftrien.blogspot.com
Github: http://github.com/Swiftrien
Project: http://swiftfire.nl

···

On 05 Jan 2017, at 20:36, J.E. Schotsman via swift-users <swift-users@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@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Rod Brown) #3

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@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@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(J.E. Schotsman) #4

What is your real question?
Obviously the doc says that this is fine, so what are you asking? what is your problem?

Which doc?
My doc is the Xcode 8.2.1 documentation for URL, which only has the methods

resourceValues(forKeys: Set<URLResourceKey>)

and

setResourceValues(URLResourceValues)

···

On 06 Jan 2017, at 08:25, Rien <Rien@Balancingrock.nl> wrote:

On 05 Jan 2017, at 20:36, J.E. Schotsman via swift-users <swift-users@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!


(Rien) #5

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?).
I also presume that the same is true for Data/NSData, Date/NSDate etc?

(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@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@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@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(J.E. Schotsman) #6

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:)”.

I still feel the need to extend URL with properties like name, parentFolder etc.

If you want to use the old API, you can simply cast back to NSURL if you require the old behaviour.

That isn't necessary for structs conforming to ReferenceConvertible. You just need to import Foundation.

IMO there is a natural class hierarchy here, like

URL -> File
URL -> Folder -> Volume
URL -> Alias

So I am going the opposite way at the moment (double wrapper, ugh!).

Jan E.

···

On 06 Jan 2017, at 14:39, Rod Brown <rodney.brown6@icloud.com> wrote:


(Rod Brown) #7

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

···

On 7 Jan 2017, at 12:50 am, Rien <Rien@balancingrock.nl> wrote:

(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@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@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@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Rien) #8

URL is the same as NSURL in Swift 3

Foundation -> NSURL -> getResourceValue.

If you use xcode, open up the Help -> Documentation and API reference
The do a search for getResourceValue.

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 10:01, J.E. Schotsman via swift-users <swift-users@swift.org> wrote:

On 06 Jan 2017, at 08:25, Rien <Rien@Balancingrock.nl> wrote:

What is your real question?
Obviously the doc says that this is fine, so what are you asking? what is your problem?

Which doc?
My doc is the Xcode 8.2.1 documentation for URL, which only has the methods

resourceValues(forKeys: Set<URLResourceKey>)

and

setResourceValues(URLResourceValues)

On 05 Jan 2017, at 20:36, J.E. Schotsman via swift-users <swift-users@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!

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Rien) #9

Thanks Rod, very enlightening!

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 15:19, Rod Brown <rodney.brown6@icloud.com> wrote:

On 7 Jan 2017, at 12:50 am, Rien <Rien@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

(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@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@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@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users