I have a swift class that has about 10 different functions in it. It's over 400 lines of code and needs to be broken up. I want to put some functions in different files. What is the best way to do this? Maybe inheritance?
You can create different files and then put some method in there within extension.
Example:
class MyMessyViewController: UIViewController {
var oneVariable: String = ""
override func viewDidLoad() {
super.viewDidLoad()
anotherFunctionFromThisExtension()
}
func one(){
}
func two(){
}
func three(){
}
}
Then Create a new file and put more functions into this file within an extension.
extension MyMessyViewController {
func anotherFunctionFromThisExtension() {
oneVariable = "I made this change from this File"
print(oneVariable)
}
}
Best practice if you have Delegates, Collection/TableViews in you view controller, you can separate them with extensions, just instead of simple extension MyMessyViewController { } write like extension MyMessyViewController: UICollectionViewDelegate, UICollectionViewDataSource { }
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 function for eg. that I with to have across all views in my app.
How would I go about defining that. Where should the function be written.
read somewhere here that one possible solution is to define the function as a UIViewController extension like so:
extension UIViewController {
func displayAlert(title:String, error:String, buttonText: String) {
...
}
}
where should such a procedure be declared?
Thanks
Create a new Swift file and name it something like:
UIViewController+DisplayAlert.swift
In there is where you can add the code in your question.
extension UIViewController {
func displayAlert(title:String, error:String, buttonText: String) {
...
}
}
Since it is extending UIViewController, you'll be able to access this function on all subclasses of UIViewController.
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"))
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.
I got a struct :
struct ErrorResultType: ErrorType {
var description: String
var code: Int
}
and a protocol:
protocol XProtocol {
func dealError(error: ErrorResultType)
}
Now I want to make an extention of UIViewController:
extension UIViewController: XProtocol {
func dealError(error: ErrorResultType) {
// do something
}
}
So I can subclass from this and override the function like:
class ABCViewController: UIViewController {
--->override func dealError(error: ErrorResultType) {
super.dealError(error)
// do something custom
}
}
But it goes wrong with: Declarations from extensions cannot be overridden yet
It doesn't make any sense to me. When I replace all ErrorResultType with AnyObject, the error won't appear any more.
Anything I missed?
For now the method in the extension must be marked with #objc to allow overriding it in subclasses.
extension UIViewController: XProtocol {
#objc
func dealError(error: ErrorResultType) {
// do something
}
}
But that requires all types in the method signature to be Objective-C compatible which your ErrorResultType is not.
Making your ErrorResultType a class instead of a struct should work though.
If i am not making mistake this is connected with Swift official extension mechanism for adding methods to classes.
Conclusion :
At the moment, it's not possible to override entities declared in
extension by subclassing, like so:
class Base { }
extension Base {
var foo: String { return "foo" }
}
class Sub: Base {
override var foo: String { return "FOO" } // This is an error
}
Please check this resource for more information : https://github.com/ksm/SwiftInFlux/blob/master/README.md#overriding-declarations-from-extensions