Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UIButton as UIButton in swift?

Tags:

swift

I am watching this Swift tutorial and there is this line:

var button:UIButton = UIButton.buttonWithType(UIButtonType.System) as UIButton

two questions:

  1. why is that line ending with as UIButton? Isn't the line clear enough that the user wants to create a button of system type? It appears to be redundant.
  2. is it necessary to declare the type UIButton on the first part of the line? Or in other words, isn't enough to declare it like

var button = UIButton.buttonWithType(UIButtonType.System)

I mean, if the part after the equal sign is initializing a button of system type is not that enough for the compiler to infer button is a UIButton? I mean, Apple said the compiler is smart to infer types.

like image 866
Duck Avatar asked Jul 01 '14 19:07

Duck


Video Answer


3 Answers

You need to keep the as UIButton downcast. buttonWithType() return AnyObject!, not UIButton, so the downcast is necessary. Other than that, you don't need to explicitly type the variable with : UIButton. Since the return type of buttonWithType() as downcast to UIButton, the variables type will be inferred to be UIButton. This is what you should use:

var button = UIButton.buttonWithType(UIButtonType.System) as UIButton
like image 89
Mick MacCallum Avatar answered Oct 14 '22 19:10

Mick MacCallum


Some additional background in addition to the already given answers: The Objective-C method

+ (id)buttonWithType:(UIButtonType)buttonType

returns id. This was the "traditional" way to declare a "factory method" in a way that it can be used from subclasses as well. There is no type cast necessary in

UIButton *button = [UIButton buttonWithType: UIButtonTypeSystem];

because id can be converted to any Objective-C pointer.

Now the equivalent type to id in Swift is AnyObject, and the above method is mapped to

class func buttonWithType(buttonType: UIButtonType) -> AnyObject!

Swift is much more strict and does not implicitly convert types, therefore the return value has to be cast to UIButton explicitly:

var button = UIButton.buttonWithType(UIButtonType.System) as UIButton

The "modern" approach to declare factory methods is instancetype (see for example http://nshipster.com/instancetype/ or Would it be beneficial to begin using instancetype instead of id?). A simple example is the NSString method

+ (instancetype)stringWithCString:(const char *)cString encoding:(NSStringEncoding)enc

which is mapped in Swift to

class func stringWithCString(cString: CString, encoding enc: UInt) -> Self!

Self is the type of the object on which the method is called, so that the return type of

NSString.stringWithCString("foo", encoding: NSUTF8StringEncoding)

is NSString! and the return type of

NSMutableString.stringWithCString("bar", encoding: NSUTF8StringEncoding)

is NSMutableString!. No type cast is necessary in Swift. In the following example, the Swift compiler "knows" that str is an NSString:

var str = NSString.stringWithCString("foo", encoding: NSUTF8StringEncoding)
var cs = str.UTF8String

The Foundation framework headers already use instancetype in many places, but not yet everywhere where possible (as in buttonWithType:). This may be improved in future releases of the SDKs.

like image 39
Martin R Avatar answered Oct 14 '22 20:10

Martin R


If you cmd click the buttonWithType you will see that in swift its declared as

class func buttonWithType(buttonType: UIButtonType) -> AnyObject!

Since the type it returns is AnyObject! you need to type cast it back to UIButton.

like image 32
Moti F. Avatar answered Oct 14 '22 18:10

Moti F.