Kelvin Lau Kelvin Lau - 7 months ago 59
Swift Question

NSURL extension to adopt StringLiteralConvertible

According to this post from NSHipster, we have extended the

NSURL
class to initialize
NSURL
objects using literals like this:

// the following is a full fledged NSURL object
let url: NSURL = "http://nshipster.com/"


Unfortunately, the post was written when Swift was first announced and it no longer compiles.

I was able to get my own custom object to conform to
StringLiteralConvertible
, and it looked like this:

final class Dog {
let name: String

init(name: String) {
self.name = name
}
}

// MARK: - StringLiteralConvertible
extension Dog: StringLiteralConvertible {
typealias UnicodeScalarLiteralType = StringLiteralType
typealias ExtendedGraphemeClusterLiteralType = StringLiteralType

convenience init(unicodeScalarLiteral value: UnicodeScalarLiteralType) {
self.init(stringLiteral: value)
}

convenience init(extendedGraphemeClusterLiteral value: ExtendedGraphemeClusterLiteralType) {
self.init(stringLiteral: value)
}

convenience init(stringLiteral value: StringLiteralType) {
self.init(name: value)
}
}


This works great. For example, the following 2 lines of code will create a
Dog
object:

let dog = Dog(name: "Bob")
let dog: Dog = "Bob"


Unfortunately, using this strategy via extending
NSURL
was met with errors:

extension NSURL: StringLiteralConvertible {
public typealias UnicodeScalarLiteralType = StringLiteralType
public typealias ExtendedGraphemeClusterLiteralType = StringLiteralType

convenience public init?(unicodeScalarLiteral value: UnicodeScalarLiteralType) {
self.init(stringLiteral: value)
}

convenience public init?(extendedGraphemeClusterLiteral value: ExtendedGraphemeClusterLiteralType) {
self.init(stringLiteral: value)
}

convenience public init?(stringLiteral value: StringLiteralType) {
self.init(string: value)
}
}


I've been trekking through the compiler errors, solving them 1 guess at a time. However, I can't get past the following error that occurs for each of the initializers:

Initializer requirement 'init(...)' can only be satisfied by a 'required' initializer in the definition of non-final class 'NSURL'


Adding the
required
keyword will give the error that you may not declared required initializers within extensions.

Looking for some directions :|

Answer

StringLiteralConvertible support

Unfortunately, StringLiteralConvertible support for NSURL seems to be not possible in the current Swift version (2.2). The closest I can get is the following:

extension NSURL: StringLiteralConvertible {

    public convenience init(stringLiteral value: String) {
        self.init(string: value)!
    }

    public convenience init(extendedGraphemeClusterLiteral value: String) {
        self.init(string: value)!
    }

    public convenience init(unicodeScalarLiteral value: String) {
        self.init(string: value)!
    }

}

But the compiler complains:

Playground execution failed: OS X Playground.playground:5:24: error: initializer requirement 'init(stringLiteral:)' can only be satisfied by a `required` initializer in the definition of non-final class 'NSURL'
    public convenience init(stringLiteral value: String) {
                       ^
OS X Playground.playground:3:24: error: initializer requirement 'init(extendedGraphemeClusterLiteral:)' can only be satisfied by a `required` initializer in the definition of non-final class 'NSURL'
    public convenience init(extendedGraphemeClusterLiteral value: String) {
                       ^
OS X Playground.playground:7:24: error: initializer requirement 'init(unicodeScalarLiteral:)' can only be satisfied by a `required` initializer in the definition of non-final class 'NSURL'
    public convenience init(unicodeScalarLiteral value: String) {

And required initializers cannot be implemented in an extension.

Alternative solution

We can simplify string-to-URL conversion from the other side!

extension String {

    var url: NSURL? {
        return NSURL(string: self)
    }

}

var url = "http://google.coom/".url
print(url?.scheme) // Optional("http")
Comments