Skip to content
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-2728] fileReferenceURL not working correctly #4511

Open
swift-ci opened this issue Sep 22, 2016 · 12 comments
Open

[SR-2728] fileReferenceURL not working correctly #4511

swift-ci opened this issue Sep 22, 2016 · 12 comments

Comments

@swift-ci
Copy link
Contributor

@swift-ci swift-ci commented Sep 22, 2016

Previous ID SR-2728
Radar None
Original Reporter fblondiau (JIRA User)
Type Bug

Attachment: Download

Additional Detail from JIRA
Votes 5
Component/s Foundation
Labels Bug, 3.0Regression
Assignee None
Priority Medium

md5: 30730ac083db546182191b11523e86d5

Issue Description:

In Swift 3.0 (i.e. Xcode 8.0 or Xcode 8.1 beta 1), a call to fileReferenceURL does NOT give a file reference URL anymore... this code

import Foundation
let string = "file:///Users/admin"
if let url = NSURL(string: string) {
    if let ref = url.fileReferenceURL() {
      print ("ref = \(ref)")
    }
}

prints

{{ ref = file:///Users/admin/}}

while it should have been printing

{{ ref = file:///.file/id=6571367.437879/}}

as it did, correctly, in Swift 2.2 (and before) in Xcode 7.3.1 for example.

@belkadan
Copy link

@belkadan belkadan commented Sep 22, 2016

@phausler, did we come up with an answer to this?

@phausler
Copy link
Member

@phausler phausler commented Sep 22, 2016

It was decided for the erring cases to avoid bridging file reference urls. The are both technically a different type in spirit and they actually behave much more like a reference type than a structure.

The peephole optimization for as casting back to NSURL ought to preserve it's reference nature. Unfortunately we did not get enough time to push through proposals to add any additional types to account for this (since it would mean pretty massive overhauls to the objc side)

@swift-ci
Copy link
Contributor Author

@swift-ci swift-ci commented Oct 6, 2016

Comment by Sanjay Madan (JIRA)

In the meantime, is there a workaround? Given a path URL, how does one get a file reference URL in Swift? I need to watch the contents of a folder, even if the folder is renamed or moved.

@swift-ci
Copy link
Contributor Author

@swift-ci swift-ci commented Oct 6, 2016

Comment by Frédéric Blondiau (JIRA)

I wrote this workaround (in attachement, to avoid text formatting processing... as I also had to watch items renamed or moved.

It seems to work correctly – but I would be pleased to get some confirmation that there are no hidden problems :-)

Workaround.pdf

@swift-ci
Copy link
Contributor Author

@swift-ci swift-ci commented Oct 6, 2016

Comment by Sanjay Madan (JIRA)

Thank you, Fédéric! This seems to work. In the first line I'm curious why you used URL (self as URL) to get the fileResourceIdentifier. Why didn't you just use the corresponding method on NSURL (self) directly? That method returns a dictionary which you can index with .fileResourceIdentifierKey.

@swift-ci
Copy link
Contributor Author

@swift-ci swift-ci commented Oct 6, 2016

Comment by Frédéric Blondiau (JIRA)

Generally, accessing the resourceIdentifiers of the URL thru the properties (instead of accessing the resourceIdentifiers of the NSURL thru the keys) may give more precise information associated with the returned value – here, fileResourceIdentifier is of type (NSCopying & NSSecureCoding & NSObjectProtocol)? instead of Any.
In this case, as we are casting the returned value to Data, I think we can, indeed, avoid bridging to URL using your suggestion. I updated the attachment. Workaround V2.pdf

@parkera
Copy link
Member

@parkera parkera commented Dec 2, 2016

Note that it is expected behavior that struct URL does not support file reference URLs.

The unfortunate part here is that we don't have a mechanism to keep NSURL.fileReferenceURL from being imported as returning struct URL instead of NSURL. We probably need to add an ObjC thunk in the overlay and mark the API as NS_REFINED_FOR_SWIFT in the NSURL.h header. However, that would be a source breaking change.

@swift-ci
Copy link
Contributor Author

@swift-ci swift-ci commented Mar 5, 2017

Comment by Charles Srstka (JIRA)

Unfortunately, Frédéric's workaround depends on the internal layout of reference URLs, which is undocumented and which could change at any time, particularly given that APFS is just around the corner. I don't recommend it.

A still somewhat hackish, but ultimately much safer option is just to use the Objective-C runtime:

let url = ...

if let refURL = (url as NSURL).perform(#selector(NSURL.fileReferenceURL))?.takeUnretainedValue() as? NSURL {
    print(refURL) // will print something along the lines of 'file:///.file/id=01234546.789012345'
}

This will just invoke the original Objective-C -fileReferenceURL method without involving the reference-mangling Swift bridging mechanism.

@lilyball
Copy link
Mannequin

@lilyball lilyball mannequin commented Mar 28, 2018

Just ran into this. We really should come up with a solution.

There is (or at least used to be) a workaround for incorrectly-nonnull APIs where you could say something like

let foo: TheType? = APIThatReturnsNonnull()

and Swift would skip the nonnull check and instead treat the API as returning a nullable object.

Perhaps we could introduce the same kind of workaround for reference convertible types, where explicitly annotating the return value as the Obj-C type would skip the reference conversion? This would also just be a performance optimization in general, because writing something like

(someNSString.methodThatReturnsString() as NSString).anotherMethod

really has no business bridging the intermediate string into String just to convert it right back to NSString.

@belkadan
Copy link

@belkadan belkadan commented Mar 28, 2018

I believe we have that already, at least in Swift 4.1. Is it not working?

@lilyball
Copy link
Mannequin

@lilyball lilyball mannequin commented Mar 28, 2018

Oh, I only tested Swift 4.0.3, because this issue is still open.

Testing in a Swift 4.1 snapshot, you're right, someNSURL.fileReferenceURL() as NSURL? is giving me a reference URL back, meaning it's not round-tripping through URL. Glad to know that escape hatch now exists.

@lilyball
Copy link
Mannequin

@lilyball lilyball mannequin commented Mar 28, 2018

Incidentally, someNSURL.fileReferenceURL()! as NSURL doesn't give me a reference URL back. In an ideal world it might be nice to skip the round trip there as well, though I can understand why it doesn't right now.

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
@shahmishal shahmishal transferred this issue from apple/swift May 5, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants