How to secure same inheritance hierarchies e.g. for MVVM - ios

I´ve got a base ViewController and a base ViewModel. The base ViewModel is used by the base ViewController. Also, I´ve got 2 subclasses of ViewControllers and 2 subclasses of ViewModels that need to be used together.
Example:
class BaseViewModel {
func somethingBasic() {}
}
class ConcreteViewModel1: BaseViewModel {
func somethingConcrete1() {}
}
class ConcreteViewModel2: BaseViewModel {
func somethingConcrete2() {}
}
class BaseViewController {
let viewModel: BaseViewModel
init(with viewModel: BaseViewModel) {
self.viewModel = viewModel
}
}
class ConcreteViewController1: BaseViewController {
init(with viewModel: ConcreteViewModel1) {
super.init(with: viewModel)
}
func useViewModel() {
viewModel.somethingBasic()
viewModel.somethingConcrete1() //this does not work
}
}
class ConcreteViewController2: BaseViewController {
init(with viewModel: ConcreteViewModel2) {
super.init(with: viewModel)
}
func useViewModel() {
viewModel.somethingBasic()
viewModel.somethingConcrete2() //this does not work
}
}
The question is: what is the preferred solution to make viewmodel.somethingConcrete1() and viewmodel.somethingConcrete2() work?

Try using Generics for this.
Create init in BaseViewController accepting a generic parameter T constrained to type BaseViewModel, i.e.
class BaseViewController<T: BaseViewModel> {
let viewModel: T
init(with viewModel: T) {
self.viewModel = viewModel
}
}
Now inherit ConcreteViewController1 and ConcreteViewController2 from BaseViewController giving the specific type for generic parameter T, i.e.
class ConcreteViewController1: BaseViewController<ConcreteViewModel1> {
func useViewModel() {
viewModel.somethingBasic()
viewModel.somethingConcrete1()
}
}
class ConcreteViewController2: BaseViewController<ConcreteViewModel2> {
func useViewModel() {
viewModel.somethingBasic()
viewModel.somethingConcrete2()
}
}

I discussed this with a few other colleagues, and we came around with this solution, based on Composition instead of inheritance:
class BaseViewModel {
func somethingBasic() {}
}
class ConcreteViewModel1 {
private let baseViewModel = BaseViewModel()
func somethingConcrete1() {}
func somethingBasic() {
baseViewModel.somethingBasic()
}
}
class ConcreteViewModel2 {
private let baseViewModel = BaseViewModel()
func somethingConcrete2() {}
func somethingBasic() {
baseViewModel.somethingBasic()
}
}
class BaseViewController {}
class ConcreteViewController1 {
private let base = BaseViewController()
private let viewModel: ConcreteViewModel1
init(with viewModel: ConcreteViewModel1) {
self.viewModel = viewModel
}
func useViewModel() {
viewModel.somethingBasic()
viewModel.somethingConcrete1()
}
}
class ConcreteViewController2: BaseViewController {
private let base = BaseViewController()
private let viewModel: ConcreteViewModel2
init(with viewModel: ConcreteViewModel2) {
self.viewModel = viewModel
}
func useViewModel() {
viewModel.somethingBasic()
viewModel.somethingConcrete2()
}
}
With that solution, you get the type safety, you avoid Generics and you don´t need to cast anywhere.

Related

Add a generic delegate to a base class in Swift

Ideally, I want to create a BaseViewController class that takes in a protocol type (of a delegate) and have a weak variable as the delegate. Something like this:
class BaseViewController<Delegate: AnyObject> {
weak var delegate: Delegate?
init(delegate: Delegate) {
self.delegate = delegate
super.init(...)
}
}
And then inherit from a view controller like so:
protocol MyDelegate: AnyObject {
func funcA()
func funcB()
}
class SomeViewController: BaseViewController<MyDelegate> {
func doSomething() {
delegate?.funcA()
}
}
This doesn't work as the compiler complains:
'BaseViewController' requires that 'MyDelegate' be a class type
How can I work this around to achieve what I need?
Thanks in advance :)
Thats because in swift protocols doesn't confirm to them selves, you can't use "MyProtocol" as concrete type confirming to protocol "MyDelegate"
What you can rather do is
protocol MyDelegate: AnyObject {
func funcA()
func funcB()
}
class BaseViewController<Delegate: MyDelegate> {
weak var delegate: Delegate?
init(delegate: Delegate) {
self.delegate = delegate
super.init(...)
//keeping OPs code as is
}
}
class SomeOtherDelegateClass: MyDelegate {
func funcA() {
//some code here
}
func funcB() {
//some code here
}
}
class SomeViewController: BaseViewController<SomeOtherDelegateClass> {
func doSomething() {
self.delegate?.funcA()
}
}
EDIT 1:
As OP mentioned in comment, he is trying to introduce a generic property in BaseViewController that will simply hold a weak reference to any instance whose class is decided/declared by Child classes of BaseViewController using generics, I am simplifying the above answer a bit
Try this
protocol MyDelegate {
func funcA()
func funcB()
}
class BaseViewController<Delegate> where Delegate: AnyObject {
weak var delegate: Delegate?
init(delegate: Delegate) {
self.delegate = delegate
super.init(...)
//keeping OPs code as is
}
}
class SomeOtherDelegateClass: MyDelegate {
func funcA() {
//some code here
}
func funcB() {
//some code here
}
}
class SomeViewController: BaseViewController<SomeOtherDelegateClass> {
func doSomething() {
self.delegate?.funcA()
}
}
protocol MyDelegate2 {
func funcABCD()
}
class SomeOtherDelegateClass2: MyDelegate2 {
func funcABCD() {
//some code here
}
}
class SomeViewController2: BaseViewController<SomeOtherDelegateClass2> {
func doSomething() {
self.delegate?.funcABCD()
}
}
TBH, I really dont see much of benefit of this design! Probably you need to revisit the code structure and see if you can come up with better code structure :)
You should set your delegate as a constraint for the generic type T in BaseViewController:
protocol MyDelegate: AnyObject {
func funcA()
func funcB()
}
class Delegated1: MyDelegate {
func funcA() { print("A1") }
func funcB() {}
}
class Delegated2: MyDelegate {
func funcA() { print("A2") }
func funcB() {}
}
class BaseViewController<T: MyDelegate>: UIViewController {
var delegate: T?
func doSomething() {
delegate?.funcA()
}
}
class SomeViewController1: BaseViewController<Delegated1> {}
class SomeViewController2: BaseViewController<Delegated2> {}
class TestClass {
let viewController1: SomeViewController1 = {
let viewController = SomeViewController1(nibName: nil, bundle: nil)
viewController.delegate = .init()
return viewController
}()
let viewController2: SomeViewController2 = {
let viewController = SomeViewController2(nibName: nil, bundle: nil)
viewController.delegate = .init()
return viewController
}()
// prints:
// A1
// A2
func myFunc() {
viewController1.doSomething()
viewController2.doSomething()
}
}

How can I fix this Conflicting conformance error?

I am trying to create a ProfileCellController that I can use to configure a cell in my UITableView.
As my table can have multiple cell types, I was hoping to use generics to set the type on the cell required and use a configure method to set the props.
This is what I have so far:
import UIKit
public protocol ProfileLoadedView {
func display(_ viewModel: ProfileViewModel)
}
public class SingleLineCell: UITableViewCell { }
public class MultiLineWithIconCell: UITableViewCell { }
public final class ProfileCellController<T> where T: UITableViewCell {
private var cell: T?
func view(in tableView: UITableView) -> UITableViewCell {
cell = tableView.dequeueReusableCell()
return cell!
}
}
extension ProfileCellController: ProfileLoadedView where T: SingleLineCell {
public func display(_ viewModel: ProfileViewModel) {
}
}
extension ProfileCellController: ProfileLoadedView where T: MultiLineWithIconCell {
public func display(_ viewModel: ProfileViewModel) {
}
}
extension UITableView {
func dequeueReusableCell<T: UITableViewCell>() -> T {
let identifier = String(describing: T.self)
return dequeueReusableCell(withIdentifier: identifier) as! T
}
}
However the second extension has an error of
Conflicting conformance of 'ProfileCellController' to protocol 'ProfileLoadedView'; there cannot be more than one conformance, even with different conditional bounds
Is it possible to achieve this?
Sadly that's not supported yet. You cannot have several conditional conformances to the same protocol with different conditions.
However, you can make ProfileCellController unconditionally conform to the ProfileLoadedView protocol, provide a default implementation for the display method and then provide more specific implementations for the subclasses.
extension ProfileCellController: ProfileLoadedView {
public func display(_ viewModel: ProfileViewModel) {
print("default")
}
}
extension ProfileCellController where T: SingleLineCell {
public func display(_ viewModel: ProfileViewModel) {
print("singleline")
}
}
extension ProfileCellController where T: MultiLineWithIconCell {
public func display(_ viewModel: ProfileViewModel) {
print("multiline")
}
}
ProfileCellController<SingleLineCell>().display(ProfileViewModel()) // prints singleline
ProfileCellController<MultiLineWithIconCell>().display(ProfileViewModel()) // prints multiline
Why don't you create a class and use some inheritance so your protocol could be just implemented once?
public class GenericCell: UITableViewCell { }
public class SingleLineCell: GenericCell { }
public class MultiLineWithIconCell: GenericCell { }
extension ProfileCellController: ProfileLoadedView where T: GenericCell {
public func display(_ viewModel: ProfileViewModel) {
switch cell {
case is SingleLineCell:
// impl goes here
return
case is MultiLineWithIconCell:
// impl goes here
return
}
}

Passing nil to a function with an optional generically constrained parameter in a protocol extension

I have a situation where I declare two functions in a protocol, one of them takes an optional generically constrained parameter, the other function takes no parameters, but needs to be implemented in an extension as a default function where it calls the one with a parameter and passes nil. However I get this error:
Argument passed to call that takes no arguments
My code:
public protocol MenuAccessible {
var menuEntryViewController: UIViewController { get }
}
public protocol MenuTabBarControllerProtocol {
func reloadTabs<T>(from uiProvider: T?) where T: MenuAccessible
func reloadTabs()
}
public extension MenuTabBarControllerProtocol {
func reloadTabs() {
reloadTabs(from: nil) // error here, can't infer type
}
}
Obviously the compiler is not able to infer the type. If I for example pass a nil (Optional) of the required type, then the compiler is happy. For example:
struct MenuAccessibleObject: MenuAccessible {
var menuEntryViewController: UIViewController { return UIViewController() }
}
public extension MenuTabBarControllerProtocol {
func reloadTabs() {
let menuAccessible: MenuAccessibleObject? = nil
reloadTabs(from: menuAccessible) // passes nil, but compiler is happpy
}
}
Is there a way to pass nil in my default function implementation and not have to create that dummy object?
I don't understand why you are Using Generic T there if you are defining type is MenuAccessible
Following is simply compiler without any issue
public protocol MenuAccessible {
var menuEntryViewController: UIViewController { get }
}
public protocol MenuTabBarControllerProtocol {
func reloadTabs(from uiProvider: MenuAccessible?)
func reloadTabs()
}
public extension MenuTabBarControllerProtocol {
func reloadTabs() {
reloadTabs(from: nil)
}
}
public extension MenuTabBarControllerProtocol {
func reloadTabs(from uiProvider: MenuAccessible?) {
fatalError() // implement me
}
}
EDIT
I don't know this will work for you or not but try this
public protocol MenuAccessible {
var menuEntryViewController: UIViewController { get }
}
public class UIProvider:NSObject {
}
public protocol MenuTabBarControllerProtocol {
func reloadAllTheItems<T>(from uiProvider: T?) where T: UIProvider, T: MenuAccessible
func reloadTabs()
}
public extension MenuTabBarControllerProtocol {
func reloadTabs() {
self.reloadAllTheItems(from: Temp())
}
func reloadAllTheItems (provider:(UIProvider & MenuAccessible)) {
}
}
class Temp: (UIProvider & MenuAccessible) {
var menuEntryViewController: UIViewController {
return UIViewController()
}
}

I can't use delegate in my app from my framework

First I make a SDK about Bluetooth
ImyBluetoothManager.swift
public protocol ImyBluetoothManager: NSObjectProtocol {
var delegate: myBluetoothDelegate?{get set}
}
public class myBluetooth {
public static func getManager() -> ImyBluetoothManager? {
return myBluetoothManager.sharedInstance()
}
}
myBluetoothManager.swift
class myBluetoothManager: NSObject, CBCentralManagerDelegate, CBPeripheralDelegate, myBluetoothManager {
static var instance: myBluetoothManager!
var delegate: myBluetoothDelegate? {
get {
return delegate
}
set {
delegate = newValue
}
}
private override init() {}
static func sharedInstance() ->myBluetoothManager {
if self.instance == nil {
self.instance = myBluetoothManager()
self.instance.setup()
self.instance.scanBLE()
}
return self.instance
}
Then I run it and get myBluetooth.framework,and I new a project 'ExampleApp'
ExampleApp
ViewController.swift
import myBluetooth
class ViewController: UIViewController,myBluetoothDelegate {
override func viewDidLoad() {
let test = SiltaBluetooth.getManager()
test?.delegate = self
super.viewDidLoad()
}
}
Then I run ExampleApp,and warning me.
warning: could not load any Objective-C class information. This will
significantly reduce the quality of type information available.

Protocol inheritance + delegates in Swift

I have a class with a delegate. I create a subclass, which also has a delegate. I wanted to let the protocol used for the second delegate extend the protocol used for first delegate:
protocol MySuperClassProtocol {
func foo()
}
class MySuperClass {
var delegate:MySuperClassProtocol?
}
protocol MySubClassProtocol:MySuperClassProtocol {
func bar()
}
class MySubClass: MySuperClass {
override var delegate:MySubClassProtocol? // compiler error - "cannot override..."
func test() {
delegate?.foo()
delegate?.bar()
}
}
class UserClass:MySubClassProtocol {
func foo() {
println("foo!")
}
func bar() {
println("bar")
}
}
Is there a way to solve this? The only possible solution I see is to make the 2 protocols independent of each other, and use different names. Like this:
protocol MySuperClassProtocol {
func foo()
}
class MySuperClass {
var mySuperClassDelegate:MySuperClassProtocol?
}
protocol MySubClassProtocol {
func bar()
}
class MySubClass: MySuperClass {
var mySubClassDelegate:MySubClassProtocol?
func test() {
mySuperClassDelegate?.foo()
mySubClassDelegate?.bar()
}
}
class UserClass:MySuperClassProtocol, MySubClassProtocol {
func foo() {
println("foo!")
}
func bar() {
println("bar")
}
}
But this looks a bit weird + will not let me use naming convention for delegate- "delegate".
Sorry for necroposting, the only one solution i found is:
protocol SuperClassDelegate {
func first_method()
}
class SuperClass {
var delegate: SuperClassDelegate?
func do_something() {
delegate?.first_method()
}
}
protocol SubClassDelegate: SuperClassDelegate {
func second_method()
}
class SubClass: SuperClass {
private var subDelegate: SubClassDelegate?
override var delegate: SuperClassDelegate? {
get { return self.subDelegate }
set { self.subDelegate = newValue as! SubClassDelegate? }
}
//override func do_something() {
// super.do_something()
// subDelegate?.second_method()
//}
func do_something_other() {
//subDelegate?.first_method()
self.do_something()
subDelegate?.second_method()
}
}
class InheritanceAndDelegation: SubClassDelegate {
let obj = SubClass()
init() {
obj.delegate = self
}
internal func first_method() {
print("Hello from SuperClass")
}
internal func second_method() {
print("Hello from SubClass")
}
func check() {
obj.do_something_other()
}
}
let inheritanceAndDelegation = InheritanceAndDelegation()
inheritanceAndDelegation.check()
//prints:
//Hello from SuperClass
//Hello from SubClass
Commented code works too. Hope it will be useful for someone.
I was trying to find an ideal solution to this for some time, but could not come up with anything better that this:
protocol BaseDelegateProtocol: class { }
class BaseDelegate: BaseDelegateProtocol { }
class BaseActor {
weak var delegate: BaseDelegate? = nil
}
// MARK: -
protocol ConcreteDelegateProtocol: class {
func doSomething()
}
class ConcreteDelegate: BaseDelegate, ConcreteDelegateProtocol {
func doSomething() {
// Do something
}
}
class ConcreteActor: BaseActor {
private weak var concreteDelegate: ConcreteDelegateProtocol? = nil
override var delegate: BaseDelegate? {
didSet {
concreteDelegate = delegate as? ConcreteDelegateProtocol
}
}
}
Above works in XCode 7 / Swift 2.
This pattern allows adopting more and more protocols on the way down inheriting from BaseDelegate.
There is no need to inherit protocols one from the other, which helps keeping things isolated.
didSet observer on delegate property is automatically called for superclasses, therefore no need to call super.<blah> explicitly, and no risk to 'forget' doing so
Concrete delegate properties can be kept private on each level of inheritance, thereby reducing the clutter.
You can do it in another way, you can add the delegate variable in Subclass and use it to access the SuperClassProtocol also using delegate?.foo().
protocol MySuperClassProtocol {
func foo()
}
class MySuperClass {
//var delegate:MySuperClassProtocol?
}
protocol MySubClassProtocol:MySuperClassProtocol {
func bar()
}
class MySubClass: MySuperClass {
var delegate:MySubClassProtocol?
func test() {
delegate?.foo()
delegate?.bar()
}
}
class UserClass:MySubClassProtocol {
func foo() {
println("foo!")
}
func bar() {
println("bar")
}
}
But the issue with this approach is you can never use MySuperClassProtocol independently unless you create a new SubClass of MySuperClass only for declaring delegate variable.

Resources