Duck
Duck

Reputation: 35933

UIButton as UIButton in 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.

Upvotes: 6

Views: 3877

Answers (4)

Shane
Shane

Reputation: 397

Swift 2.1 is now

var button = UIButton(type: .System)

so no need to downcast with .buttonWithType

Upvotes: 0

Martin R
Martin R

Reputation: 539685

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.

Upvotes: 7

Moti F.
Moti F.

Reputation: 142

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.

Upvotes: 2

Mick MacCallum
Mick MacCallum

Reputation: 130193

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

Upvotes: 9

Related Questions