How to avoid using A.self? - swift

Take this code:
protocol P: class {
static var hello: String { get }
}
class A: P {
class var hello: String {
return "Hello"
}
}
class B: A {
override static var hello: String {
return "Hello World"
}
}
class C: A {}
class D: C {
override static var hello: String {
return "Hello D"
}
}
func sayHello(elements: P.Type...) {
for p in elements {
print(p.hello)
}
}
func sayHelloAgain(elements: A.Type...) {
for p in elements {
print(p.hello)
}
}
func sayHelloThe3rd(elements: [A.Type]) {
for p in elements {
print(p.hello)
}
}
sayHello(A.self, B.self, C.self)
sayHelloAgain(A.self, B.self, C.self)
Compare it to this (taken from this presentation)
func register<T: UITableViewCell where T: ReusableView, T: NibLoadableView>(_: T.Type) { ... }
tableView.register(FoodTableViewCell)
Why do I have to use A.self in one case, but not in the other?
And also, don't need to use .self when calling with one argument.
sayHello(A)
sayHello(A, B) //doesn't compile

The .self is syntactic salt. It's not necessary from a technical perspective, but it exists to cause errors in code that's often a result of a typo, such as:
struct Foo { }
let foo = Foo
This code will give you a compiler error, telling you that either you need to complete the initializer/function/method call, or append .self if you meant to refer to the type.
In the latter example, the context deals exclusively with types and not values, so there's no chance of confusing one with the other, thus, .self isn't necessary.
Perhaps there's a way to modify the function declaration in your example so as to not require the .self, but I'm not aware of such a feature. I'd be interested to find out.

Related

How can i pass class as a parameter to a function in Swift?

Let us consider i have two different classes.
class A {
var something = "Hello"
}
class B {
var something = "World"
}
Now
class C {
func request() {
//Call with class A or B it can contain any class. I can call either class A or B depending on condition
update(myClass: A or B)
}
func update(myClass:A or B ) {
print(myClass.something) //Since both class have same varaible var something so this code should work either i pass class A or B through function
}
}
Plz help me achieve this using Swift
You cannot declare a function in Swift that could accept an input argument of several different types, so you cannot declare a type as A or B. However, you don't actually need this to solve your specific problem.
Since you want to access a common property of the two class instances, you should declare that property in a protocol, make both classes conform to that protocol, then make the function take an input argument of the protocol type.
protocol SomethingProtocol {
var something: String { get }
}
class A: SomethingProtocol {
let something = "Hello"
}
class B: SomethingProtocol {
let something = "World"
}
class C {
func request() {
//Call with class A or B it can contain any class. I can call either class A or B depending on condition
update(something: A())
update(something: B())
}
func update(something: SomethingProtocol) {
print(something.something) //Since both class have same varaible var something so this code should work either i pass class A or B through function
}
}
Use a protocol
protocol MyProtocol: class {
var something: String { get set }
}
class A: MyProtocol {
var something = "Hello"
}
class B: MyProtocol {
var something = "world"
}
class C {
func update(myClass:MyProtocol ) {
print(myClass.something) //Since both class have same varaible var something so this code should work either i pass class A or B through function
}
}
usage:
let a = A()
let b = B()
let c = C()
print(c.update(myClass: a))
print(c.update(myClass: b))
Output:
hello
world
Create a protocol that both A and B conforms to and use it as the parameter type in update()
protocol SomeProtocol {
var something: String {get set}
}
func update(_ o: SomeProtocol) {
print(o.something)
}
Let it be known that I think using a protocol is the cleanest option that will best solve your problem.
However, it is possible to use Any to pass any object as a parameter, this will require checking which class you are dealing with inside your update method.
Something like this...
class C {
func update(myClass: Any) {
if let a = myClass as? A {
print(a.something)
}
if let b = myClass as? B {
print(b.something)
}
}
}
This might be neater as a switch - ref
class C {
func update(myClass: Any) {
switch myClass {
case let a as A:
print(a.something)
case let b as B:
print(b.something)
default:
print("not a thing")
}
}
}

Create instance of class based on function argument [duplicate]

This question already has answers here:
Swift language NSClassFromString
(25 answers)
Closed 5 years ago.
Suppose I have three classes:
import Foundation
class A {
init() {
print("A")
}
}
class B {
init() {
print("B")
}
}
class C {
init() {
print("C")
}
}
I want to dinamically pass a string ("A", "B" or "C") as a function argument and then, inside the body of this function, create an instance of the class I passed. Is this possible? How?
I tried this one (and other variants) but with no luck:
func test(c:AnyObject){
let _class = c()
//...
}
test(c:A)
[UPDATE] Maybe the question is no different from the one #Code Different suggests but that question is old and there were so many changes in the language that one should try any suggested solution before finding the one that works as of today
What could work is having a base class, let's call it BaseClass. Classes that needs to be used would inherit from BaseClass.
Then, in your function, you would pass it the desired type.
Here is a code snippet that demonstrates this technique:
class BaseClass { }
class A: BaseClass { ... }
class B: BaseClass { ... }
class C: BaseClass { ... }
func test(type: BaseClass.Type) {
let someObject = type.init()
// You can cast the object if required
}
test(type: A.self) // creates an object of class A
test(type: B.self) // creates an object of class B
Edit: If you really need a string to cast your types, you might consider doing some job prior to calling test. Getting the type in a switch case and then passing it to test should do.
Edit: It would also work with a protocol, as long as it defines the initializers you need, along with every functions that must be exposed:
protocol SomeProtocol: class {
init()
func someFunction()
}
class A {
required init() {
print("A")
}
}
extension A: SomeProtocol {
func someFunction() {
print("Some function of A")
}
}
class B {
required init() {
print("B")
}
}
extension B: SomeProtocol {
func someFunction() {
print("Some function of B")
}
}
class C {
required init() {
print("C")
}
}
extension C: SomeProtocol {
func someFunction() {
print("Some function of C")
}
}
func test(someType: SomeProtocol.Type) {
let someObject: SomeProtocol = someType.init()
someObject.someFunction()
}
test(someType: A.self) // creates an object of class A
test(someType: B.self) // creates an object of class B

Any way to get the calling class on static functions in Swift?

The question is better explained in code:
class A {
class func thefunc() -> String {
/* Can I here know if thefunc was called using
A.thefunc() or
B.thefunc()?
*/
return "A" /* or "B"= */
}
}
class B: A {
}
You can use self in a static method to refer to the type (as compared to the instance for using self in an instance method)
class A {
class func thefunc() -> A.Type {
return self
}
}
class B: A { }
let metaTypeA = A.thefunc() // A.Type
let metaTypeB = B.thefunc() // B.Type
Similarly, you can use runtime introspection, specifically the subjectType property of the Mirror representation of self.
Instance Variables
...
var subjectType: Any.Type
The static type of the subject being reflected.
From the swiftdoc.org reference of Mirror structure.
E.g.:
class A {
class func thefunc() {
print(Mirror(reflecting: self).subjectType)
}
}
class B: A { }
A.thefunc() // A.Type
B.thefunc() // B.Type
Alternatively, if you needn't actually make use of the meta-type (just differ between the "static caller"), you could use the String representation of self.
class A {
class func thefunc() -> String {
return String(self)
}
}
class B: A { }
print(A.thefunc()) // A
print(B.thefunc()) // B

Implementing generic interfaces in Apple's Swift

I have a class with a property which should have as type what in other languages would be called a generic (or template) interface. When I try to mimic this behavior in Swift I cannot get protocols to work with the idea. For example:
protocol P {
typealias T
func returnT() -> T
}
class G<T>: P {
var t: T
init(t: T) {
self.t = t
}
func returnT() -> T {
return t
}
}
class C {
var p: P<Int> // Cannot specialize non-generic type 'P'
init(instanceOfP: P<Int>) { // Cannot specialize non-generic type 'P'
p = instanceOfP
}
func usePsT() -> Int {
return p.returnT() // 'P' does not have a member named 'returnT'
}
}
Errors from the compiler are reported as comments. It seems clear to me that such a situation should not be problematic: but since Swift's protocols cannot be generics (they use this obscure typealias syntax instead) C has no way to know that every class that implements P can be specialized for Int. Is there a Swift-y way to represent this situation correctly? Or is there any known workaround so that I don't have to force or de-generalize the class structure?
The generic isn't really needed in your protocol (use Any) - it's needed in your class G<T>. You could do this...
protocol P {
func returnT() -> Any
}
class G<T>: P {
var t: T
init(t: T) {
self.t = t
}
func returnT() -> Any {
return t
}
}
class C {
var p: P
init(instanceOfP: P) {
p = instanceOfP
}
func usePsT() -> Any {
return p.returnT()
}
}
let gi = G<Int>(t: 7) // {t 7}
let ci = C(instanceOfP: gi) // {{t 7}}
ci.usePsT() // 7
let gs = G<String>(t: "Hello")
let cs = C(instanceOfP: gs)
cs.usePsT() // "Hello"
My solution is not ideal but saves me a lot of complications, still code is readable...
Instead of interfaces I use base class with open empty functions.
Like this:
public class CSTableControllerFilter<Row: CSTableControllerRow, Data> {
open func filter(data: [Row]) -> [Row] { data }
open func onReloadDone(in controller: CSTableController<Row, Data>) {}
}

Satisfy Swift Protocol Methods with Closure Attributes?

I have a protocol with a method. I have thought that methods can be replaced with closures by the same name, but it doesn't seem to work:
protocol Foo {
func bar() // Type: Void -> Void
}
class X: Foo {
func bar() { }
}
class Y: Foo { // Compiler: doesn't conform to protocol Foo
let bar: Void->Void = {}
}
Is there a way to make this work? I want to override the methods behavior for a Test Stub implementation. Currently, I'd have to do this, which I'd like to shorten:
class Z: Foo {
var barClosure: Void -> Void = {}
func bar() {
barClosure()
}
}
let baz = Z()
baz.barClosure = { /* ... */ }
baz.bar() // Calls the closure replacement
Thanks to #Dániel Nagy, I was able to figure out what options I have. The protocol should require a closure. This way, the client code won't change, as closure calls are identical to method calls.
make the property mutable so implementations can decide if they want to lock the value
require a getter only (for the same reason)
initialize the property as immutable (let) in production code
initialize the property as mutable (var) in test code to provide alternate implementations in test cases, like mock observers do
Here's a modified example which works well in a Playground by returning strings:
protocol Foo {
var bar: () -> String { get }
}
class X: Foo {
// cannot be overwritten
let bar: () -> String = { return "default x" }
}
class Y: Foo {
private let _bar: () -> String = { return "default y" }
// Can be overwritten but doesn't have any effect
var bar: () -> String {
get {
return _bar
}
set {
}
}
}
class Z: Foo {
// Can be overwidden
var bar: () -> String = {
return "default z"
}
}
let bax = X()
bax.bar() // => "default x"
// bax.bar = { /* ... */ } // Forbidden
let bay = Y()
bay.bar() // => "default y"
bay.bar = { return "YY" }
bay.bar() // => "default y"
let baz = Z()
baz.bar() // => "default z"
baz.bar = { return "ZZ" }
baz.bar() // => "ZZ"
You declared the protocol to have a function, bar(), but in class Y, you just have a constant instead of a function, this is the problem. But if you want to have something like in class Y, you should change the protocol to:
protocol Foo {
var bar: () -> () {get set}
}
And implement like that:
class Test: Foo {
private var _bar: (() -> ())?
var bar: () -> () {
get {
return {}
}
set {
self._bar = newValue
}
}
}
UPDATED
If you to shorten your class, you can use something like that:
protocol Foo {
var barClosure: Void -> Void {get set}
}
class Z: Foo {
var barClosure: Void -> Void = {
//do here something
}
}
let a = Z()
a.barClosure()
The func keyword does a little bit more magic behind the scenes that you can’t replicate with properties – especially in the case of classes, where functions can be overridden, so vtables need to be built etc.
That said, if you were going to replace methods using closure expressions, you’d need to do more than the code you gave. The equivalent of this:
struct A {
let x: Int
func f() {
println("In f(), x is \(a.x)")
}
}
would be more like this:
struct A {
let x: Int
// returns a function that takes A objects, and
// returns a function that captures them
static let f: (A)->()->() = { a in
{ ()->() in println("In f(), x is \(a.x)") }
}
// equivalent of the dot notation call of f
var f: ()->() {
return A.f(self)
}
}
This replicates how struct methods actually work, and allows you to do all the same things an f method does:
let a = A(x: 5)
// static version of f
let A_f = A.f
// that static version bound to a self:
let f = A_f(a)
f()
// the above is equivalent to:
a.f()
But this still isn’t enough for A to conform to a protocol that requires an f() method.