Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Typecasting in Swift

I am writing a library which can parse typed Ids from JSON. However, I am finding the typecasting rules a little baffling.

Example:

class AccountId : NSString { }

let json : AnyObject? = "user-1" // Returned by NSJSONSerialization.JSONObjectWithData
let s = json as? NSString   // Succeeds, s == Some("user-1")
let a = json as? AccountId  // Fails, a == nil

Why does the first typecast succeed while the second one fail? Is there something magical about NSString which does not crossover to Swift-only classes?

I am using XCode Version 6.1 (6A1030) (the latest at the time of writing).

like image 674
musically_ut Avatar asked Sep 29 '14 16:09

musically_ut


People also ask

What is typecasting in Swift?

Type casting is a way to check the type of an instance, or to treat that instance as a different superclass or subclass from somewhere else in its own class hierarchy. Type casting in Swift is implemented with the is and as operators.

What is typecasting with example?

Converting one datatype into another is known as type casting or, type-conversion. For example, if you want to store a 'long' value into a simple integer then you can type cast 'long' to 'int'. You can convert the values from one type to another explicitly using the cast operator as follows − (type_name) expression.

What is typecasting and its types?

Type casting is when you assign a value of one primitive data type to another type. In Java, there are two types of casting: Widening Casting (automatically) - converting a smaller type to a larger type size. byte -> short -> char -> int -> long -> float -> double.

What is typecasting used for?

Typecast is a way of changing an object from one data type to the next. It is used in computer programming to ensure a function handles the variables correctly. A typecast example is the transformation of an integer into a string.


2 Answers

As a general rule, if you have a hierarchy of classes A -> B -> C (C inherits from B, which in turn inherits from A), and you have an instance of B, you can upcast to A, but you cannot downcast to C.

The reason is that C might add properties which are not available in B, so the compiler or the runtime wouldn't know how to initialize the additional data, not to mention that it must also be allocated.

Note that polymorphism allows you do to upcast and downcast with variables - which means, if you have an instance of C stored in a variable of type A, you can cast that variable to B and C, because it actually contains an instance of C. But if the variable contains an instance of B, you can downcast to B, but not to C.

In your case, rather than downcasting you should specialize a constructor accepting NSString, but I suspect that in this specific case of NSString it cannot be done (there's no NSString designated initializer accepting a string as argument). If you are able to do that, then your code would look like:

var json: AnyObject? = "test"
if let string = json as? NSString {
    let a = AccountId(string: string)
}

and at that point you can use a where an instance of either AccountId or NSString is expected

like image 142
Antonio Avatar answered Oct 13 '22 18:10

Antonio


Is there something magical about NSString which does not crossover to Swift-only classes?

Yes. Swift's String class is automatically bridged to NSString and vice versa. From the docs:

Swift automatically bridges between the String type and the NSString class. This means that anywhere you use an NSString object, you can use a Swift String type instead and gain the benefits of both types—the String type’s interpolation and Swift-designed APIs and the NSString class’s broad functionality. For this reason, you should almost never need to use the NSString class directly in your own code. In fact, when Swift imports Objective-C APIs, it replaces all of the NSString types with String types. When your Objective-C code uses a Swift class, the importer replaces all of the String types with NSString in imported API.

Why does the first typecast succeed while the second one failed?

Because of the strong relationship between String and NSString, the compiler knows how to convert from one to the other. On the other hand, because your AccountId class is a more specialized version of NSString, you can't cast from String to AccountId.

like image 43
Caleb Avatar answered Oct 13 '22 18:10

Caleb