Generic on class that is subclassed - ios

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.

Related

How to make protocol inheritance with strong constraints

I would like to make some abstract protocol with generic types
protocol UseCase {
associatedtype P
associatedtype R
func execute(params: P) async throws -> R
}
Then I would like to make some concrete protocol with some types
protocol TestUseCase: UseCase where P == Int, R == Int { }
And then use it to declare some implementation to use it on another side
class TestUseCaseImpl: TestUseCase {
func execute(params: Int) async throws -> Int {
// some impl
}
}
When I try to use it inside of my view model I got such error:
class ViewModel {
private let testUseCase: TestUseCase // error
init(testUseCase: TestUseCase) { // errror
self.testUseCase = testUseCase
}
}
Protocol 'TestUseCase' can only be used as a generic constraint because it has Self or associated type requirements
To fix such problem I can declare generic ViewModel with some use case type like this:
class ViewModel<UseCase: TestUseCase> {
private let testUseCase: UseCase
init(testUseCase: UseCase) {
self.testUseCase = testUseCase
}
}
Problem around ViewModel - it's possible to have many use cases inside of ViewModel.
How to implement such idea without generic ViewModel?
You need to use the any keyword. This is only supported in Swift >= 5.7.
Note: it is very unlikely that you want a type called ViewModel. Nest type Model inside of View if that's what it is.
class ViewModel {
private let testUseCase: any TestUseCase
init(testUseCase: some TestUseCase) {
self.testUseCase = testUseCase
}
}

Add protocol to super class which will force other classes that inherit from it to implement protocol

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#>)
}
}

Can we access overridden class function from the base class in swift?

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")
}
}

Initialiser Inheritance confusion

I am trying to build some mocking infrastructure, I want to be able to return a stubbed value and count the times the value was accessed. I have something simple like this:
class BasicMock<T> {
var callsCount = 0
private let backing: T
var result: T {
callsCount++
return backing
}
init(result: T) {
self.backing = result
}
}
class MockTimeDefinitionSerialiser: BasicMock<[String: [AnyObject]]>, TimeDefinitionSerialiserProtocol {
func serialiseTravelTime(travelTime: JSSTravelTime) -> [String: AnyObject] {
return result
}
}
However trying to build it:
let mockTimeDefinitionSerialiser = MockTimeDefinitionSerialiser(result: ["": ""])
Emits the error 'MockTimeDefinitionSerialiser' cannot be constructed because it has no accessible initialisers
My interpretation of the Swift docs is that I should automatically inherit the initialiser as I have set all stored properties.
What am I doing wrong?
Please remove any unnecessary code when asking a question. I was able to reduce your problem to this:
class Base<T> {
init(t: T) {}
}
class Sub: Base<Int> {}
Sub(t: 0) // error: 'Sub' cannot be constructed because it has no accessible initialisers
It seems like even though you specified the T in the subclass, the compiler cannot infer what the initialiser uses for T. I couldn't find a way to get the initialiser to be inherited, you'd have to use a workaround:
class Sub: Base<Int> {
override init(t: Int) {
super.init(t: t)
}
}

How to reference a class that follows a protocol in return type of function?

I have a protocol called Social Service, declared as follows:
protocol SocialService: class {
class func testFunc()
}
A class that follows the protocol may look like this:
class Twitter: SocialService {
class func testFunc() {
}
}
I want to have a method which returns a class that follows this protocol, so calling it would look like this:
let socialService = socialServiceForServiceType(serviceType: String)
I'm not sure what I need to put as the return value type of this function. For example, this:
func socialServiceForServiceType(serviceType: String) -> SocialService.Type
doesn't give an error right here, but trying to call it as above, gives an error:
Accessing members of protocol type value 'SocialService.Type' is
unimplemented
EDIT: I don't want an instance of that type, I want a class of that type. So I want a Twitter class, so I can call the class methods from the SocialService protocol on it.
Like the error says, this feature is unimplemented. However...
I don't want an instance of that type, I want a class of that type. So I want a Twitter class, so I can call the class methods from the SocialService protocol on it.
I'm not sure what you think you're getting from avoiding instances like this. Bear in mind classes don’t need to have member variables, and without them are essentially just collection of function pointers – which is what you seem to be looking for.
If you implement a Twitter class that has no properties and that conforms to a protocol, then calling methods on that protocol will dynamically dispatch to the implementations of that instance:
protocol SocialService: class {
func testFunc()
}
class Twitter: SocialService {
func testFunc() {
println("Testing Twitter!")
}
}
func socialServiceForServiceType(serviceType: String) -> SocialService {
return Twitter()
}
let service = socialServiceForServiceType("blah")
// prints "Testing Twitter!"
service.testFunc()
If your concern is that you want to put member variables in the Twitter class, but don’t want the overhead of that for some features, then this probably suggests you want to decompose this functionality into two different classes. Alternatively, if you want a singleton instance (to handle the connectivity for example) then there are other patterns to handle this.
Use simply
func socialServiceForServiceType(serviceType: String) -> SocialService
A protocol can be the return type of a function.
Totally agree with Airspeed Velocity, but I'd like to expand on one of his points:
I'm not sure what you think you're getting from avoiding instances like this. Bear in mind classes don’t need to have member variables, and without them are essentially just collection of function pointers – which is what you seem to be looking for.
I assume you're trying to do something like this:
func socialServiceForServiceType(serviceType: String) -> SocialService.Type
...
let cls = socialServiceForServiceType("twitter")
let conn = cls.connect(user)
Or something like that. You don't need classes to achieve that. You can just return functions.
typealias Connect = User -> Connection
func connectorForServiceType(serviceType: String) -> Connect {
switch serviceType {
case "twitter": return Twitter.Connect
...
}
}
let connect = connectorForServiceType("twitter")
let conn = connect(user)
If you have a whole bundle of functions that you want to package together, just use a struct.
struct ServiceHandlers {
let connect : User -> Connection
let ping : () -> Bool
let name: () -> String
}
func standardPinger(host: String) -> () -> Bool {
return { host in
// perform an ICMP ping and return Bool
}
}
func handlersForServiceType(serviceType: String) -> ServiceHandlers {
switch serviceType {
case "twitter":
return ServiceHandlers(connect: Twitter.connect,
ping: standardPinger("www.twitter.com"),
name: { "Twitter" })
...
}
}
let service = handlersForServiceType("twitter")
let conn = service.connect(user)
In some ways this is duplicative with class methods, but (a) the features you need for class methods aren't implemented, and (b) this is much more flexible. You can return any collection of functions you want; they don't have to all be class methods. It's easier to have default behaviors (which are hard in Swift when you use inheritance). It's easier to extend because you don't necessarily have to extend all the classes (see my use of standardPinger, which is some function I've made up that returns another function; it doesn't have to be a class method).
Breaking free of class/inheritance thinking and just passing around functions can be a major benefit in Swift. Sometimes a struct is better than a protocol.
Use a Factory pattern to achieve the same.
class SocialFactory : NSObject
{
class func socialServiceForServiceType(serviceType: String) -> SocialService?
{
switch serviceType
{
case "Twitter":
return Twitter();
case "Facebook":
return Facebook()
default:
return nil;
}
}
}

Resources