Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to return a custom object in a swift convenience initializer?

I'm trying to do something like this:

public extension UIImage {
    public convenience init(whatever: Int) {
        UIGraphicsBeginImageContextWithOptions(...)

        //...

        let image = UIGraphicsGetImageFromCurrentContext()
        UIGraphicsEndImageContext()

        return image // <- impossible
    }
}

But this is not possible as "nil" is the only valid return for an initializer... How do i do this?

For example, the Objtive-C method [UIImage imageNamed:] is a class method (that can return whatever it wants in Objective-C) and it was mapped to the swift initializer UIImage(named:).

like image 697
Vogel Vogel Avatar asked Oct 19 '15 17:10

Vogel Vogel


People also ask

Does initializer return any value in Swift?

You implement this initialization process by defining initializers, which are like special methods that can be called to create a new instance of a particular type. Unlike Objective-C initializers, Swift initializers don't return a value.

What is the return type of initializer in Swift?

Unlike Objective-C initializers, Swift initializers do not return a value. please explain below syntax. It does initialize a String object by calling the initializer and return it. Value get assigned to instanceOfString .

What does init () do in Swift?

Swift init() Initialization is the process of preparing an instance of a class, structure, or enumeration for use. This process involves setting an initial value for each stored property on that instance and performing any other setup or initialization that is required before the new instance is ready for use.

How do you designate a Failable initializer?

You write a failable initializer by placing a question mark after the init keyword ( init? ). Note: You cannot define a failable and a nonfailable initializer with the same parameter types and names. A failable initializer creates an optional value of the type it initializes.


2 Answers

What you want is a class factory method, not an initializer. Most factory methods in Foundation/Cocoa are automatically bridged to initializers, but if what you want can't be done via init, you can add a new class method:

public extension UIImage {
    class func imageWithWhatever(whatever: Int) -> UIImage {
        UIGraphicsBeginImageContextWithOptions(...)

        //...

        let image = UIGraphicsGetImageFromCurrentContext()
        UIGraphicsEndImageContext()

        return image
    }
}
like image 91
Nate Cook Avatar answered Nov 15 '22 07:11

Nate Cook


This is because you are returning a new object, not self. The point of init is to create the structure of your object, not a new one, so if you want to do it as a convenience init, you need to do it like this:

public extension UIImage {
    public convenience init?(whatever: Int) {
        defer {
            UIGraphicsEndImageContext()
        }
        UIGraphicsBeginImageContextWithOptions(...)

        //...
        guard let currentContext = UIGraphicsGetCurrentContext() else { return nil }
        guard let image = currentContext.makeImage() else { return nil }

        self.init(cgImage:image)
    }
}

perhaps instead of a convenience init, you want to create a class function that is doing what you are asking:

public class func createImage(whatever: Int) -> UIImage? {
    defer {
        UIGraphicsEndImageContext()
    }
    UIGraphicsBeginImageContextWithOptions(...)

    //...
    guard let currentContext = UIGraphicsGetCurrentContext() else { return nil }
    guard let cgImage = currentContext.makeImage() else { return nil }
    let image = UIImage(cgImage: cgImage)

    return image
}

I apologize that this is not 100% to code, but that is basically the gist of it

like image 22
Knight0fDragon Avatar answered Nov 15 '22 06:11

Knight0fDragon