Is there any way I cast a class without knowing the actual class directly?
E.g.
if ([editedObject isKindOfClass:[object class]])
{
object = editedObject;
}
I have this code, I pass an object to the method called 'object'. Let says object is a Person class, but it could also be an Animal class. So I can't do this:
object = (Person *)editedObject;
Because I don't know for sure its that class. So how can I cast the class without directly knowing it?
Thanks.
What you are trying to do doesn't make sense. Different object pointer types is a purely compile-time thing. A cast from one object pointer type to another is purely for syntactic convenience, and does not perform any "operations" at runtime (it does not even check that the object is the type you cast it to).
So if you "don't know" the type at compile-time, then there is no syntactic convenience to take advantage of by casting. So there is completely no point to "casting".
Related
let screen = mainStoryBoard.instantiateViewController(withIdentifier: self.screenPresenter.screenPresenterIdentifier) as? variable_name
I have to use some variable_name in as? and
variable_name = type(of: object_name)
and
object_name = ExampleViewController() // ExampleViewController is of type UIViewController
Edit:-
means i want to ask after as? we have to provide some Class in which we have to convert like let screen = mainStoryBoard.instantiateViewController(withIdentifier: self.screenPresenter.screenPresenterIdentifier) as? ExampleViewController here ExampleViewController is hardcoded so I want to make it dynamic and take input from user in which class user wants to convert?
First let's get some terms right. When you add as? followed by a Type after a variable, it means you are Type Casting (casting for short) the variable into the Type. Basically you are telling the compiler that you want to handle the object as the type you are casting to. Casting only works if the object is actually the type or the type family you are casting to. You can not cast to unrelated types. There are two forms of casting. The as? form is the conditional form while the as! is the forced form. Because casting can failed, therefore the as? will return the results wrapped in optionals while the as! will crash your app when fail to cast.
There is no way to cast an assignment to a type defined in runtime (dynamic as you have put it) for Swift. The type needs to be defined at compile time. However, there are ways to use type erasure to not care about the exact type during assignment.
Cast as AnyObject. By casting as AnyObject, you're wrapping the object with the type AnyObject (similar to optionals). However when you want to use the object within, you'll need to cast the AnyObject type back to the actual type of the object to use it. Unless the code you are writing is for storage or transporting of these objects, it is not very useful otherwise.
Cast as parent class. Cast to parent class type of all possible class you'll be assigning to the variable. The downside is that the object you are trying to use must be in a class hierarchy and the cast need to use the parent to all that may be assigned. For example. Class A is the parents of Class B and Class C. Class B is the parents of Class D. If you case using Class A, the assignment of A, B, C, or D, will succeed but if you cast as Class C, Class D will fail to be cast as Class C. Therefore, it's only useful to you if the objects you will ever need to cast is the child or grand child of the class you are casting to.
Cast as Protocol. This is similar to #2 except all the object you try to cast must implement the protocol. You can always use extension to add protocol to any class in Swift but you will need to do that before you can cast that class to a particular protocol.
For further information, please read Apple's documentation on Type Casting here.
I'm finding that the following code does not work, but I don't exactly understand why.
Say I have a class name saved in a string. I want to cast a view controller as the class that this string refers to.
let controller = self.navigationController as! NSClassFromString("MyUIViewController")
Swift doesn't seem to understand this - I get this error:
Undeclared use of NSClassFromString.
Or the error:
Consecutive statements must be separated by `,`
Can anyone explain why this is the case? I can't cast (using as?) a type based on some variable?
Thanks
No, you cannot cast to a runtime type object. You must cast to a compile-time type. This is why we write x as Int, not x as Int.self: Int is a type, and Int.self is an object that represents that type at runtime.
What would it mean to cast to NSClassFromString("MyUIViewController")? Now you have a variable, controller, whose value is some type that the compiler knows nothing about, so the compiler cannot let you do anything with controller. You can't call methods or access properties on it, because the compiler doesn't know what methods or properties it has. You can't pass it as an argument to a function, because the compiler doesn't know whether it is the right type for that argument.
If you edit your question to explain what you want to do with controller (what methods you want to call on it or what properties you want to access or what functions you want to pass it to), then I will revise my answer to address your goal.
In Swift we are able to write following construction:
class SomeClass {}
let metaMetatype: SomeClass.Type.Type = SomeClass.Type.self
Here metaMetatype does not conform to type AnyObject (SomeClass.Type does). Construction can be even longer, as long as we wish:
let uberMetatype: SomeClass.Type.Type.Type.Type.Type.Type.Type.Type.Type.Type = SomeClass.Type.Type.Type.Type.Type.Type.Type.Type.Type.self
Are this constructions have any sense? If SomeClass.Type.Type not an object, what is this, and why we able to declare it?
If SomeClass.Type.Type not an object, what is this and why we able to declare it?
I will try to dissect what you're asking.
SomeClass.Type.Type is a Metatype of a Metatype. Metatypes exist in Swift because Swift has types that are not classes. This is most similar to the Metaclass concept in Objective-C.
Lexicon.rst in the Swift Open Source Repo has a pretty good explanation:
metatype
The type of a value representing a type. Greg Parker has a good
explanation of Objective-C's "metaclasses" because Swift has types
that are not classes, a more general term is used.
We also sometimes refer to a value representing a type as a "metatype
object" or just "metatype", usually within low-level contexts like IRGen
and LLDB. This is technically incorrect (it's just a "type object"), but
the malapropism happened early in the project and has stuck around.
Why are we able to declare a type of a type of a type... and so on? Because it's a feature of the language called type metadata:
type metadata
The runtime representation of a type, and everything you can do with it.
Like a Class in Objective-C, but for any type.
Note that you can't do something like NSObject().class in Swift because class is a reserved keyword for the creation of a class. This is how you would get the type (or class in this case) of an NSObject in Swift:
let nsObj = NSObject()
nsObj.classForCoder // NSObject.Type
nsObj.classForKeyedArchiver // NSObject.Type
nsObj.dynamicType // NSObject.Type
Note that nsObj and nsObj.self are identical and represent the instance of that NSObject.
I don't see where in the Swift module or open source repo where types allow for .Type, but I'm still looking. It might have to do with the inheritance from SwiftObject, the Objective-C object all Swift classes inherit from (at least on Mac).
Type of a class is also represented in memory (it has for example their own methods). It's represented by singleton representing the Type. (It's not an instance of this type - that's something different). If you call self on a Type like this SomeClass.self you will take singleton instance representing the SomeClass Type.
For more info check this answer
I am having trouble understanding with some of the code snippets about this part of the Java tutorial: http://docs.oracle.com/javase/tutorial/java/IandI/interfaceAsType.html
public Object findLargest(Object object1, Object object2) {
Relatable obj1 = (Relatable)object1;
Relatable obj2 = (Relatable)object2;
if ((obj1).isLargerThan(obj2) > 0)
return object1;
else
return object2;
}
and:
public interface Relatable {
// this (object calling isLargerThan)
// and other must be instances of
// the same class returns 1, 0, -1
// if this is greater than,
// equal to, or less than other
public int isLargerThan(Relatable other);
}
In the first example, why am I downcasting Object types into Relatable types? What happens if the first method doesn't include the first two statements?
Let's say I wrote a Rectangle class that implements the Relatable interface and has the "findLargest" method. If I know that I'm comparing two Rectangle objects, why not just make the first method downcast the objects into Rectangles instead?
You cast the Objects into Relatable types because otherwise you cannot use the methods declared in the Relatable interface. Since Object does not have the isLargerThan method, you would get a compiler error without casting. Honestly, in my opinion the findLargest method as shown here was not very well designed; a better illustration of the purpose of Interfaces would be to ask for Relatable objects as the parameters like so:
public Object findLargest(Relatable object1, Relatable object2) {
//implementation not shown to save space
}
This way, the user must pass Relatable objects, but they can pass any object whose class implements Relatable (such as Rectangle)
"If I know that I'm comparing two Rectangle objects..."True, if you know that you are comparing two Rectangle objects, there is little use for an interface, but the purpose of interfaces is to allow you to create a generic "type" of object that can be used to define common features of several different classes.For example, what if you also had a Circle class and a Square class (both of which implemented Relatable)? In this case, you do not necessarily know the exact type of object you have, but you would know that it is Relatable, so it would be best to cast to type Relatable and use the isLargerThan method in a case like this.
Interfaces define a set of methods which every class which the interface implements has to implement. The downcast is necessary to get access to these methods.
You don't know if you are comparing rectangles with this interface. You could get any Relatble passed. This is one of the cases generics come in handy.
1.In the first example, why am I down casting Object types into Relatable types? What happens if the first method doesn't include the first two statements?
Answer
Every object has some basic functionality and you want a specific object write now. You are down casting your object into a "Relatable" so you can use the "isLargerThan" method(an object wont have it since it has only basic common stuff).
If you didn't down cast, you would not pass compilation.
2.Let's say I wrote a Rectangle class that implements the Relatable interface and has the "findLargest" method. If I know that I'm comparing two Rectangle objects, why not just make the first method downcast the objects into Rectangles instead?
Answer
Since you want to create something generic.
Lets say you have a Student and a Driver. Both of them are People. You can create an interface called IPeople and make both the Student and the driver implement it.
IPeople will have a method called "getAge()" that each of them will implement.
IPeople will have all the functionality that you need for "People". That's how you create cross object functionality under the "same hat".
What I want to do is:
- (UIView *)getView:(UIView *)recycledView withClass:(Class)myClass
{
myClass *currentItem = (myClass*)recycledView;
....
}
I'm calling this function as follows:
[self getView:myView withClass:[SpecialView class]];
Getting a compilation error, any ideas if it's possible to achieve this?
Casting is a compilation only operation. You can't cast at runtime. At runtime, you can use isKindOfClass: to determine class.
In general, the need for dynamic casting indicates a design problem in your code. Specifically, you aren't leveraging either inheritance or polymorphism correctly.
For this case, you might add:
+ (UIView*)recyleView:(UIView*)recycledView;
As a method to all of your SpecialView classes (or it might be abstracted).
Sorry, you can't do it. The best you can do is cast to the declared type of myClass. Casts do not modify the objects, they simply declare the known (after checking) type of the existing object.
And there is no advantage to casting to a dynamic type, since all the compiler and JVM checks that occur based on the cast are static.
A cast happens during compilation, so attempting to cast to a type that's determined at run time (as in an Objective-C method call) is impossible.