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
. Usinginstancetype
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 anassociatedtype
. The best approximation would be to move this functionality into anextension
orprotocol
and useSelf
. 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
How to Use String.Substringwithrange? (Or, How Do Ranges Work in Swift)
How to Get a Reference to the App Delegate in Swift
Firestore Search Array Contains For Multiple Values
Swift Optional Escaping Closure Parameter
How to Get Current Language Code With Swift
Changing Navigation Title Programmatically
How to Pass Multiple Enum Values as a Function Parameter
How to Remove the Left and Right Padding of a List in Swiftui
Nehotspothelper.Register Not Received Call Back Ios11
How to Dispatch_Sync, Dispatch_Async, Dispatch_After, etc in Swift 3, Swift 4, and Beyond
Load a Uiview from Nib in Swift
Send Data from Tableview to Detailview Swift
Uialertcontroller - Add Custom Views to Actionsheet
Swift: How to Use Preprocessor Flags (Like '#If Debug') to Implement API Keys
Getting "File Not Found" in Bridging Header When Importing Objective-C Frameworks into Swift Project