Search code examples
iosswiftoption-typeswift-protocolsswift-extensions

Swift protocol default implementation for optional readonly variables


I have the following piece of code, the protocol MyDisplayable has three optional Strings, and I have a default implementation of the protocol via extension. My question is, since I'm sure the extension returns the three strings, is there a way I can use them as non-optional and is there any risk if some other implementation overwrites it? (see the question points 1 and 2 in code below)

Thanks a lot!

protocol MyDisplayable {
    var displayName: String? { get }
    var shortDescription: String? { get }
    var longDescription: String? { get }
}

protocol MyObject : MyDisplayable, CustomStringConvertible {
}

extension MyObject {
    var displayName: String? {
        return "noname"
    }

    var shortDescription: String? {
        return "something can't be described"
    }

    var longDescription: String? {
        return "no way to describe it further"
    }

    var description: String {
        // **1. is there a way to use the strings as if they are non-optional?**
        // **2. is it a problem if another class implements the protocol and returns `nil` for any of the strings, but here they are force unwrapped?**
        return "\(displayName!): \(shortDescription!)\n\(longDescription!)"
    }
}

class Something : MyObject {
}

let something = Something()
print("Something: \(something)")

Solution

  • Unfortunately, it's not possible to treat a declared optional as a non-optional. You have declared those strings as optional in your protocol, thus when you implement that protocol they stay optional.

    However, you can use getter-setter to ensure that your variables always store some value even when they are declared as optional.

    I'll elaborate with some code :

    protocol MyDisplayable {
        var displayName: String? { get set }
        var shortDescription: String? { get set }
        var longDescription: String? { get set }
    }
    
    protocol MyObject : MyDisplayable, CustomStringConvertible {
    }
    
    extension MyObject {
        var displayName: String? {
            get {
                return "noname"
            }
            set {
                newValue ?? ""
            }
        }
    
        var shortDescription: String? {
            get {
                return "something can't be described"
            }
            set {
                newValue ?? ""
            }
        }
    
        var longDescription: String? {
            get {
                return "no way to describe it further"
            }
            set {
                newValue ?? ""
            }
        }
    
        var description: String {
            // **1. is there a way to use the strings as if they are non-optional?**
            // **2. is it a problem if another class implements the protocol and returns `nil` for any of the strings, but here they are force unwrapped?**
            return "\(displayName!): \(shortDescription!)\n\(longDescription!)"
        }
    }
    
    class Something : MyObject {
    }
    
    let something = Something()
    print("Something: \(something)")
    

    Now even if some other class overwrites a nil value to those strings they will return empty string "". They will still be optional as they are declared optional, but now they will always have a non-nil value.