I want to create a class, so that the it's subclasses after calling a function a, will receive a new object of the type Self. I'm insuring, that the subclasses will have the init() method.
In a way I want to clone the object, but actually it's more than that, since I want to create a clone with modified values of the original, so I don't really want to use swifty copy constructor syntax
Why it doesn't work? Definitely this:
func myCustomCopy(modificationCommand: Command) -> Test {
let newInt = modificationCommand.execute(self.myInt)
return Test(newInt: newInt)
}
is not what I want.
Example:
protocol Testable {
var myInt: Int { get set }
init(newInt: Int)
}
class Test: Testable {
var myInt = 10
required init(newInt: Int) { myInt = newInt }
func myCustomCopy(modificationCommand: Command) -> Self {
let newInt = modificationCommand.execute(self.myInt)
return self.init(newInt: newInt)
}
}
You may use the (dynamically typed) metatype returned by type(of:) to access an initializer of the concrete type of the metatype. Quoting the Language Reference - Metatypes
Use an initializer expression to construct an instance of a type from
that type’s metatype value. For class instances, the initializer
that’s called must be marked with the required keyword or the entire
class marked with the final keyword.
So in your case, you could use the metatype of self to call a required initializer of the concrete type of self, e.g.
func myCustomCopy() -> Self {
return type(of: self).init()
}
Note that, as specified in the quote above, since you are working with a non-final class, the initializer must be a required one.
Related
I am trying to understand : "self, dynamicType, Type". I have this code :
class SomeClass {}
let cls : SomeClass.Type = SomeClass.self
let cls2 : SomeClass = SomeClass()
Are cls and cls2 the same thing ?
Can someone give some detail about the differences ? Thanks
No, cls and cls2 are different things. The easiest way to understand the difference will be to extend your example like this:
class SomeClass {
class func doIt() {
print("I'm a class method. I belong to my type.")
}
func doItOnlyIfInstanceOfThisType() {
print("I'm a instance method. I belong to my type instance.")
}
}
And now let's take your cls:
let cls : SomeClass.Type = SomeClass.self
cls.doIt()
That will print I'm a class method. I belong to my type.. But you cannot invoke this:
cls.doItOnlyIfInstanceOfThisType() // causes a compilation error, PRO TIP: actually you can use this method as a func property, but I'll add the explanation for this later
Let's take your cls2. The only visible method of it is doItOnlyIfInstanceOfThisType because it's an instance method (of this type).
let cls2 : SomeClass = SomeClass()
cls2.doItOnlyIfInstanceOfThisType()
So the difference between them is that cls is a type and cls2 is an instance of this type.
A little bit more knowledge about why SomeClass.self and SomeClass()?
The type of a class also exists in memory (it has for example its own methods), as a singleton representing the Type (not an instance of this type - that's something different).
If you call self on a Type like this SomeClass.self you will get a singleton instance representing the SomeClass Type.
SomeClass() invokes the init() method of SomeClass, a constructor that creates an instance of SomeClass.
PRO Tip
You can manipulate a Type instance function (like closures/blocks in ObjC). It's a generated class method. But you must pass an instance of the type that you take this method from as an argument, like this:
let myFunc :()->() = cls.doItOnlyIfInstanceOfThisType(cls2)
myFunc()
A metatype type refers to the type of any type, including class types, structure types, enumeration types, and protocol types.
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 dynamicType expression with an instance of a type to access that instance’s dynamic, runtime type as a value, as the following example shows:
class SomeBaseClass {
class func printClassName() {
print("SomeBaseClass")
}
}
class SomeSubClass: SomeBaseClass {
override class func printClassName() {
print("SomeSubClass")
}
}
let someInstance: SomeBaseClass = SomeSubClass()
someInstance.dynamicType.printClassName()
// prints "SomeSubClass"
The compile-time type of someInstance is SomeBaseClass,
the runtime type of someInstance is SomeSubClass
You can use the identity operators (=== and !==) to test whether an instance’s runtime type is the same as its compile-time type.
if someInstance.dynamicType === SomeBaseClass.self {
print("The dynamic type of someInstance is SomeBaseCass")
} else {
print("The dynamic type of someInstance isn't SomeBaseClass")
}
More detail -> The Swift Programming Language: Types
Swift 3.0:
.dynamicType is deprecated, you should use type(of:) to get its meta type:
type(of: someInstance).printClassName()
Protocols in Swift can declare the init() method in their definition. However, I can't think of any use case where this solves any problem other than forcing the conforming classes to define the init() as in the protocol. We can call the declared methods on the protocol type but init on protocol cannot be used to instantiate its object, which is its only purpose.
What problem does declaring init() method in a protocol solve?
I think the real utility comes when it's used as a constraint in a generic class o function. This is real code from one of my projects.
I declare a protocol with a init:
protocol JSONCreatable {
init(fromJson json: JSON)
}
Then, in a generic function where I return a class that conforms to that protocol:
import SwiftyJSON
extension JSON {
func asObject<T>() -> T? where T: JSONCreatable {
if isEmpty {
return nil
}
return T(fromJson: self)
}
func asArray<T>() -> [T] where T: JSONCreatable {
return array?.map{ json in T(fromJson: json) } ?? []
}
}
This allows me to do things like this:
let user: User = json["user"].asObject()
let results: [Element] = json["elements"].asArray()
It forces class to have init(data: data) from some data, example:
protocol JSONable {
init(data: JSON)
}
forces all classes, that are JSONable to have an initialiser from JSON, so you are always sure, that you can create an instance from JSON.
It's commonly used in order to allow for protocol extensions and generic placeholders constrained to protocols to call the initialiser on the given concrete type that conforms to the protocol. For example, consider RangeReplaceableCollection's default implementation of init<S : Sequence>(_ elements: S):
extension RangeReplaceableCollection {
// ...
/// Creates a new instance of a collection containing the elements of a
/// sequence.
///
/// - Parameter elements: The sequence of elements for the new collection.
public init<S : Sequence>(_ elements: S) where S.Iterator.Element == Iterator.Element {
self.init()
append(contentsOf: elements)
}
// ...
}
Without init() being defined as a protocol requirement of RangeReplaceableCollection, there's no way for the extension to know that we can call init() in order to create a new instance of the conforming type.
But it can also be used directly outside of generics and extensions – for example, it can be used to construct a new instance represented by a given existential metatype (the metatype of 'some concrete type that conforms to a protocol'):
protocol P {
init()
}
struct S : P {
init() {}
}
let s: P = S()
let s1 = type(of: s).init() // creates a new instance of S, statically typed as P.
In this example:
type(of: s) returns the dynamic type of s as P.Type (an existential metatype), as s is statically typed as P. Remember that type(of:) is a (T) -> T.Type operation.
init() constructs a new instance of the underlying concrete type, in this case S.
The new instance is statically typed as P (i.e boxed in an existential container).
I would like to have a class with static initialization method:
class A {
required init() {
}
// this one works
class func f0() -> Self {
return self.init()
}
// this one works as well
class func f1() -> Self {
let create = { self.init() } // no error, inferred closure type is '() -> Self'
return create()
}
}
Unfortunately, Swift 3 compiler is unable to infer type for any closure more complex than { self.init() }. For example:
class func f2() -> Self {
let create = {
// error: unable to infer complex closure return type; add explicit type to disambiguate
let a = self.init()
return a
}
return create()
}
Any attempt to specify closure type, variable type explicitly or cast from A to Self leads to an error:
class func f3() -> Self {
let create = { () -> Self in // error: 'Self' is only available in a protocol or as the result of a method in a class;
let a = self.init()
return a
}
return create()
}
class func f4() -> Self {
let create = {
let a: Self = self.init() // error: 'Self' is only available in a protocol or as the result of a method in a class;
return a
}
return create()
}
class func f5() -> Self {
let create = { () -> A in
let a = self.init()
return a
}
return create() as! Self // error: cannot convert return expression of type 'A' to return type 'Self'
}
The solution is to avoid closures using Self.
This seems like a very unfortunate limitation of the compiler. Is there a reason behind it? Is this issue likely to be fixed in future Swift versions?
The fundamental problem is that Swift needs to determine the type of Self at compile time, but you want to determine it at runtime. It has been somewhat expanded to allow class functions to return Self if everything can be resolved at compile time, but Swift can't always prove that your types must be correct in some of these cases (sometimes because it doesn't know how yet, and sometimes because it's actually possible to be wrong).
As an example, consider a subclass that doesn't override a Self-returning method. How can it return the subclass? What if it passes Self to something else? How can you statically type check that at compile time given future subclasses the compiler doesn't even know about? (Including subclasses that can be added at runtime and across module boundaries.)
I expect this to get a little better, but Swift discourages this kind of complex inheritance (these are non-final classes, so you must consider all the possible subclasses) and prefers protocols long-term, so I wouldn't expect this to be fully possible in Swift 4 or 5.
I have a basic generic class:
class SharedClass<T> {}
And a builder for it:
class SharedClassBuilder {
func build<T>() -> SharedClass<T>? {
return ...
}
}
What I want to be able to do, is return an instance that inherits SharedClass, and conforms to T. For example:
protocol MyObject {
func doIt()
}
var result: SharedClass<MyObject>? = SharedClassBuilder().build()
result?.doIt()
Unfortunately, the Swift compiler complains that the returned type does not have a member named doIt.
Is there a way to achieve what I'm looking for?
I suspect it's not so much that you want the returned class to be constrained by the generic type, as you're asking the returned class to be an instance of the constrained type. In your snippet, you're expecting the unwrapped result to conform to MyObject. Taking this a step further, it means that the conformance of SharedClass is determined entirely from how it was constructed. As far as I know this isn't supported in Swift.
However, there's nothing stopping you having a member of SharedClass that is a T. Something along the lines of:
class SharedClass<T> {
var v : T?
}
class SharedClassBuilder {
func build<T>() -> SharedClass<T>? {
return SharedClass()
}
}
protocol MyObject {
func doIt()
}
var result: SharedClass<MyObject>? = SharedClassBuilder().build()
result?.v?.doIt()
I am trying to understand : "self, dynamicType, Type". I have this code :
class SomeClass {}
let cls : SomeClass.Type = SomeClass.self
let cls2 : SomeClass = SomeClass()
Are cls and cls2 the same thing ?
Can someone give some detail about the differences ? Thanks
No, cls and cls2 are different things. The easiest way to understand the difference will be to extend your example like this:
class SomeClass {
class func doIt() {
print("I'm a class method. I belong to my type.")
}
func doItOnlyIfInstanceOfThisType() {
print("I'm a instance method. I belong to my type instance.")
}
}
And now let's take your cls:
let cls : SomeClass.Type = SomeClass.self
cls.doIt()
That will print I'm a class method. I belong to my type.. But you cannot invoke this:
cls.doItOnlyIfInstanceOfThisType() // causes a compilation error, PRO TIP: actually you can use this method as a func property, but I'll add the explanation for this later
Let's take your cls2. The only visible method of it is doItOnlyIfInstanceOfThisType because it's an instance method (of this type).
let cls2 : SomeClass = SomeClass()
cls2.doItOnlyIfInstanceOfThisType()
So the difference between them is that cls is a type and cls2 is an instance of this type.
A little bit more knowledge about why SomeClass.self and SomeClass()?
The type of a class also exists in memory (it has for example its own methods), as a singleton representing the Type (not an instance of this type - that's something different).
If you call self on a Type like this SomeClass.self you will get a singleton instance representing the SomeClass Type.
SomeClass() invokes the init() method of SomeClass, a constructor that creates an instance of SomeClass.
PRO Tip
You can manipulate a Type instance function (like closures/blocks in ObjC). It's a generated class method. But you must pass an instance of the type that you take this method from as an argument, like this:
let myFunc :()->() = cls.doItOnlyIfInstanceOfThisType(cls2)
myFunc()
A metatype type refers to the type of any type, including class types, structure types, enumeration types, and protocol types.
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 dynamicType expression with an instance of a type to access that instance’s dynamic, runtime type as a value, as the following example shows:
class SomeBaseClass {
class func printClassName() {
print("SomeBaseClass")
}
}
class SomeSubClass: SomeBaseClass {
override class func printClassName() {
print("SomeSubClass")
}
}
let someInstance: SomeBaseClass = SomeSubClass()
someInstance.dynamicType.printClassName()
// prints "SomeSubClass"
The compile-time type of someInstance is SomeBaseClass,
the runtime type of someInstance is SomeSubClass
You can use the identity operators (=== and !==) to test whether an instance’s runtime type is the same as its compile-time type.
if someInstance.dynamicType === SomeBaseClass.self {
print("The dynamic type of someInstance is SomeBaseCass")
} else {
print("The dynamic type of someInstance isn't SomeBaseClass")
}
More detail -> The Swift Programming Language: Types
Swift 3.0:
.dynamicType is deprecated, you should use type(of:) to get its meta type:
type(of: someInstance).printClassName()