11

I'm rewriting an Objective C category below to Swift:

@implementation UIImage (Extra)

+ (UIImage *)validImageNamed:(NSString *)name
{
    UIImage *image = [self imageNamed:name];
    NSAssert(image, @"Unable to find image named '%@'", name);
    return image;
}

This asks to be implemented as an convenience init, but how can I check if designated initializer self.init(named:) succeeds?

extension UIImage {
    convenience init(validateAndLoad name: String!) {
        self.init(named: name)

        // need to assert here if self.init fails
    }

When self.init(named:) call fails, extension's init stops executing.

I've tried creating an UIImage instance and assigning it to self, but this doesn't compile.

Of course, a helper method can be used like in ObjC version:

extension UIImage {

    class func validImage(named name: String) -> UIImage {
        var image = UIImage(named: name)
        assert(image == nil, "Image doesn't exist")
        return image
    }

But is there a way to implement this using an initializer?

memmons
  • 40,222
  • 21
  • 149
  • 183
Zmey
  • 2,304
  • 1
  • 24
  • 40

3 Answers3

8

You can now create failable initializers in extensions; however, the initializers can not be defined in a protocol.

class Thing {

    var text:String?

}

extension Thing  {

    convenience init?(text:String) {
        self.init()
        if text == "" {
            return nil
        } else {
            self.text = text
        }
    }
}


let that = Thing(text: "Hello")
println(that?.text) //prints Optional("Hello")

let empty = Thing(text: "")
println(empty) //prints nil
Kelton
  • 96
  • 2
  • 1
3

Unlike Objective-C, Swift initializers don't return self, so checking for initialization failures is not possible. An Apple engineer suggested using a factory method with an optional return type instead:

class ImageFactory {

    class func validImage(named name: String) -> UIImage? 
    {
        var image = UIImage(named:name)
        assert(image != nil, "fail")
        return image;
    }
}

The Apple engineer indicated that they are working on building something into the language that will get around using factory class methods.

memmons
  • 40,222
  • 21
  • 149
  • 183
0

i would write the method like below:

extension UIImage {

class func validImage(named name: String) -> UIImage? {
    var image = UIImage(named: name)
    return image
}

in swift you can use optionals. If here is no image with the given name the method will return nil.

Mike Lischke
  • 48,925
  • 16
  • 119
  • 181
Areal-17
  • 406
  • 3
  • 10