Swift: returning Self in class method using error handling for init method

I'm sorry, I am newbie in Swift, but I have about 5 years of development in Objective-C.


Here is the deal. I have frequently used regular expression, so I decide to write extension with method which returns regex with predefined pattern and options. But in my case NSRegularExpression initialization demands error handling. Because of that I have to declare a variable before init. But the type of this variable should be Self (because it's class method and it should return Self)!
So my code may be look like that:


class func frequentlyUsedExpression() -> Self {
    
        let pattern = "frequently_used_pattern"
    
        var regex : Self? = nil
        do {
            regex = try self(pattern: pattern, options: [])
        } catch let error as NSError {
            print(error)
            regex = nil
        }
    
        return regex
    }


But I cannot create Self-type variable.


I cannot ignore error handling even if I would. Because of that I cannot do "return self(pattern: pattern, options: [])", which can be used in other cases.
I cannot declare regex as NSRegularExpression, because it's impossible to cast it in Self in return.
I cannot create convenience initializer, because my method have no parameters.


I spent about three hours trying to solve it, but still don't know what to do.

Answered by LCS in 10724022

In Swift, functions and methods generally return a specific type , and the return type needs to be optional, since you might be returning nil.

(There's also seems to be a Swift bug related to Self?, since trying to return Self? from your class function crashes SourceKit, so until that is fixed you couldn't return Self? anyway)


You can return values from inside the do and catch blocks, so this would work for your function:

extension NSRegularExpression
{
    class func frequentlyUsedExpression() -> NSRegularExpression?
    {
        let pattern = "frequently_used_pattern"
     
        do
        {
            let regex = try self(pattern: pattern, options: [])
            return regex
        }
        catch
        {
            print(error)
            return nil
        }
    }

}



If you want subclasses of NSRegularExpression to be able to explicitly return their own type, it would be possible to create a convenience initializer that take an enum parameter and returns the appropriate pattern. (And, I think this is a cleaner way to implement it in Swift, anyway.)


enum CommonRegexPatterns: String
{
    case Pattern01 = "frequently_used_pattern01"
    case Pattern02 = "frequently_used_pattern02"
    // [...]
}


extension NSRegularExpression
{
    convenience init?(custom: CommonRegexPatterns)
    {
        let pattern = custom.rawValue
      
        do
        {
            try self.init(pattern: pattern, options: [])
        }
        catch
        {
            print(error)
            return nil
        }
    }
  
}


let x = NSRegularExpression(custom: .Pattern01)
Accepted Answer

In Swift, functions and methods generally return a specific type , and the return type needs to be optional, since you might be returning nil.

(There's also seems to be a Swift bug related to Self?, since trying to return Self? from your class function crashes SourceKit, so until that is fixed you couldn't return Self? anyway)


You can return values from inside the do and catch blocks, so this would work for your function:

extension NSRegularExpression
{
    class func frequentlyUsedExpression() -> NSRegularExpression?
    {
        let pattern = "frequently_used_pattern"
     
        do
        {
            let regex = try self(pattern: pattern, options: [])
            return regex
        }
        catch
        {
            print(error)
            return nil
        }
    }

}



If you want subclasses of NSRegularExpression to be able to explicitly return their own type, it would be possible to create a convenience initializer that take an enum parameter and returns the appropriate pattern. (And, I think this is a cleaner way to implement it in Swift, anyway.)


enum CommonRegexPatterns: String
{
    case Pattern01 = "frequently_used_pattern01"
    case Pattern02 = "frequently_used_pattern02"
    // [...]
}


extension NSRegularExpression
{
    convenience init?(custom: CommonRegexPatterns)
    {
        let pattern = custom.rawValue
      
        do
        {
            try self.init(pattern: pattern, options: [])
        }
        catch
        {
            print(error)
            return nil
        }
    }
  
}


let x = NSRegularExpression(custom: .Pattern01)

It makes sense. Thank you so much! 🙂

Swift: returning Self in class method using error handling for init method
 
 
Q