I'm trying to make a simple game using Swift. The game has different levels, and each level requires the game to behave in slightly different ways. I decided to use a different class for each level, all inherited from a base level class.
This is the base:
import SpriteKit
class LevelBase {
var scene: GameScene! // Seems very dodgy
var blocks = [SKSpriteNode]()
init(scene: GameScene) { // Should this be required init?
self.scene = scene
}
func filterBlock(_ block: SKSpriteNode) {
blocks = blocks.filter() { $0 !== block } // Looks really dodgy to me
}
func update(time: TimeInterval) {
// For override
}
func levelUp() {
// For override
}
func postGenerate() {
// For override
}
}
However, to me, this class seems to be very badly written. I can't find any examples anywhere of functions created in a class just to be overwritten, which makes me think I'm doing something wrong. Should I be using extensions or protocols for optional functions like that? I don't quite understand how they work, so I haven't used any so far.
The second issue is that this class needs to be initialized with the game scene variable, since some levels need it to add or remove sprites. This seems especially dodgy, considering the class is created in the game scene's file.
Surely there's a better way?
I have no experience with SpriteKit, but from a general perspective you should consider to "Favour composition over Inheritance".
You would have one Level class that is not intended for subclassing but can be instantiated with objects or values that have different implementation.
Additionally you should use protocols to define those and you can add default implementation as protocol extensions.
final class Level {
init(levelImplementation: LevelImplementationType) {
self.levelImplementation = levelImplementation
}
let levelImplementation: LevelImplementationType
func navigate() {
levelImplementation.navigate()
}
func update(timeInterval: TimeInterval) {
levelImplementation.update(timeInterval: timeInterval)
}
}
The Level would be instantiated with an object or struct conforming to LevelImplementationType
protocol LevelImplementationType {
func navigate()
func update(timeInterval: TimeInterval)
}
Default implementations can be done via an extension.
extension LevelImplementationType {
func navigate() {
}
func update(timeInterval: TimeInterval) {
}
}
The LevelImpelmenation needs to conform to LevelImplementationType, but don't have any further constraints. i.e. they can have very different initialisers.
struct LevelImplementation1: LevelImplementationType {
// useses default implementation of `navigate` and `update` from extension
}
struct LevelImplementation2: LevelImplementationType {
// useses default implementation of `update` from extension
func navigate() {
}
}
struct LevelFileImplementation: LevelImplementationType {
init(with path: String) {
// read variables from file at path
}
func navigate() {
// navigate as given in file
}
}
Level instances cane be created like
let level1 = Level(levelImplementation: LevelImplementation1())
let level2 = Level(levelImplementation: LevelImplementation2())
let level3 = Level(levelImplementation: LevelFileImplementation(with: "path/to/file"))
Related
I use model view presenter architecture in my app and I wonder what's better for respect solid principles and reusability.
So I have 4 classes: View Controller, Presenter, Model and Service. But I have a doubt in connection between presenter and service. I am not sure if I don't break single responsibility principle.
Presenter:
class WorkoutPresenter() {
// some code
let workoutSettingsService = WorkoutSettingsService()
func changeUnitFromKGtoLBInHistory() {
workoutSettingsService.changeUnitFromKGtoLBInHistory()
}
func changeUnitFromLBtoKGInHistory() {
workoutSettingsService.firstFunction()
}
func changeUnitFromKGtoLBInCalendar() {
workoutSettingsService.secondFunction()
}
}
class WorkoutSettingService {
func firstFunction() {
// some code
}
func secondFunction() {
// some code
}
func thirdFunction() {
// some code
}
}
Now workout service has 3 responsibilities (first, second and third function)
Or maybe better option would be create different class for each function and then call them in WorkoutService, something like:
class WorkoutSettingService {
let firstFunctionClass: FirstFunctionClass
let secondFunctionClass: SecondFunctionClass
let thirdFunction: ThirdFunctionClass
init(firstFunctionClassClass: FirstFunction, secondFunctionClass: SecondFunctionClass, thirdFunctionClass: ThirdFunctionClass) {
self.firstFunctionClass = firstFunction
self.secondFunctionClass = secondFunction
self.thirdFunctionClass = thirdFunction
}
func firstFunctionCall() {
firstFunctionClass.function()
}
func secondFunctionCall() {
secondFunctionClass.function()
}
func thirdFunctionCall() {
thirdFunctionClass.function()
}
}
And then call it in Presenter like before. Or maybe better than accessing to this new three class is create a protocols and set delegates from service to this new specific classes?
I hope you understand what my problem is. If you have other idea how to connect presenter with service in clean way, go ahead.
The cleaner approach in my opinion would be to introduce protocols to your service class and segregate the responsibilities.
To make the example simpler, I am going to assume that func changeUnitFromKGtoLBInHistory() and func changeUnitFromLBtoKGInHistory() have to invoke a service with respect to some history data and the func changeUnitFromKGtoLBInCalendar() has to invoke current calendar data.
First we introduce 2 protocols to do that
protocol InHistoryServiceProtocol {
func firstFunction()
func secondFunction()
}
protocol InCalendatServiceProtocol {
func thirdFunction()
}
Then we update the class WorkoutSettingService to conform to protocol as below:
class WorkoutSettingService: InHistoryServiceProtocol, InCalendatServiceProtocol {
func firstFunction() {
// some code
}
func secondFunction() {
// some code
}
func thirdFunction() {
// some code
}
}
Now we use protocol composition to gracefully handle the service class in the presenter
class WorkoutPresenter {
// some code
typealias WorkoutServiceProtocols = InHistoryServiceProtocol & InCalendatServiceProtocol
let workoutSettingsService: WorkoutServiceProtocols = WorkoutSettingService()
func changeUnitFromKGtoLBInHistory() {
workoutSettingsService.firstFunction()
}
func changeUnitFromLBtoKGInHistory() {
workoutSettingsService.secondFunction()
}
func changeUnitFromKGtoLBInCalendar() {
workoutSettingsService.thirdFunction()
}
}
This way you have the flexibility to add/remove responsibilities in the Work out service class respecting the SOLID principles. It also becomes easy to mock the data and inject into presenter for testing.
I have a protocol Vehicle and its extension like below:
protocol Vehicle {
func Drive()
}
extension Vehicle {
func Stop() {
print("iiiich...")
}
}
And I also have declaration like below for Stop Method
struct Car: Vehicle {
func Drive() {
print("Can Drive")
}
func Stop() {
print("yo stop")
}
}
let myCar = Car()
myCar.Drive()
myCar.Stop()
But its override the Stop Method
// Output
// Can Drive
// yo stop
And as per my requirement I need default method sometime and some time overridden method definition
Hey I got the answers that is to conform the protocol by the object call your default method rather than overriddedn, so we can call both defination as required
let honda: Vehicle = Car()
honda.Drive()
honda.Stop()
// Output
// Can Drive
// iiiich..
When we create a variable without type then this is static dispatch when a object conform a protocol only.
If you need the method declared in the protocol extension, just make the compiler think that the car is of type Vehicle:
let myCar = Car()
(myCar as Vehicle).Stop()
As already mentioned in the answers, the generic solution is to make sure that the instance that calls Stop() method is of type Vehicle (not Car). Nevertheless I would mention what's the logic behind it.
Personally, I think that there is a possibility to face this issue when it comes to work with the POP paradigm. Protocol extensions is a handy way the apply Polymorphism in our code, however it does leads to this "weird" behavior!
Static Dispatch:
Firstly, keep in mind that it is not a bug. In case of:
let honda: Vehicle = Car()
honda.Drive()
honda.Stop()
there is a manual cast to the honda as Vehicle, at this point the compiler will use static dispatch, which means that it would be recognizable which method should be called (Vehicle().Stop or Car().Stop) during the compile time. It selects the default implementation for Vehicle which is implemented in the extension, without the need of checking what is the concrete type.
Dynamic Dispatch:
In case of:
let myCar = Car()
myCar.Drive()
myCar.Stop()
nothing special goes here, it works exactly as expected. That's exactly the the meaning of dynamic dispatch, which leads to apply polymorphic operations during the run time.
To make it more clear, consider that you have another type that conforms to Vehicle protocol:
struct Bus: Vehicle {
func Drive() {
print("Bus Drive")
}
func Stop() {
print("Bus stop")
}
}
let myBus = Bus()
myCar.Drive()
myCar.Stop()
Obviously, the print("Bus stop") is the one which will be called, and actually that's the expected! The compiler is "smart" enough to recognize which method to be selected based on what is the concrete type (Bus().Stop).
Furthermore:
For better understanding of what's going on here, reviewing Understanding Swift Performance Apple session might be helpful.
You need a protocol with a default implementation that allows a struct param, that can do custom behaviors:
import UIKit
struct Car{
//Any properties
func drive(){
print("Yo Drive")
}
func stop(){
print("Yo Stop")
}
}
protocol Vehicle {
func drive(vehicle : Car?)
func stop(vehicle : Car?)
}
extension Vehicle where Self: UIViewController {
func drive(vehicle : Car? = nil) {
if (vehicle != nil){
vehicle?.drive()
}else{
print("drive default behavior")
}
}
func stop(vehicle : Car? = nil) {
if (vehicle != nil){
vehicle?.stop()
}else{
print("stop default behavior")
}
}
}
class ViewController : UIViewController, Vehicle {
func driving() {
drive() //will print drive default behavior
stop() //will print stop default behavior
let car = Car()
drive(vehicle: car) //will print yo drive!
stop(vehicle: car) //will print yo Stop!
}
override func viewDidLoad() {
driving()
}
}
I was previously using a class that could be simplfied down to this:
class Whatever {
var someArray = [Int]()
func unchangingFunction {
print("test")
}
func functionForOverride() {}
}
I was asking of ways to improve this, and I got told to favour composition over inheritance, using something like the following:
protocol Implementation {
func functionForOverride()
}
final class Whatever {
var someArray = [Int]() // How can I access this?
let implementation: Implementation
init(implementation: Implementation) {
self.implementation = implementation
}
func unchangingFunction() {
print("test")
}
func functionForOverride() {
implementation.functionForOverride()
}
}
However, with this, I can't find a way to do anything with the someArray array:
struct Something: Implementation {
func functionForOverride() {
print(someArray) // This cannot work
}
}
With the original code I am able to access and alter someArray however I want, but with this new way, I can't think of an easy solution.
I think we should use a "real" example in order to make things clearer.
Inheritance (and why it's wrong)
We have the following classes
class Robot {
var battery = 0
func charge() {
print("⚡️")
battery += 1
}
}
class Human {
func eat() {
print("🍽")
}
}
class RobotCleaner: Robot {
func clean() {
print("💧")
}
}
class HumanCleaner: Human {
func clean() {
print("💧")
}
}
Code duplication!!!
As you can see the clean() method is duplicated in RobotCleaner and HumanCleaner. Can you find a way (using inheritance) to remove code duplication?
Ok think about that, I'll wait on the next paragraph... :)
...
Oh, here you are! There's no way to fix that with inheritance right? Well, let's see what we can do with composition.
Composition (the classic way)
Let's define the following 3 protocols and related components
protocol Robot {
mutating func charge()
}
struct RobotComponent: Robot {
var battery = 0
mutating func charge() {
print("⚡️")
battery += 1
}
}
protocol Human {
func eat()
}
struct HumanComponent: Human {
func eat() {
print("🍽")
}
}
protocol Cleaner {
func clean()
}
struct CleanerComponent: Cleaner {
func clean() {
print("💧")
}
}
Now we can build any combination of the previous 3 elements
struct RobotCleaner: Robot, Cleaner {
var robotComponent = RobotComponent()
let cleanerComponent = CleanerComponent()
mutating func charge() {
robotComponent.charge()
}
func clean() {
cleanerComponent.clean()
}
}
struct HumanCleaner: Human, Cleaner {
let humanComponent = HumanComponent()
let cleanerComponent = CleanerComponent()
func eat() {
humanComponent.eat()
}
func clean() {
cleanerComponent.clean()
}
}
Protocol Oriented Programming: Composition the Swifty way
Swift offers a very neat way of doing composition.
First of all let's define the following 3 protocols (and related extensions).
protocol Robot {
var battery: Int { get set }
}
extension Robot {
mutating func charge() {
print("⚡️")
battery += 1
}
}
protocol Human { }
extension Human {
func eat() {
print("🍽")
}
}
protocol Cleaner { }
extension Cleaner {
func clean() {
print("💧")
}
}
Now we can create a Type which has any combination of the previous 3 entities. Let's see how.
struct HumanCleaner: Human, Cleaner { }
struct RobotCleaner: Robot, Cleaner {
var battery: Int = 0
}
If 'Implementation' requires 'someArray' to do what it is intended to do, then you should have 'Implementation' require any object conforming to it to also declare 'someArray'
Like this:
protocol Implementation {
var someArray: [Int]
}
And if you know what you want to do with 'someFunction', then you could give a default implementation of it with a protocol extension like so:
extension Implementation {
func someFunction() {
//you can do some stuff with someArray here
}
}
Then when you conform to 'Implementation' you need to declare 'someArray' but not 'someFunction', unless you want to override the default function.
E.g.
class MyClass: Implementation {
var someArray: [Int]!
init() {}
}
Note that MyClass now has access to 'someFunction', which can be freely overridden in your class, and that you can add as many functions as you want to 'Implementation's extension.
Objective-C declares a class function, initialize(), that is run once for each class, before it is used. It is often used as an entry point for exchanging method implementations (swizzling), among other things.
Swift 3.1 deprecates this function with a warning:
Method 'initialize()' defines Objective-C class method 'initialize',
which is not guaranteed to be invoked by Swift and will be disallowed
in future versions
How can this be resolved, while still maintaining the same behaviour and features that I currently implement using the initialize() entry point?
Easy/Simple Solution
A common app entry point is an application delegate's applicationDidFinishLaunching. We could simply add a static function to each class that we want to notify on initialization, and call it from here.
This first solution is simple and easy to understand. For most cases, this is what I'd recommend. Although the next solution provides results that are more similar to the original initialize() function, it also results in slightly longer app start up times. I no longer think
it is worth the effort, performance degradation, or code complexity in most cases. Simple code is good code.
Read on for another option. You may have reason to need it (or perhaps parts of it).
Not So Simple Solution
The first solution doesn't necessarily scale so well. And what if you are building a framework, where you'd like your code to run without anyone needing to call it from the application delegate?
Step One
Define the following Swift code. The purpose is to provide a simple entry point for any class that you would like to imbue with behavior akin to initialize() - this can now be done simply by conforming to SelfAware. It also provides a single function to run this behavior for every conforming class.
protocol SelfAware: class {
static func awake()
}
class NothingToSeeHere {
static func harmlessFunction() {
let typeCount = Int(objc_getClassList(nil, 0))
let types = UnsafeMutablePointer<AnyClass>.allocate(capacity: typeCount)
let autoreleasingTypes = AutoreleasingUnsafeMutablePointer<AnyClass>(types)
objc_getClassList(autoreleasingTypes, Int32(typeCount))
for index in 0 ..< typeCount { (types[index] as? SelfAware.Type)?.awake() }
types.deallocate(capacity: typeCount)
}
}
Step Two
That's all good and well, but we still need a way to actually run the function we defined, i.e. NothingToSeeHere.harmlessFunction(), on application startup. Previously, this answer suggested using the Objective-C code to do this. However, it seems that we can do what we need using only Swift. For macOS or other platforms where UIApplication is not available, a variation of the following will be needed.
extension UIApplication {
private static let runOnce: Void = {
NothingToSeeHere.harmlessFunction()
}()
override open var next: UIResponder? {
// Called before applicationDidFinishLaunching
UIApplication.runOnce
return super.next
}
}
Step Three
We now have an entry point at application startup, and a way to hook into this from classes of your choice. All that is left to do: instead of implementing initialize(), conform to SelfAware and implement the defined method, awake().
My approach is essentially the same as adib's. Here's an example from a desktop application that uses Core Data; the goal here is to register our custom transformer before any code mentions it:
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
override init() {
super.init()
AppDelegate.doInitialize
}
static let doInitialize : Void = {
// set up transformer
ValueTransformer.setValueTransformer(DateToDayOfWeekTransformer(), forName: .DateToDayOfWeekTransformer)
}()
// ...
}
The nice thing is that this works for any class, just as initialize did, provided you cover all your bases — that is, you must implement every initializer. Here's an example of a text view that configures its own appearance proxy once before any instances have a chance to appear onscreen; the example is artificial but the encapsulation is extremely nice:
class CustomTextView : UITextView {
override init(frame: CGRect, textContainer: NSTextContainer?) {
super.init(frame:frame, textContainer: textContainer)
CustomTextView.doInitialize
}
required init?(coder aDecoder: NSCoder) {
super.init(coder:aDecoder)
CustomTextView.doInitialize
}
static let doInitialize : Void = {
CustomTextView.appearance().backgroundColor = .green
}()
}
That demonstrates the advantage of this approach much better than the app delegate does. There is only one app delegate instance, so the problem isn't very interesting; but there can be many CustomTextView instances. Nevertheless, the line CustomTextView.appearance().backgroundColor = .green will be executed only once, as the first instance is created, because it is part of the initializer for a static property. That is very similar to the behavior of the class method initialize.
If you want to fix your Method Swizzling in Pure Swift way:
public protocol SwizzlingInjection: class {
static func inject()
}
class SwizzlingHelper {
private static let doOnce: Any? = {
UILabel.inject()
return nil
}()
static func enableInjection() {
_ = SwizzlingHelper.doOnce
}
}
extension UIApplication {
override open var next: UIResponder? {
// Called before applicationDidFinishLaunching
SwizzlingHelper.enableInjection()
return super.next
}
}
extension UILabel: SwizzlingInjection
{
public static func inject() {
// make sure this isn't a subclass
guard self === UILabel.self else { return }
// Do your own method_exchangeImplementations(originalMethod, swizzledMethod) here
}
}
Since the objc_getClassList is Objective-C and it cannot get the superclass (e.g. UILabel) but all the subclasses only, but for UIKit related swizzling we just want to run it once on the superclass. Just run inject() on each target class instead of for-looping your whole project classes.
A slight addition to #JordanSmith's excellent class which ensures that each awake() is only called once:
protocol SelfAware: class {
static func awake()
}
#objc class NothingToSeeHere: NSObject {
private static let doOnce: Any? = {
_harmlessFunction()
}()
static func harmlessFunction() {
_ = NothingToSeeHere.doOnce
}
private static func _harmlessFunction() {
let typeCount = Int(objc_getClassList(nil, 0))
let types = UnsafeMutablePointer<AnyClass>.allocate(capacity: typeCount)
let autoreleasingTypes = AutoreleasingUnsafeMutablePointer<AnyClass>(types)
objc_getClassList(autoreleasingTypes, Int32(typeCount))
for index in 0 ..< typeCount { (types[index] as? SelfAware.Type)?.awake() }
types.deallocate(capacity: typeCount)
}
}
You can also use static variables since those are already lazy and refer them in your top-level objects' initializers. This would be useful for app extensions and the like which doesn't have an application delegate.
class Foo {
static let classInit : () = {
// do your global initialization here
}()
init() {
// just reference it so that the variable is initialized
Foo.classInit
}
}
If you prefer Pure Swift™! then my solution to this kind of thing is running at _UIApplicationMainPreparations time to kick things off:
#UIApplicationMain
private final class OurAppDelegate: FunctionalApplicationDelegate {
// OurAppDelegate() constructs these at _UIApplicationMainPreparations time
private let allHandlers: [ApplicationDelegateHandler] = [
WindowHandler(),
FeedbackHandler(),
...
Pattern here is I'm avoiding the Massive Application Delegate problem by decomposing UIApplicationDelegate into various protocols that individual handlers can adopt, in case you're wondering. But the important point is that a pure-Swift way to get to work as early as possible is dispatch your +initialize type tasks in the initialization of your #UIApplicationMain class, like the construction of allHandlers here. _UIApplicationMainPreparations time ought to be early enough for pretty much anybody!
Mark your class as #objc
Inherit it from NSObject
Add ObjC category to your class
Implement initialize in category
Example
Swift files:
//MyClass.swift
#objc class MyClass : NSObject
{
}
Objc files:
//MyClass+ObjC.h
#import "MyClass-Swift.h"
#interface MyClass (ObjC)
#end
//MyClass+ObjC.m
#import "MyClass+ObjC.h"
#implement MyClass (ObjC)
+ (void)initialize {
[super initialize];
}
#end
Here is a solution that does work on swift 3.1+
#objc func newViewWillAppear(_ animated: Bool) {
self.newViewWillAppear(animated) //Incase we need to override this method
let viewControllerName = String(describing: type(of: self)).replacingOccurrences(of: "ViewController", with: "", options: .literal, range: nil)
print("VIEW APPEAR", viewControllerName)
}
static func swizzleViewWillAppear() {
//Make sure This isn't a subclass of UIViewController, So that It applies to all UIViewController childs
if self != UIViewController.self {
return
}
let _: () = {
let originalSelector = #selector(UIViewController.viewWillAppear(_:))
let swizzledSelector = #selector(UIViewController.newViewWillAppear(_:))
let originalMethod = class_getInstanceMethod(self, originalSelector)
let swizzledMethod = class_getInstanceMethod(self, swizzledSelector)
method_exchangeImplementations(originalMethod!, swizzledMethod!);
}()
}
Then on AppDelegate:
UIViewController.swizzleViewWillAppear()
Taking from the following post
Init static stored property with closure
[static stored property with closure]
One more example to execute something once using
extension MyClass {
static let shared: MyClass = {
//create an instance and setup it
let myClass = MyClass(parameter: "parameter")
myClass.initialize()//setup
return myClass
}()
//() to execute the closure.
func initialize() {
//is called once
}
}
//using
let myClass = MyClass.shared
I think that is a workaround way.
Also we can write initialize() function in objective-c code, then use it by bridge reference
Hope the best way.....
This question already has an answer here:
Implement protocol through extension [duplicate]
(1 answer)
Closed 6 years ago.
I'm trying to override an instance method from a protocol extension, and I'm having some trouble.
For context, I'm making an iOS app with a lot of different UICollectionViews. These views get data from different databases (requiring different callback funcs) and have very different layouts. Because any combination of (database, layout) is possible, it's difficult to make a nice OOP class hierarchy without massive code duplication.
I had the idea to put the layout functions (mostly those defined in the UICollectionViewDelegateFlowLayout protocol) into protocol extensions, so I can decorate a given UICollectionView subclass with a protocol that's extended to implement all relevant layout functions, but I'm having a hard time of it. The essence of the problem is contained in the code below.
class Base {
func speak(){
print("Base")
}
}
class SubA: Base, ProtocolA {}
class SubB: Base, MyProtocolB {}
protocol MyProtocolA{
func speak()
}
protocol MyProtocolB{
func speak()
}
extension MyProtocolA{
func speak(){
print("A")
}
}
extension MyProtocolA{
func speak(){
print("B")
}
}
let suba = SubA()
suba.speak() // prints "Base", I want it to print "A"
let subb = SubB()
subb.speak() // prints "Base", I want it to print "B"
Thoughts?
The default implementations in the protocols are only called if the class that conforms to these protocols do not implement that method itself. The classes' methods override the default implementations of the protocols, not the other way around.
Typically, you'd do something like:
protocol MyProtocolA {
func speak()
}
protocol MyProtocolB {
func speak()
}
extension MyProtocolA {
func speak() {
print("A")
}
}
extension MyProtocolB {
func speak() {
print("B")
}
}
class SubA: MyProtocolA {}
class SubB: MyProtocolB {}
let suba = SubA()
suba.speak() // prints "A"
let subb = SubB()
subb.speak() // prints "B"
But if you do
class SubC: MyProtocolA {
func speak (){
print("C")
}
}
let subc = SubC()
subc.speak() // prints "C"
Frankly, as you look at this, the use of Base is entirely redundant in this example, so I've removed it. Clearly, if you need to subclass from Base for other reasons, feel free. But the key point is that protocol default implementations don't override the classes' implementation, but rather the other way around.