Return Instancetype in Swift

How can I return instancetype in Swift from instance method

The very short answer is no there is no direct equivalent.

The more detailed answer is that the languages are conceptually different.

  • In Objective-C anything returned is an object aka id. Using instancetype is a hint to the compiler and IDE for a specific type to allow further checks and auto-completion. This works for sub-classing and extensions.
  • Swift is strongly typed, there is no base object and we also have classes and structs. A function can only return a specific type, Self, a generic type or an associatedtype. The best approximation would be to move this functionality into an extension or protocol and use Self. This would work the same way. There is no equivalent for this in a sub classing context.

Long detailed answer Return instancetype in Swift

How can I return instancetype in Swift

You can do it. Playground code below. It's self() that niceObject() has to return. Additionally, you must have a required init on the base class.

class A {
required init() {
}

func whatClassAmI() -> String {
return "Class A"
}
}

class B: A {
required init() {
super.init()
}
override func whatClassAmI() -> String {
return "Class B"
}
}

let a = A()
let sa = a.whatClassAmI() // "Class A", of course

let b = B()
let sb = b.whatClassAmI() // "Class B", of course

extension A {
class func niceObject() -> Self {
return self.init()
}
}

let aa = A.niceObject()
let saa = aa.whatClassAmI() // "Class A"

let bb = B.niceObject()
let sbb = bb.whatClassAmI() // "Class B", as required

Return instancetype in Swift

Similar as in Using 'self' in class extension functions in Swift, you can define a generic helper method which infers the type of self from the calling context:

extension UIViewController
{
class func instantiateFromStoryboard(storyboardName: String, storyboardId: String) -> Self
{
return instantiateFromStoryboardHelper(storyboardName, storyboardId: storyboardId)
}

private class func instantiateFromStoryboardHelper<T>(storyboardName: String, storyboardId: String) -> T
{
let storyboard = UIStoryboard(name: storyboardName, bundle: nil)
let controller = storyboard.instantiateViewControllerWithIdentifier(storyboardId) as! T
return controller
}
}

Then

let vc = MyViewController.instantiateFromStoryboard("name", storyboardId: "id")

compiles, and the type is inferred as MyViewController.


Update for Swift 3:

extension UIViewController
{
class func instantiateFromStoryboard(storyboardName: String, storyboardId: String) -> Self
{
return instantiateFromStoryboardHelper(storyboardName: storyboardName, storyboardId: storyboardId)
}

private class func instantiateFromStoryboardHelper<T>(storyboardName: String, storyboardId: String) -> T
{
let storyboard = UIStoryboard(name: storyboardName, bundle: nil)
let controller = storyboard.instantiateViewController(withIdentifier: storyboardId) as! T
return controller
}
}

Another possible solution, using unsafeDowncast:

extension UIViewController
{
class func instantiateFromStoryboard(storyboardName: String, storyboardId: String) -> Self
{
let storyboard = UIStoryboard(name: storyboardName, bundle: nil)
let controller = storyboard.instantiateViewController(withIdentifier: storyboardId)
return unsafeDowncast(controller, to: self)
}
}

How can I initiate an instancetype from Objective-C with Swift

var mobileApi = MobileAPI.newDemoInstance()

or

let mobileApi = MobileAPI.newDemoInstance()

if you don't intend to modify it.

Obj-C Instance method returning a instanceType called from Swift - Function produces expected type 'UIImage!' error

If you look at the method you have defined in Objective C image category, it is instance method and you are trying to call it using UIImage class in swift.

You can basically use either one of the following two approaches,

Either,

self.backgroundImageView.image = self.someImage.applyDarkEffect() // notice the method does not take argument

Or if you want to use class level method, then first create a closure and call it as,

let applyEffectToImageClosure = UIImage.applyDarkEffect(self.someImage)
self.backgroundImageView.image = applyEffectToImageClosure()

How to access Customalertview objective C instancetype method in swift

It should look something like this:

UIAlertView(title: "Title", message: "Message", delegate: self, cancelButtonTitle: "Cancel", otherButtonTitles: "OtherButton1", "OtherButton2")

I'm not sure what CustomAlertView is. If that's your class, replace UIAlertView with CustomAlertView in the initializer.

otherButtonTitles is a comma separated list of Strings:

public convenience init(title: String, message: String, delegate: UIAlertViewDelegate?, cancelButtonTitle: String?, otherButtonTitles firstButtonTitle: String, _ moreButtonTitles: String...)

You don't need to use a singleton like in Rahul's answer.

Assuming your CustomAlertView.h file looks like this:

#import <UIKit/UIKit.h>

@interface CustomAlertView : UIAlertView

-(instancetype)initWithTitle:(NSString *)title message:(NSString *)message delegate:(id)delegate cancelButtonTitle:(NSString *)cancelButtonTitle otherButtonTitles:(NSString *)otherButtonTitles, ...;

@end

You can import CustomAlertView.h into your bridging header and initialize the class like this in Swift 3:

CustomAlertView(title: "Title", message: "Message", delegate: self, cancelButtonTitle: "Cancel", otherButtonTitles: "Other1", "Other2")

How to call Objective-C instancetype method in Swift?

You are not supposed to write initializer like that in Objective C. Either you should have it just init or then if you are passing argument in constructor then only you can name it otherwise.

Here is how you can do it,

@interface CustomObjectHavingData : NSObject

@property (nonatomic, strong) NSData *objWithData;

- (instancetype)initWithObjHavingData:(NSData *)data;

@end


@implementation CustomObjectHavingData

- (instancetype)initWithObjHavingData:(NSData *)data
{
if (self = [super init]) {
_objWithData = data;
}

return self;
}

@end

In Swift, you can simply call it like this,

  let myCustomObject = CustomObjectHavingData(objHavingData: someData)

The name is quite inappropriate though.

Generic Return Type Based on Class

You can use the class-level Self for this:

extension NSObject {
class func create() -> Self {
return self.init()
}
}

let array = NSArray.create()

But I don't really see why you would, since you might as well just add an initializer.



Related Topics



Leave a reply



Submit