How to use variable in instantiateViewController in Swift IOS - swift

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.

Related

what's the difference between typing String() and String.self in swift?

I'm kind of stuck trying to understand .self in swift, always I register a custom cell in an collectionView or an tableView I have to register like customCollectionViewCell.self but why not for example customCollectionViewCell() ?
I've tried in the playground to type String.self in a var to see what happens and it give me no errors but when I try to give it a value it give me the following error
Cannot assign value of type 'String' to type String.Type
what does it mean?
Type() is shorthand notation for Type.init(), so String() calls String.init() and hence initialises a String.
On the other hand, String.self returns the meta type of String, which is a type that represents the String type itself rather than any instance of that type. For more information on meta types, see the Metatype Type section of the official Swift language reference.
In your specific example, you need to register a UITableViewCell subclass type rather than an instance of a specific type, hence you need to use YourCellType.self.

Creating a factory method returning generic

I have an abstract class defined this way:
class BaseCoordinator<ResultType>
Other classes inherit from this one eg.
final class AppCoordinator: BaseCoordinator<Void>
final class AuthFlowCoordinator: BaseCoordinator<AuthFlowCoordinationResult>
final class MainFlowCoordinator: BaseCoordinator<Void>
Now I want to create a factory method. I guess it's sugnature should look like:
func makeCoordinator<T>() -> BaseCoordinator<T>
But, of course, I get error like this one:
Cannot convert return expression of type 'AppCoordinator' to return type 'BaseCoordinator<T>'
What Xcode suggests me is to add as! BaseCoordinator<T>, but I hate this force downcasting (and returning ? isn't satisfying me either, as I'm 100% sure I'll have a correct default object), as I want assurance that at least a default Coordinator will be returned.
It feels like I'm missing something, but I really have no clue what is it. Is it actually possible to make such factory method, or is Swift generics limited?
T must have a predefined type at compile time. Therefore you cannot choose T using the implementation of makeCoordinator() by returning different coordinators with different ResultTypes.
In this case, the caller can choose which value he wants to assign to T, potentially breaking the function. For example the following two calls would be perfectly valid:
let coordinator: BaseCoordinator<Void> = makeCoordinator()
let coordinator: BaseCoordinator<[Int: [String]]> = makeCoordinator()
It would not make sense to use [Int: [String]] as a generic type but it is still possible. Depending on the generic type you choose at the function call, the cast may work or not, which is why a force cast will likely lead to a crash.
An optional cast, as suggested by Tom E would fix the potential crash but it would still not resolve this problem.
Therefore you cannot use a factory pattern for this without erasing ResultType to Any using a wrapper type, which would defeat the purpose of generics.
If you want type safety, you have to create a factory method for each subclass of BaseCoordinator you want to instantiate or just call their initializers manually.
You might want to try as? instead of as!. The former yields an optional, i. e. the result will be nil if the cast doesn’t succeed. This way you have a safe cast without the need of forcing anything.

Dynamic casting using result of NSClassFromString("MyUIViewController")

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.

Metatype of Metatype

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

Cast a Class without Directly Knowing it?

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".