Am stuck in a situation where I have a let variable declared & initialized in base class. I would need to pass a different enum in one of my other classes extending this base class.
So, I tried creating a class function in base class so that I can override and return a different enum type. But is there any way that I can access the extended class from base class ?
Created a sample code below to help explain:
class A {
var string: String {
get {
// Is it possible to refer to the class type dynamically here ?
// So that it would call B's printMessage
return A.printMessage("Hello")
}
}
class func printMessage(message: String) -> String {
return "You shall not pass !"
}
}
class B: A {
override class func printMessage(message:String) -> String {
return message + "World !"
}
}
let obj = B()
print(obj.string)
make it like this:
var string: String {
get {
// Is it possible to refer to the class type dynamically here ?
// So that it would call B's printMessage
return self.dynamicType.printMessage("Hello")
}
}
Related
So I'm new to iOS development and have been working on minor changes to an app at my internship that has a relatively large objective-c code base. I've been learning swift from Treehouse(Wow, love them!) and I just learned about protocols. Currently, they should be used in certain instances and the instructor used this example.
Say you have a company with two different types of employees: Salary and Hourly(Pretty common). Now, they both would inherit from a super class called Employee and both would have to call a function called "pay" which would pay the employee. How do you enforce these classes to implement that function? Sure, use a protocol but that would require you to remember to add that to the function declaration. Is there a way to just add the protocol to the super class "Employee" and then whatever inherits from that class would have to follow that protocol that's part of that superclass. Is there another way to do this? Thanks!
What you are looking for is an abstract class. The purpose of an abstract class is to behave as a base class for concrete classes to inherit from, but an abstract class cannot be instantiated directly.
If Employee was an an abstract class then any attempt to actually instantiate an instance of Employee would be reported as an error by the compiler. You would need to instantiate a concrete subclass of Employee, such as SalariedEmployee or HourlyEmployee.
The definition of the Employee class would include that the calculatePay method was required and again a compile time error would occur if a concrete subclass did not implement that method.
Now, the bad news. Neither Objective-C nor Swift supports abstract classes.
You can provide a similar kind of class by providing an implementation of a method that throws an exception if it isn't overridden by a subclass. This gives a runtime error rather than a compile time error.
e.g.
class Employee {
var givenName: String
var surname: String
...
init(givenName: String, surname: String) {
self.givenName = givenName
self.surname = surname
}
func calculatePay() -> Float {
fatalError("Subclasses must override calculatePay")
}
}
class SalariedEmployee: Employee {
var salary: Float
init(givenName: String, surname: String, annualSalary: Float) {
salary = annualSalary
super.init(givenName: givenName, surname: surname)
}
override func calculatePay() -> Float {
return salary/12 // Note: No call to super.calculatePay
}
}
Whether the calculatePay is part of the base class or assigned to the base class through an extension that adds conformance to a protocol, the result is the same;
The Employee class will need a default implementation of the function that generates some sort of error
Failure of a subclass to implement the method will not cause a compile time error
You could assign a protocol, say, Payable to each subclass individually, but then as the protocol was not part of the base class, you couldn't say something like:
var employees[Employee]
for e in employees {
let pay = e.calculatePay()
}
You would have to use the slightly more complicated:
for e in employees {
if e is Payable {
let pay = e.calculatePay()
}
}
Unfortunately abstract functions are not yet supported. A possible workaround is to launch a fatalError when such function is not overridden by a subclass, doing so:
protocol YourProtocol {
func pay()
}
class Employee: YourProtocol {
func pay() {
fatalError("Must Override")
}
}
class SubEmployee: Employee {
func pay() {
print("stuff here")
}
}
My approach to this is to include the delegate as a parameter in the class initializer. See the code below:
protocol ProtocolExample {
func somethingNeedsToHappen()
}
// typical class example with delegate property for the required protocol
class ClassExampleA {
var delegate: ProtocolExample!
init() {
}
func aCriticalMethodWithUpdates() {
delegate.somethingNeedsToHappen()
}
}
// use class example in a view controller. Can easily forget to invoke the delegate and protocol
class MySampleViewControllerA: UIViewController {
var classExampleA : ClassExampleA!
func loadMyData() {
classExampleA = ClassExampleA()
}
}
// an alternative approach for the class is to include the delegate parameter in the initializer.
class ClassExampleB {
var delegate: ProtocolExample!
init(delegateForUpdates: ProtocolExample) {
delegate = delegateForUpdates
}
func doSomething() {
delegate.somethingNeedsToHappen()
}
}
// go to use it and you're reminded that the parameter is required...
class MySampleViewControllerB: UIViewController {
var classExampleB: ClassExampleB!
func loadMyData() {
classExampleB = ClassExampleB() // error: Missing argument for parameter 'delegateForUpdates' in call
}
}
// so to avoid error:
class MySampleViewControllerC: UIViewController {
var classExampleB: ClassExampleB!
func loadMyData() {
classExampleB = ClassExampleB(delegateForUpdates: <#ProtocolExample#>)
}
}
Say I have a class named LivingCreature
And other classes that inherit from it:
Human
Dog
Alien
This is what I'm trying to accomplish:
let valueForLivingCreature = Dictionary<Alien, String>
And access it like so:
let alienValue = livingCreatureForValue[Alien]
But this means the class should conform to Equatable and Hashable, but the class itself, not the class instance.
I've tried various ways of accomplishing this, but no luck.
As a compromise I've came up with is:
typealias IndexingValue = Int
class LivingCreature {
static var indexingValue: IndexingValue = 0
}
And then I can use the class as a key like so:
let livingCreatureForValue = Dictionary<IndexingValue, String>
Access:
let alienValue = livingCreatureForValue[Alien.indexingValue]
But, this way the IndexingValue should be set per class, by hand.
I would like to make a hash from the class itself like so:
class LivingCreature {
static var indexingValue: IndexingValue {
return NSStringFromClass(self).hash
}
}
This is not possible because self is not accessible is static var.
My question is, is there a better way of addressing this kind of issue?
Edit:
#Paulw11 Asked me why not make LivingCreature confirm to Equatable and Hashable,
The reason is I would not be able to access the value by the class type reference.
I would have to alloc an instance every time:
let alienValue = livingCreatureForValue[Alien()]
I do not want to call "Alien()" every time for finding a value.
And the component that uses it, doesn't care about the livingCreature instance, only about the class type.
I assume your are trying something like:
let valueForLivingCreature = Dictionary<LivingCreature.Type, String>
and:
let alienValue = valueForLivingCreature[Alien.self]
Then you can use ObjectIdentifier:
class LivingCreature {
class var classIdentifier: ObjectIdentifier {
return ObjectIdentifier(self)
}
//...
}
class Human: LivingCreature {
//...
}
class Dog: LivingCreature {
//...
}
class Alien: LivingCreature {
//...
}
let valueForLivingCreature: Dictionary<ObjectIdentifier, String> = [
Human.classIdentifier: String(Human),
Dog.classIdentifier: String(Dog),
Alien.classIdentifier: String(Alien),
]
let alienValue = valueForLivingCreature[Alien.classIdentifier] //->"Alien"
But in most use cases when you want to use meta-class as a dictionary key, you can find another way around:
class LivingCreature {
class var classValue: String {
return String(self)
}
//...
}
class Human: LivingCreature {
//...
//Override `classValue` if needed.
}
class Dog: LivingCreature {
//...
}
class Alien: LivingCreature {
//...
}
let alienValue = Alien.classValue //->"Alien"
I've seen some discussions about this problem, but have not read a satisfactory explanation. Can anybody tell me why this does not work?
class Parent<T> {
var data:T
init(data:T) {
self.data = data
}
}
class Child : Parent<Int> {}
let c = Child(data: 4)
The last line gives the error:
'Child' cannot be constructed because it has no accessible initializers
Do I really need to implement the initializer just to call super?
Edit:
To give a bit of context, the real code looks closer to the below. I have an Action class which uses generics, because I have another bit of code which can chain actions together and I want to use Swift's type safety to ensure that actions can be chained. Then I have a bunch of subclasses classes (e.g. CustomAction). I am looking for a way to avoid overriding the init method in each of the subclasses. Or alternatively, I want to understand why that's not possible.
class Action<Input, Output> {
var cachedOutput:Output?
init(cachedOutput:Output?) {
self.cachedOutput = cachedOutput
}
}
protocol CustomInput {}
protocol CustomOutput {}
class CustomAction : Action<CustomInput, CustomOutput> {
}
yes, you really need to override init method ..
class Parent<T> {
var data:T
init(data:T) {
self.data = data
}
}
class Child<T> : Parent<T> {
override init(data: T) {
super.init(data: data)
}
}
let c = Child(data: 4) // Child<Int>
let c2 = Child(data: "alfa") // Child<String>
what are the errors ...
// what is the type T ? it is undeclared!
class Child2: Parent2<T> {}
// how to specialize non-generic type Parent ? how to create it?
// i need an initializer in class Child3 ... Hm ...
class Child3: Parent<Int> {}
// cannot specialize non-generic type 'Parent'
class Child3: Parent<Int> {
override init(data: Int) {
super.init(data: data)
}
}
// So, Child3 must be of the same specialized type as Parent!!
that is terrible, isn't it? so look at my final example !
class Parent<T> {
var data:T
init(data:T) {
self.data = data
}
}
class Child<Double> : Parent<String> {
init(data: Double) {
super.init(data: "\(data)")
}
}
let c = Child(data: 4) // Child<Int> !!!!!
let d = Child(data: true) // Child<Bool> !!!
in your case it works like
class Parent<T> {
var data:T
init(data:T) {
self.data = data
}
}
class Child: Parent<String> {
init(data: Double) {
super.init(data: "\(data)")
}
}
let c = Child(data: 4)
print(c.dynamicType) // Child :-)
This now works in Swift 3. My original example now compiles. There is no mention of this in the Swift 3 Language changes, so I can only assume that this was a bug.
I want to be able to have the classes which have a static property (field) which is either inherited from the base class or "mixed" from a protocol. And every class should have it's own implementation of that property. Is it possible? Preferably, it to be immutable.
class C1 {
static let stProperty = "my prorepty1"
}
class C2 {
static let stProperty = "my prorepty2"
}
It's possible, but it's really hard to make this useful in Swift. How do you plan to refer to this property? Let's start with a super-simple implementation:
protocol SomeProtocol {
static var prop: String { get }
}
class C1: SomeProtocol {
static let prop = "This is One"
}
Great. So now I want a function that uses this:
func useProp(x: SomeProtocol) -> String {
return x.prop
// 'SomeProtocol' does not have a member named 'prop'
}
That doesn't work. x is an instance, but I want the type.
// Accessing members of protocol type value 'SomeProtocol.Type' is unimplemented
func useProp(x: SomeProtocol.Type) -> String {
return x.prop
}
This is probably how it will work some day given the word "unimplemented." But it doesn't work today.
func useProp(x: SomeProtocol) -> String {
// Accessing members of protocol type value 'SomeProtocol.Type' is unimplemented
return x.dynamicType.prop
}
Same thing.
Today, you really have to hang this on the object itself and not use static or class:
protocol SomeProtocol {
var prop: String { get }
}
class C1: SomeProtocol {
let prop = "This is One"
}
func useProp(x: SomeProtocol) -> String {
return x.prop
}
That's not so terrible in many cases, since the value for the class is probably also the value for any given instance of the class. And it's really all we can do today.
Of course your problem might be that you don't have an instance yet and you need this information to build an instance. That's really hard today and you should probably rethink your design. You'll generally have to use some other pattern like a Builder. See Generic Types Collection for more.
Now you also said:
or "mixed" from a protocol
I wouldn't say "mixed" here. If you really mean this like a Ruby "mixin", there is no such thing in Swift today. Swift folks often refer to this feature as "default implementation," and it's not currently possible (though I do expect it to come eventually). The only thing you can do in the protocol is say that the implementor has to provide this method somehow. You can't provide it for them.
Sure you can do that with a protocol:
protocol SomeProtocol {
static var foo: String { get }
}
class One: SomeProtocol {
class var foo: String {
get {
return "This is One"
}
}
}
Btw I agree with Rob Napier below that this is a bit off a oddball feature. I do think there are probably use-cases for it, but I also think those can be better implemented with other language features
protocol P {
class var stProperty: String { get }
}
class C1 {
class var stProperty: String {
return = "my property1"
}
}
class C2 {
class var stProperty: String {
return = "my property2"
}
}
Usage:
C2.prop //"my property2"
If you try:
C2.prop = "new value" //"cannot assign to the result of this expression"
In my application written in Swift, I have the following class structure. Class A has a static method which does some stuff, but in a very simple form it looks like the code below.
class A {
class func create<T: A>() -> T? {
println(NSStringFromClass(T));
return nil;
}
}
Class B is subclassed from class A.
class B : A {
}
Now, when I execute the following code, the println command outputs A instead of B.
var myVar:B? = B.create();
I am not sure what I am doing wrong here, but I would expect it to output B.
When debugging and putting a breakpoint in the create method, the value $swift.type.T is defined as a Builtin.RawPointer MyApp.A instead of B.
Your generic class method on A doesn't make sense to me. Instead I would actually use something like the code below. This way it creates an instance of Self, which is whatever class you call it on. No need for generics in this case.
class A {
required init() {}
class func create() -> Self {
return self()
}
func test() -> String {
return "A"
}
}
class B : A {
override func test() -> String {
return "B"
}
}
let b = B.create() // "{A}" according to the playground, but it is a "B" instance!
b.test() // "B"
Please note that A needs a required initializer because the use of Self. When doing it in playground, the created instance is shown as {A} on the right. This is an error in Xcode I believe, the actual type is correct.
Edit:
I believe the code above isn't what you were looking for exactly, now I do get what you're trying to do. I would suggest not doing that by depending on the actual class name, but using a generic class to create the instances for you:
protocol Entity {
init()
class func entityName() -> String
}
class EntityFactory<T : Entity> {
class func newEntity() -> T? {
var entity: T?
// ... create entity here using T.entityName()
return entity
}
}
class Person : Entity {
required init() {}
class func entityName() -> String {
return "Person"
}
}
let person = EntityFactory<Person>.newEntity()
Think this is a more elegant solution, which moves the responsibility of creating an entity to a separate generic class. This results in code that is maintainable and testable. You can even abstract it out further for i.e. unit testing purposes, but that seems a bit out of scope here.