How to put different values and keys into a dictionary [duplicate] - ios

I want to create a Dictionary that does not limit the key type (like NSDictionary)
So I tried
var dict = Dictionary<Any, Int>()
and
var dict = Dictionary<AnyObject, Int>()
resulting
error: type 'Any' does not conform to protocol 'Hashable'
var dict = Dictionary<Any, Int>()
^
<REPL>:5:12: error: cannot convert the expression's type '<<error type>>' to type '$T1'
var dict = Dictionary<Any, Int>()
^~~~~~~~~~~~~~~~~~~~~~
OK, I will use Hashable
var dict = Dictionary<Hashable, Int>()
but
error: type 'Hashable' does not conform to protocol 'Equatable'
var dict = Dictionary<Hashable, Int>()
^
Swift.Equatable:2:8: note: '==' requirement refers to 'Self' type
func ==(lhs: Self, rhs: Self) -> Bool
^
Swift.Hashable:1:10: note: type 'Hashable' does not conform to inherited protocol 'Equatable.Protocol'
protocol Hashable : Equatable
^
<REPL>:5:12: error: cannot convert the expression's type '<<error type>>' to type '$T1'
var dict = Dictionary<Hashable, Int>()
^~~~~~~~~~~~~~~~~~~~~~~~~~~
So Hashable inherited from Equatable but it does not conform to Equatable??? I don't understand...
Anyway, keep trying
typealias KeyType = protocol<Hashable, Equatable> // KeyType is both Hashable and Equatable
var dict = Dictionary<KeyType, Int>() // now you happy?
with no luck
error: type 'KeyType' does not conform to protocol 'Equatable'
var dict = Dictionary<KeyType, Int>()
^
Swift.Equatable:2:8: note: '==' requirement refers to 'Self' type
func ==(lhs: Self, rhs: Self) -> Bool
^
Swift.Hashable:1:10: note: type 'KeyType' does not conform to inherited protocol 'Equatable.Protocol'
protocol Hashable : Equatable
^
<REPL>:6:12: error: cannot convert the expression's type '<<error type>>' to type '$T1'
var dict = Dictionary<KeyType, Int>()
^~~~~~~~~~~~~~~~~~~~~~~~~~
I am so lost now, how can I make compiler happy with my code?
I want to use the dictionary like
var dict = Dictionary<Any, Int>()
dict[1] = 2
dict["key"] = 3
dict[SomeEnum.SomeValue] = 4
I know I can use Dictionary<NSObject, Int>, but it is not really what I want.

Swift 3 update
You can now use AnyHashable which is a type-erased hashable value, created exactly for scenarios like this:
var dict = Dictionary<AnyHashable, Int>()

I believe that, as of Swift 1.2, you can use an ObjectIdentifier struct for this. It implements Hashable (and hence Equatable) as well as Comparable. You can use it to wrap any class instance. I'm guessing the implementation uses the wrapped object's underlying address for the hashValue, as well as within the == operator.

I took the liberty of cross-posting / linking to this question on a separate post on the Apple Dev forums and this question is answered here.
Edit
This answer from the above link works in 6.1 and greater:
struct AnyKey: Hashable {
private let underlying: Any
private let hashValueFunc: () -> Int
private let equalityFunc: (Any) -> Bool
init<T: Hashable>(_ key: T) {
underlying = key
// Capture the key's hashability and equatability using closures.
// The Key shares the hash of the underlying value.
hashValueFunc = { key.hashValue }
// The Key is equal to a Key of the same underlying type,
// whose underlying value is "==" to ours.
equalityFunc = {
if let other = $0 as? T {
return key == other
}
return false
}
}
var hashValue: Int { return hashValueFunc() }
}
func ==(x: AnyKey, y: AnyKey) -> Bool {
return x.equalityFunc(y.underlying)
}

Dictionary is struct Dictionary<Key : Hashable, Value>...
Which means that Value could be anything you want, and Key could be any type you want, but Key must conform to Hashable protocol.
You can't create Dictionary<Any, Int>() or Dictionary<AnyObject, Int>(), because Any and AnyObject can't guarantee that such a Key conforms Hashable
You can't create Dictionary<Hashable, Int>(), because Hashable is not a type it is just protocol which is describing needed type.
So Hashable inherited from Equatable but it does not conform to
Equatable??? I don't understand...
But you are wrong in terminology. Original error is
type 'Hashable' does not conform to inherited protocol 'Equatable.Protocol'
That means that Xcode assuming 'Hashable' as some type, but there is no such type. And Xcode treat it as some kind empty type, which obviously does not conform any protocol at all (in this case it does not conform to inherited protocol Equatable)
Something similar happens with KeyType.
A type alias declaration introduces a named alias of an existing type into your program.
You see existing type. protocol<Hashable, Equatable> is not a type it is protocol so Xcode again tells you that type 'KeyType' does not conform to protocol 'Equatable'
You can use Dictionary<NSObject, Int> just, because NSObject conforms Hashable protocol.
Swift is strong typing language and you can't do some things like creating Dictionary that can hold anything in Key. Actually dictionary already supports any can hold anything in Key, which conforms Hashable. But since you should specify particular class you can't do this for native Swift classes, because there is no such master class in Swift like in Objective-C, which conforms air could conform (with a help of extensions) to Hashable
Of course you can use some wrapper like chrisco suggested. But I really can't imagine why you need it. It is great that you have strong typing in Swift so you don't need to worry about types casting as you did in Objective-C

Hashable is just a protocol so you can't specify it directly as a type for the Key value. What you really need is a way of expressing "any type T, such that T implements Hashable. This is handled by type constraints in Swift:
func makeDict<T: Hashable>(arr: T[]) {
let x = Dictionary<T, Int>()
}
This code compiles.
AFAIK, you can only use type constraints on generic functions and classes.

This doesn't exactly answer the question, but has helped me.
The general answer would be implement Hashable for all your types, however that can be hard for Protocols because Hashable extends Equatable and Equatable uses Self which imposes severe limitations on what a protocol can be used for.
Instead implement Printable and then do:
var dict = [String: Int]
dict[key.description] = 3
The implementation of description has to be something like:
var description : String {
return "<TypeName>[\(<Field1>), \(<Field2>), ...]"
}
Not a perfect answer, but the best I have so far :(

This does not answer the OP's question, but is somewhat related, and may hopefully be of use for some situations. Suppose that what you really want to do is this:
public var classTypeToClassNumber = [Any.Type : Int]()
But Swift is telling you "Type 'Any.Type' does not conform to protocol Hashable".
Most of the above answers are about using object instances as a dictionary key, not using the type of the object. (Which is fair enough, that's what the OP was asking about.) It was the answer by Howard Lovatt that led me to a usable solution.
public class ClassNumberVsClassType {
public var classTypeToClassNumber = [String : Int]()
public init() {
classTypeToClassNumber[String(describing: ClassWithStringKey.self)] = 367622
classTypeToClassNumber[String(describing: ClassBasedOnKeyedItemList3.self)] = 367629
classTypeToClassNumber[String(describing: ClassBasedOnKeyedItemList2.self)] = 367626
classTypeToClassNumber[String(describing: ClassWithGuidKey.self)] = 367623
classTypeToClassNumber[String(describing: SimpleStruct.self)] = 367619
classTypeToClassNumber[String(describing: TestData.self)] = 367627
classTypeToClassNumber[String(describing: ETestEnum.self)] = 367617
classTypeToClassNumber[String(describing: ClassBasedOnKeyedItemList0.self)] = 367624
classTypeToClassNumber[String(describing: ClassBasedOnKeyedItemList1.self)] = 367625
classTypeToClassNumber[String(describing: SimpleClass.self)] = 367620
classTypeToClassNumber[String(describing: DerivedClass.self)] = 367621
}
public func findClassNumber(_ theType : Any.Type) -> Int {
var s = String(describing: theType)
if s.hasSuffix(".Type") {
s = s.substring(to: s.index(s.endIndex, offsetBy: -5)) // Remove ".Type"
}
let classNumber = _classTypeToClassNumber[s]
return classNumber != nil ? classNumber! : -1
}
}
EDIT:
If the classes involved are defined in different modules, and may have conflicting class names if you neglect the module name, then substitute "String(reflecting:" for "String(describing:", both when building up the dictionary and when doing the lookup.

You can use the class name as a Hashable, e.g.:
var dict = [String: Int]
dict[object_getClassName("key")] = 3
See How do I print the type or class of a variable in Swift? for how you might get the class name.

Related

Meaning of .type in Swift [duplicate]

What's the difference between metatype .Type and .self in Swift?
Do .self and .Type return a struct?
I understand that .self can be used to check with dynamicType. How do you use .Type?
Here is a quick example:
func printType<T>(of type: T.Type) {
// or you could do "\(T.self)" directly and
// replace `type` parameter with an underscore
print("\(type)")
}
printType(of: Int.self) // this should print Swift.Int
func printInstanceDescription<T>(of instance: T) {
print("\(instance)")
}
printInstanceDescription(of: 42) // this should print 42
Let's say that each entity is represented by two things:
Type: # entitiy name #
Metatype: # entity name # .Type
A metatype type refers to the type of any type, including class types, structure types, enumeration types, and protocol types.
Source.
You can quickly notice that this is recursive and there can by types like (((T.Type).Type).Type) and so on.
.Type returns an instance of a metatype.
There are two ways we can get an instance of a metatype:
Call .self on a concrete type like Int.self which will create a
static metatype instance Int.Type.
Get the dynamic metatype instance from any instance through
type(of: someInstance).
Dangerous area:
struct S {}
protocol P {}
print("\(type(of: S.self))") // S.Type
print("\(type(of: S.Type.self))") // S.Type.Type
print("\(type(of: P.self))") // P.Protocol
print("\(type(of: P.Type.self))") // P.Type.Protocol
.Protocol is yet another metatype which only exisits in context of protocols. That said, there is no way how we can express that we want only P.Type. This prevents all generic algorithms to work with protocol metatypes and can lead to runtime crashes.
For more curious people:
The type(of:) function is actually handled by the compiler because of the inconsistency .Protocol creates.
// This implementation is never used, since calls to `Swift.type(of:)` are
// resolved as a special case by the type checker.
public func type<T, Metatype>(of value: T) -> Metatype { ... }
First and foremost see Apple docs on type(of:)
The functions signature is interesting:
func type<T, Metatype>(of value: T) -> Metatype
Where is it used?
If you are writing/creating a function that accepts a type e.g. UIView.Type, not an instance e.g. UIView()then to you would write T.Type as the type of the parameter. What it expects as a parameter can be: String.self, CustomTableView.self, someOtherClass.self.
But why would a function ever need a type?
Normally a function which requires a type, is a function that instantiates objects for you. I can think of a few examples:
register function from tableview
tableView.register(CustomTableViewCell.self, forCellReuseIdentifier: "CustomTableViewCell")
Notice that you passed CustomTableViewCell.self. If later on you try to dequeue a tableView of type CustomTableViewCell but didn't register CustomTableViewCell type then it would crash because the tableView hasn't dequeued/instantiated any tableviewcells of CustomTableViewCell type.
decode function from JSONDecoder. Example is from the link
struct GroceryProduct: Codable {
var name: String
var points: Int
var description: String?
}
let json = """
{
"name": "Durian",
"points": 600,
"description": "A fruit with a distinctive scent."
}
""".data(using: .utf8)!
let decoder = JSONDecoder()
let product = try decoder.decode(GroceryProduct.self, from: json)
print(product.name)
Notice try decoder.decode(GroceryProduct.self, from: json). Because you passed GroceryProduct.self it knows that it needs to instantiate an object of type GroceryProduct. If it can't then it would throw an error. For more on JSONDecoder see this well written answer
Trying to find a value of a certain class type. Example trying to find a viewController of a certain type among all viewcontrollers of a navigationController:
func popBackTo<T>(type: T.Type, in nav: UINavigationController? = nil, completion: ((T?) -> Void)? = nil) {
let nav = window?.rootViewController as? UINavigationController
guard let nav = nav, let destinationVC = nav.viewControllers.first(where: { $0 is T }) else {
return
}
nav.popToViewController(destinationVC, animated: true)
}
# Example call site:
popBackTo(LoginVC.self)
As an alternate workaround for where types are needed see the following question: Swift can't infer generic type when generic type is being passed through a parameter. The accepted answer offers an intersting alternative.
More about the internals and how it works:
.Type
The metatype of a class, structure, or enumeration type is the name of
that type followed by .Type. The metatype of a protocol type—not the
concrete type that conforms to the protocol at runtime—is the name of
that protocol followed by .Protocol. For example, the metatype of the
class type SomeClass is SomeClass.Type and the metatype of the
protocol SomeProtocol is SomeProtocol.Protocol.
From Apple : metaType Type
Under the hood AnyClass is
typealias AnyClass = AnyObject.Type // which is why you see T.Type
Basically where ever you see AnyClass, Any.Type, AnyObject.Type, its because it's in need of a type. A very very common place we see it is when we want to register a class for our tableView using register func.
func register(_ cellClass: Swift.AnyClass?, forCellReuseIdentifier identifier: String)
If you are confused as to what does 'Swift.' do then above, then see the comments from here
The above could have also been written as:
func register(_ cellClass: AnyObject.Type, forCellReuseIdentifier identifier: String)
.self
You can use the postfix self expression to access a type as a value.
For example, SomeClass.self returns SomeClass itself, not an instance
of SomeClass. And SomeProtocol.self returns SomeProtocol itself, not
an instance of a type that conforms to SomeProtocol at runtime. You
can use a type(of:) expression with an instance of a type to access
that instance’s dynamic, runtime type as a value, as the following
example shows:
From Apple : metaType Type
Playground code:
Easy example
struct Something {
var x = 5
}
let a = Something()
type(of:a) == Something.self // true
Hard example
class BaseClass {
class func printClassName() {
print("BaseClass")
}
}
class SubClass: BaseClass {
override class func printClassName() {
print("SubClass")
}
}
let someInstance: BaseClass = SubClass()
/* | |
compileTime Runtime
| |
To extract, use: .self type(of)
Check the runtime type of someInstance use `type(of:)`: */
print(type(of: someInstance) == SubClass.self) // True
print(type(of: someInstance) == BaseClass.self) // False
/* Check the compile time type of someInstance use `is`: */
print(someInstance is SubClass) // True
print(someInstance is BaseClass) // True
I highly recommend to read Apple documentation on Types. Also see here
They appear in different places syntactically.
In a place syntactically where you have to specify a type, Something.Type is a valid type, corresponding to the type that is the metatype (which is metaclass for classes) of Something. Something.self is not a valid syntax for a type.
In a place syntactically where you have to write an expression, Something.self is a valid expression. It's an expression of type Something.Type, and the value is the thing ("class object" in the case of classes) that represents the type Something. Something.Type is not a valid expression syntax.
This was one of those topics that confused the hell out of me today.
I was writing a generic function:
func foo<T: Protocol>(ofType: T.Type) {
T.bar()
}
And tried calling it as follows:
foo(ofType: ClassImplementingProtocol.Type) // Compiler error
Spent about 30 min researching why it wasn't working. Then I tried this:
foo(ofType: ClassImplementingProtocol.self) // Works
Turns out Xcode's code completion is very bad at showing the difference between meta types and types... From the code completion pop-up it looks like .self and .Type are the same thing:
But the "explain like im 5" of it is, when you have a method parameter of Class.Type, it is expecting an instance of Class.Type.
Class.self returns an instance of Class.Type, whereas Class.Type is referring to Class.Type...
Very unclear if you ask me.
Metatype .Type
Metatype is a type which allows you to access to parts of Class and Struct[About] type(not instance) like initializers class and static[About] properties and methods
let var1: String = HelloWorld
let var2: String.Type = HelloWorld.self
Some experiments:
class SomeClass {
required init() { }
class func foo1() { }
static func foo2() { }
func foo3() { }
}
class SomeSubClass: SomeClass { }
let a1: SomeClass = SomeClass()
let a2: SomeClass = a1
let a3: SomeClass = a1.self
SomeClass.self.foo1() //class func
SomeClass.foo1() //class func
//static. metatype by type(class name) <class_name/structure_name>.self
let c1: SomeClass.Type = SomeClass.self
//dynamic. metatype by instance
let c2: SomeClass.Type = type(of: a1)
//access to type's init, class, static throught Metatype
let d1: SomeClass = c1.self.init()
let d2: SomeClass = c1.init()
//call
c1.foo1() //class func
c1.foo2() //static func
// c1.foo3() //instance func. Instance member 'foo3' cannot be used on type 'SomeClass'
// c1.foo3(SomeClass()) //Expression resolves to an unused function
//Sub
// <class_name>.Type allows to save class and sunclass
var e1: SomeClass.Type = SomeClass.self //class
e1 = SomeSubClass.self //sub class
//Any.Type allows to save class and struct
var e2: Any.Type = SomeClass.self //class
e2 = String.self //struct
//AnyObject.Type allows to save only class
var e3: AnyObject.Type = SomeClass.self //class
e3 = NSString.self //class
get String
let typeString = "\(SomeType.Type)"
func register<T>(instance: T) {
instanceString = String(describing: type(of: instance))
}

Why CustomStringConvertible protocol not working for Int?

public func +<T: CustomStringConvertible>(lhs: T, rhs: T)->String{
return lhs.description+rhs.description
}
let a:String = "A"
let i:Int = 0
print(a+i)
I am overloading '+' operator for CustomStringConvertible types. String and Int both confirms CustomStringConvertible protocol but it gives an error: "binary operator '+' cannot be applied to operands of type 'String' and 'Int' print(a+i)". It working fine when I apply it to 'String'+'NSNumber'.
don't know what is going behind the scene. why it is not working?
The problem is firstly (believe it or not) String doesn't conform to CustomStringConvertible. You'll therefore want to conform it yourself in order for it to return self for description (probably easier than writing another overload to deal with strings independently).
extension String:CustomStringConvertible {
public var description: String {
return self
}
}
Secondly, you need two generic parameters for your + overload, in order to allow it to accept different types for both parameters, while ensuring that both parameters conform to CustomStringConvertible:
public func +<T: CustomStringConvertible, U:CustomStringConvertible>(lhs: T, rhs: U)->String{
return lhs.description+rhs.description
}

Where in Swift is defined that we can use `[]` as Array literal?

I try to find in Swift documentation where it is defined, but I couldn't.
I expect something like following:
typealias [] = Array
typealias [Element] = Array<Element>
typealias [AnyObject] = Array<AnyObject>
So why it is possible to use [] instead of Array as initializer?
Edit depending on answer
I try to do the same with my custom Person class but it doesn't work:
class Person: ArrayLiteralConvertible {
typealias Element
public init(arrayLiteral elements: Self.Element...)
}
let personNames: Person = ["John", "Mark", "Kris"]
It's defined in the Summary of the Grammar, in the definition of array-literal:
array-literal → [ array-literal-items(opt) ]
array-literal-items → array-literal-item ,(opt) | array-literal-item , array-literal-items
array-literal-item → expression
In more "descriptive" text, this particular case is defined in The Swift Programming Language, Collection Types in the section on Arrays:
Creating an Empty Array
You can create an empty array of a certain type using initializer syntax:
var someInts: [Int] = []
print("someInts is of type [Int] with \(someInts.count) items.")
// Prints "someInts is of type [Int] with 0 items."
Note that the type of the someInts variable is inferred to be
[Int] from the type of the initializer.
To your updated question, the correct syntax (circa Swift 5, though your question is from and older version), would be:
class Person: ExpressibleByArrayLiteral {
required public init(arrayLiteral elements: String...) { ... }
}
You can write it a as a literal everything that conforms to literal protocols . Sets as Array conforms to ArrayLiteralConvertible protocol, you can declare a set by using the same array literal sintax and specifing the type to avoid compiler confusion or they still will be inferred as Array:
let set: Set = ["Hello","Bye"]
To conforms array literal protocol you must provide an initializer:
protocol ArrayLiteralConvertible {
typealias Element
init(arrayLiteral elements: Element...)
}
There is a nice post on NSHipster
Documentation define a literal as:
A literal is the source code representation of a value of a type, such
as a number or string.
Where it a literal first defined? I guess it's the duty of the compiler detect them and substitute with the proper type.

Putting two generic Arrays into one Swift Dictionary with Generics

I'm trying to put two different generic types into a collection. In this example there are two arrays, one containing Ints and the other Strings.
let intArray = Array<Int>()
let stringArray = Array<String>()
let dict = [1:intArray, "one": stringArray]
The error reads Type of expression is ambiguous without more context.
So I tried specifying the Dictionary's type
let dict: [Hashable: Any] = [1:intArray, "one": stringArray]
This leads to two errors.
Using 'Hashable' as a concrete type conforming to protocol 'Hashable' is not supported.
Protocol 'Hashable' can only be used as a generic constraint because it has Self or associated type requirements
Adding import Foundation and using NSDictionary as the type works fine.
let dict: NSDictionary = [1:intArray, "one": stringArray]
But this should be possible in pure Swift too without using Foundation. What is the type the Dictionary has to have?
edit: This apparently has more to do with the type of the keys. They have to be of the same type, not just conform to Hashable.
let dict: [Int:Any] = [1:intArray, 2: stringArray]
This works. But is it possible to make the type of the value more precise? [Int:Array<Any>] does not work.
Elaborating on the answer from #RobNapier, here is a similar approach that uses enum for both, keys and values of the dictionary:
enum Key: Equatable, Hashable {
case IntKey(Int)
case StringKey(String)
var hashValue: Int {
switch self {
case .IntKey(let value) : return 0.hashValue ^ value.hashValue
case .StringKey(let value) : return 1.hashValue ^ value.hashValue
}
}
init(_ value: Int) { self = .IntKey(value) }
init(_ value: String) { self = .StringKey(value) }
}
func == (lhs: Key, rhs: Key) -> Bool {
switch (lhs, rhs) {
case (.IntKey(let lhsValue), .IntKey(let rhsValue)) : return lhsValue == rhsValue
case (.StringKey(let lhsValue), .StringKey(let rhsValue)) : return lhsValue == rhsValue
default: return false
}
}
enum Value {
case IntValue(Int)
case StringValue(String)
init(_ value: Int) { self = .IntValue(value) }
init(_ value: String) { self = .StringValue(value) }
}
var dict = [Key: Value]()
dict[Key(1)] = Value("One")
dict[Key(2)] = Value(2)
dict[Key("Three")] = Value("Three")
dict[Key("Four")] = Value(4)
What is the type the Dictionary has to have?
You may try:
let dict: [NSObject: Any] = [1: intArray, "one": stringArray]
The statement let dict: [Hashable: Any] = ... does not compile, because the type of the key of a Dictionary must be a concrete type conforming to Hashable, e.g. Int, String, etc. Hashable is not a concrete type.
The above suggestion works, because 1. NSObject is a concrete type (where you can instantiate objects from), 2. NSObject is a Hashable, and 3. because instances of subclasses of NSObjects will work here as well, and 4. the compiler can initialise NSObject subclasses from string and number literals.
If you don't like NSObject as the type of the key, you may create your own class or struct.
Note that your first attempt let dict = [1:intArray, "one": stringArray] works if you include Foundation; yielding an NSDictionary (so no need to explicitly state this type).
The reason why we can have these kinds of, apparently, generic dictionaries when using Foundation is the implicit type conversion performed (behind the hood) by the compiler when bridging Swift native types to Foundation.
let intArray : [Int] = [10, 20, 30]
let stringArray : [String] = ["foo", "baz", "bar"]
let dict = [1:intArray, "onx": stringArray]
print(dict.dynamicType)
for e in dict {
print(e.dynamicType, e.key.dynamicType, e.value.dynamicType)
}
/* __NSDictionaryI
(AnyObject, AnyObject) __NSCFString _SwiftDeferredNSArray
(AnyObject, AnyObject) __NSCFNumber _SwiftDeferredNSArray */
The keys as well as values in dict above are wrapped in type AnyObject; which can hold only reference (class) type objects; the compiler implicitly performs conversion of value types Int/String to Foundation reference types __NSCFNumber/__NSCFString. This is still an NSDictionary though; e.g. AnyObject itself does not conform to Hashable, so it can't be used as a key in a native Swift dictionary.
If you wish to create Swift-native "generic-key" dictionary, I'd suggest you create a wrapper (say a structure) that conforms to Hashable and that wraps over the underlying (various) key type(s). See e.g. (the somewhat outdated) thread
How to create Dictionary that can hold anything in Key? or all the possible type it capable to hold

How to use AnyClass in Swift Generic class

I need to pass a type in my generic base class.
class SomeBaseClass<T: AnyClass> {
// Implementation Goes here
}
I get the following error:
Inheritance from non-protocol, non-class type 'AnyClass' (aka
'AnyObject.Type')
Ideally I would like to use 'T' to be as a specific type rather than AnyClass, but AnyClass is OK as well.
Thanks
You should use AnyObject if you want the type to be a class.
class SomeBaseClass<T: AnyObject> {
// Implementation Goes here
}
// Legal because UIViewController is a class
let o1 = SomeBaseClass<UIViewController>()
// Illegal (won't compile) because String is a struct
let o2 = SomeBaseClass<String>()
Instead of specifying T needs to be a class, you could instead do:
class SomeBaseClass<T> {
let type: T.Type
init(type: T.Type) {
self.type = type
}
}
If you're planning to be using T.Type a lot it may be worth using a typealias:
class SomeBaseClass<T> {
typealias Type = T.Type
let type: Type
...
}
Some example usage:
let base = SomeBaseClass(type: String.self)
And advantage of this method is T.Type could represent structs and enums, as well as classes.
You can do this trick:
protocol P {}
class C: P {}
class C1<T: P> {}
let c1 = C1<C>()
In this case you wrap you class C with protocol P, then you able to create new generic class C1 where T is your protocol P. That's allow you to create instance of C1 class with generic parameter class C.

Resources