Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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 :|

like image 680
Kelvin Lau Avatar asked Dec 15 '25 03:12

Kelvin Lau


1 Answers

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")
like image 82
werediver Avatar answered Dec 16 '25 20:12

werediver



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!