No more stringByAppendingPathComponent in Xcode 7 beta 5?

I may have missed it in the release notes, but the Xcode 7 beta 5 compiler is complaining that stringByAppendingPathComponent is not available on String (only NSString). Is this intentional or a bug I wonder?

Replies

Same here...anything with path is unavailable. Did not see it in the release notes either.

I was going to post this myself - its other methods too:


error: 'stringByAppendingPathComponent' is unavailable: Use stringByAppendingPathComponent on NSString instead.
error: 'lastPathComponent' is unavailable: Use lastPathComponent on NSString instead.


I thought NSString methods were all suppose to be bridged into Swift strings...

I hope this is a bug ... or I have to fix 162 errors :-(


This is my workaround for the methods i use:


extension String {

    var lastPathComponent: String {
       
        get {
            return (self as NSString).lastPathComponent
        }
    }
    var pathExtension: String {
       
        get {
           
            return (self as NSString).pathExtension
        }
    }
    var stringByDeletingLastPathComponent: String {
       
        get {
           
            return (self as NSString).stringByDeletingLastPathComponent
        }
    }
    var stringByDeletingPathExtension: String {
       
        get {
           
            return (self as NSString).stringByDeletingPathExtension
        }
    }
    var pathComponents: [String] {
       
        get {
           
            return (self as NSString).pathComponents
        }
    }

    func stringByAppendingPathComponent(path: String) -> String {
       
        let nsSt = self as NSString
       
        return nsSt.stringByAppendingPathComponent(path)
    }

    func stringByAppendingPathExtension(ext: String) -> String? {
       
        let nsSt = self as NSString
       
        return nsSt.stringByAppendingPathExtension(ext)
    }
}

I dont know why just now the compiler is complain about this:


Xcode 6.3 Release Notes


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.

This means that the following code will no longer work:

import Foundation
func log(s: String) { println(x) }
let ns: NSString = "some NSString" // okay: literals still work
log(ns) // fails with the error
  // "'NSString' is not convertible to 'String'"

In order to perform such a bridging conversion, make the conversion explicit with the as keyword:

log(ns as String) // succeeds
Implicit conversions from Swift value types to their bridged Objective-C classes are still permitted. For example:


func nsLog(ns: NSString) { println(ns) }
let s: String = “some String”
nsLog(s) // okay: implicit conversion from String to NSString is permitted


Note that these Cocoa types in Objective-C headers are still automatically bridged to their corresponding Swift type, which means that code is only affected if it is explicitly referencing (for example)

NSString
in a Swift source file. It is recommended you use the corresponding Swift types (for example,
String
) directly unless you are doing something advanced, like implementing a subclass in the class cluster. (18311362)


[Swift 1.2]

This is definitely annoying. Here's something to lessen the pain a bit:


import Foundation

public extension String {
     var NS: NSString { return (self as NSString) }
}


"hi there".NS.stringByAppendingPathComponent("people")


It's a little nicer than scattering ("hi there" as NSString) everywhere, anyway. I still hope they fix it.

Why not just go whole hog and add an extension to String with a function of stringByAppendingPathComponent(). If Apple lets it work as it did before in the future, then you could remove the extension and not have to go edit your code all over.


EDIT: Hah! Code already posted by tieferbegabt

There not to fix!


This is a intended behavior and the correct behavior, if you want a NSString, use a NSString not a String.

Well, I'm using a Cocoa API that is returning an NSString. Then Swift bridges over to String for me "for free", but now I have to write code to bridge it back to what it really is. For example:


NSTemporaryDirectory() as NSString).stringByAppendingPathComponent(...


NSTemporaryDirectory() actually returns a NSString, even thought Swift bridges it to a String.

That's unpleasant. I really hope they fix it!

While that's true, when Apple made that change, they added extensions on String to the Foundation module that would have the same interfaces as the NSString methods, so that while technically the implicit conversions were gone, they would still behave the same in most cases. This is why it continued to work until now, and indeed most of the NSString stuff is still there — for example, stringByAppendingFormat() and dataUsingEncoding() still work, among others. It seems to be specifically the methods in NSPathUtilities.h that have been removed from the String extension, and given that they've introduced a specific error message saying to use NSString instead, it sounds like it is deliberate, rather than a bug. I wouldn't expect this to be fixed.


My guess is that they are trying to discourage the use of paths in favor of URLs to refer to files (although that doesn't help when you want to do something like construct a filename by appending a path extension to a base name before passing that to URLByAppendingPathComponent on the parent directory's URL. But oh well).

What's wrong with 'URLByAppendingPathExtension'?

It can lead to incorrect results.


Suppose you've got a parent directory, referred to by an NSURL named "parentURL". This directory contains two items: "foo", which is a directory, and "foo.txt", which is a regular file. So, you:


let base = parentURL.URLByAppendingPathComponent("foo")


As part of its operation, URLByAppendingPathComponent does an lstat on the file to determine whether or not it is a directory; if it is, it adds a trailing slash to the pathname. So, base now contains "file:///path/to/foo/". Now, add the extension:


let full = base.URLByAppendingPathExtension("txt")


Unfortunately, URLByAppendingPathExtension preserves the directory status of the original URL, so full now contains "file:///path/to/foo.txt/", even though it should simply be "file:///path/to/foo.txt".


Alternatively, if "foo" doesn't exist (which is actually pretty likely if you're creating the URL this way), URLByAppendingPathComponent will assume it's not a directory. If the filename with extension is a directory, this will end up not having a trailing slash even though it should.


Yes, if you know ahead of time whether the file system item is a directory or not, you can pass the explicit isDirectory: parameter to URLByAppendingPathComponent. If you don't know it, though, it's important to fully compose the filename before handing it to URLByAppendingPathComponent.


There are other cases as well, such as NSSavePanel's "nameFieldStringValue" property, in which using an NSURL is not necessarily applicable.

Well, Swift is designed to make our code less buggy, more secure, and more reliable. I guess Apple feels one way to accomplish that is having each of us slowly re-write Cocoa function by function.

I have the same problem... But usually i change from string to NSString early as possible, just after get the return.


It's annoying sometimes, but is better at end the day. Some operations can be made more efficiently using only Swift. And others is not used all the time, and when is, like said, i change my datatype to NSString.

thanks for those extensions, i had nearly 80 errors...