Swift - How can I test with generic? - ios

I wanna unittest with generics.
But I can't think of a way.
My code is as below, and I want to test the part prepare().
class A_ViewModel {
var useCase: UseCaseProtocol = UseCase()
var item: A_CellModel = .init()
// I want to unittest prepare()
func prepare() {
// logic....
// and call calcuate
useCase.calculate(item: item)
}
}
protocol TestableProtocol {
var testProperty: Bool { get set }
}
class A_CellModel: TestableProtocol {
var testProperty: Bool = false
}
protocol UseCaseProtocol {
func calculate<T: TestableProtocol>(item: T)
}
class UseCase: UseCaseProtocol {
func calculate<T: TestableProtocol>(item: T) {
// logic......
}
}
However, since calcaulte(item:) in usecase uses generic, it is necessary to hand over the clear type (A_CellModel).
In that case, there is a dependence between A_ViewModel and A_CellModel, which makes it difficult to test the unit.
In order to test prepare(), should calcaulte(item:) give up generic?
Should I use existential type?

Related

Call a method with dynamic class name in swift

How can we call class functions with a dynamic class name?
Assume the following example where I have two class with methods with same signature
class Foo{
class func doSomething()
}
class Foobar {
class func doSomething()
}
class ActualWork{
//call following method with a variable type so that it accepts dynamic class name
func callDynamicClassMethod(x: dynamicClass)
x.doSomething()
}
How can this be implemented so that x accepts values at run time
Edit: Sorry, I missed to mention that I was looking for any other ways other than protocol oriented approach. This is more of an exploratory question to explore if there is a more direct approach/pods/libraries to achieve this.
I liked this question, because it made me to think a lit'bit outside of the box.
I'll answer it, by dividing it into a few parts.
First
call class functions
Class function is basically a Type methods, which can be achieved using the static word inside the class context.
Taking that into account, you can get a simple solution, using protocol and passing the class reference (conforming to that protocol) like this:
protocol Aaa{
static func doSomething();
}
class Foo : Aaa{
static func doSomething() {
print("Foo doing something");
}
}
class FooBar : Aaa{
static func doSomething() {
print("FooBar doing something");
}
}
class ActualWork{
//Using class (static) method
func callDynamicClassMethod <T: Aaa> (x: T.Type) {
x.doSomething();
}
}
//This is how you can use it
func usage(){
let aw = ActualWork();
aw.callDynamicClassMethod(x: Foo.self);
aw.callDynamicClassMethod(x: Foo.self);
}
Second
In case you don't really need the method on the class context, you may consider using instance methods. In that case the solution would be even simpler, like this:
protocol Bbb{
func doSomething();
}
class Bar : Bbb{
func doSomething() {
print("Bar instance doing something");
}
}
class BarBar : Bbb{
func doSomething() {
print("BarBar instance doing something");
}
}
class ActualWork{
//Using instance (non-static) method
func callDynamicInstanceMethod <T: Bbb> (x: T){
x.doSomething();
}
}
//This is how you can use it
func usage(){
let aw = ActualWork();
aw.callDynamicInstanceMethod(x: Bar());
aw.callDynamicInstanceMethod(x: BarBar());
}
Third
If you need to use the class func syntax, as OP originally did:
class func doSomething()
You CANNOT simply use a protocol. Because protocol is not a class...
So compiler won't allow it.
But it's still possible, you can achieve that by using
Selector with NSObject.perform method
like this:
class ActualWork : NSObject{
func callDynamicClassMethod<T: NSObject>(x: T.Type, methodName: String){
x.perform(Selector(methodName));
}
}
class Ccc : NSObject{
#objc class func doSomething(){
print("Ccc class Doing something ");
}
}
class Ddd : NSObject{
#objc class func doSomething(){
print("Ccc class Doing something ");
}
#objc class func doOther(){
print("Ccc class Doing something ");
}
}
//This is how you can use it
func usage() {
let aw = ActualWork();
aw.callDynamicClassMethod(x: Ccc.self, methodName: "doSomething");
aw.callDynamicClassMethod(x: Ddd.self, methodName: "doSomething");
aw.callDynamicClassMethod(x: Ddd.self, methodName: "doOther");
}
Generics and Protocol oriented programming will do the job:
protocol Doable {
static func doSomething()
}
class Foo: Doable {
static func doSomething() {
debugPrint("Foo")
}
}
class Foobar: Doable {
static func doSomething() {
debugPrint("Foobar")
}
}
class ActualWork {
func callDynamicClassMethod<T: Doable>(x: T.Type) {
x.doSomething()
}
}
let work = ActualWork()
work.callDynamicClassMethod(x: Foo.self)
work.callDynamicClassMethod(x: Foobar.self)
you can achieve this with help of Protocol
protocol common {
static func doSomething()
}
class Foo : common{
static func doSomething() {
print("Foo")
}
}
class Foobar : common {
static func doSomething() {
print("Foobar")
}
}
class ActualWork{
//call following method with a variable type so that it accepts dynamic class name
func callDynamicClassMethod(x: common.Type) {
x.doSomething()
}
}
let fooObj : common = Foo()
let Foobarobj : common = Foobar()
let workObk = ActualWork()
workObk.callDynamicClassMethod(x:Foo.self)
workObk.callDynamicClassMethod(x:Foobar.self)
I think, there are three solutions. I shared an sample below.
Use "protocol" that has "doSomething()" function requirements.
Create a function which gets function definition as a parameter.
Use reflection. you can use EVReflection that is good Api for reflection.
sample code:
protocol FooProtocol {
static func doSomething()
}
class Foo: FooProtocol {
class func doSomething() {
print("Foo:doSomething")
}
}
class Foobar: FooProtocol {
class func doSomething() {
print("Foobar:doSomething")
}
}
class ActualWork {
func callDynamicClassMethod<T: FooProtocol>(x: T.Type) {
x.doSomething()
}
func callDynamicClassMethod(x: #autoclosure () -> Void) {
x()
}
func callDynamicClassMethod(x: () -> Void) {
x()
}
}
ActualWork().callDynamicClassMethod(x: Foo.self)
ActualWork().callDynamicClassMethod(x: Foobar.self)
print("\n")
ActualWork().callDynamicClassMethod(x: Foo.doSomething())
ActualWork().callDynamicClassMethod(x: Foobar.doSomething())
print("\n")
ActualWork().callDynamicClassMethod(x: Foo.doSomething)
ActualWork().callDynamicClassMethod(x: Foobar.doSomething)
Looks like you are searching for duck typing, and this is harder to achieve in a statically typed language (with some exceptions, listed in the linked Wikipedia page).
This is because dynamically calling a method requires knowledge about the layout of the target object, thus either inheritance of the class declaring the method, or conformance to a protocol that requires that method.
Starting with Swift 4.2, and the introduction of dynamic member lookup, there is another approach to solve your problem, however it also involves some ceremony:
// This needs to be used as base of all classes that you want to pass
// as arguments
#dynamicMemberLookup
class BaseDynamicClass {
subscript(dynamicMember member: String) -> () -> Void {
return { /* empty closure do nothing */ }
}
}
// subclasses can choose to respond to member queries any way they like
class Foo: BaseDynamicClass {
override subscript(dynamicMember member: String) -> () -> Void {
if member == "doSomething" { return doSomething }
return super[dynamicMember: member]
}
func doSomething() {
print("Dynamic from Foo")
}
}
class Bar: BaseDynamicClass {
override subscript(dynamicMember member: String) -> () -> Void {
if member == "doSomething" { return doSomething }
return super[dynamicMember: member]
}
func doSomething() {
print("Dynamic from Bar")
}
}
func test(receiver: BaseDynamicClass) {
receiver.doSomething()
}
test(receiver: Bar()) // Dynamic from Bar
To conclude, in the current Swift version there is no way to have both the argument and the method dynamic, some common ground needs to be set.

Function implementation in constrained protocol extension is not invoked

Problem Summary
I have a generic view subclass TintableView<T>: UIView, which implements a protocol TintStateComputing with identical associated type T. TintStateComputing's constrained extension implementation is not being called; its unconstrained extension implementation is called instead.
The TintStateComputing protocol has a function computeTintState() -> T, which does what it sounds like: checks the local state properties, and returns the according instance of T.
I want to write extension implementations of func computeTintState() -> T on TintStateComputing, constrained on the type of T. For example, with a ControlState enum:
extension TintStateComputing where T == ControlState {
func computeTintState() -> T {
return self.isEnabled ? .enabled : T.default
}
}
However, in order to complete the protocol conformance, I think I need to account for other values of T. So I've also stated an unconstrained extension to TintStateComputing. This unconstrained extension implementation is always being called, instead of the constrained implementation.
extension TintStateComputing {
func computeTintState() -> T {
return _tintState ?? T.default
}
}
Playground Testbed
import UIKit
// MARK: - Types
public enum ControlState: Int {
case normal, enabled, highlighted, selected, disabled
}
public protocol Defaultable {
static var `default`: Self { get }
}
extension ControlState: Defaultable {
public static let `default`: ControlState = .normal
}
// MARK: - TintStateComputing declaration
public protocol TintStateComputing {
associatedtype TintState: Hashable & Defaultable
func computeTintState() -> TintState
var _tintState: TintState? { get }
var isEnabled: Bool { get }
}
// MARK: - TintableView declaration
class TintableView<T: Hashable & Defaultable>: UIView, TintStateComputing {
// `typealias TintState = T` is implictly supplied by compiler
var _tintState: T?
var isEnabled: Bool = true { didSet { _tintState = nil }}
var tintState: T {
get {
guard _tintState == nil else {
return _tintState!
}
return computeTintState()
}
set {
_tintState = newValue
}
}
}
// MARK: - Unconstrained TintStateComputing extension
extension TintStateComputing {
func computeTintState() -> TintState {
return _tintState ?? TintState.default
}
}
// MARK: - Constrained TintStateComputing extension
extension TintStateComputing where TintState == ControlState {
func computeTintState() -> TintState {
return self.isEnabled ? .enabled : TintState.default
}
}
// MARK: - Test Case
let a = TintableView<ControlState>()
a.isEnabled = true
print("Computed tint state: \(a.tintState); should be .enabled") // .normal
print("finished")
Workaround
I realized this morning that since (at least for now) what I'm really trying to accomplish is handle the isEnabled: Bool flag on the view, I could follow the same pattern as used for Defaultable to define a default 'enabled' case.
public protocol Enableable {
static var defaultEnabled: Self { get }
}
extension ControlState: Defaultable, Enableable {
public static let `default`: ControlState = .normal
public static let defaultEnabled: ControlState = .enabled
}
At that point, I can really eliminate the TintStateComputing protocol, and update my view's tintState: T implementation to account for the flag directly.
var tintState: T {
get {
guard _tintState == nil else { return _tintState! }
return self.isEnabled ? T.defaultEnabled : T.default
}
set {
_tintState = newValue
}
}
It's not as generalized as putting the implementation in a constrained extension, but it will work for now. I think that if I have future subclasses with multi-dimensional tint-state types (e.g. 'enabled' + 'in-range') I'll be able to address via override.
struct CalendarState: Equatable, Hashable, Defaultable, Enableable {
let x: Int
static let `default`: CalendarState = CalendarState(x: 0)
static let defaultEnabled: CalendarState = CalendarState(x: 1)
}
class ControlTintableView: TintableView<ControlState> {}
class CalendarView: TintableView<CalendarState> {}
let a = ControlTintableView()
a.isEnabled = true
print("ControlTintableView computed tint state: \(a.tintState); should be: .enabled") // .enabled
let b = CalendarView()
b.isEnabled = true
print("CalendarView computed tint state: \(b.tintState); should be: CalendarState(x: 1)") // CalendarState(x: 1)
The problem is that there is only one specialization of TintableView, and it's based on what it knows from its own definition. When compiling the class, it considers computeTintState(), sees that TintState is not promised at that point to be exactly ControlState, and so compiles-in the more general version.
In order to do what you want, when it encounters TintableView<ControlState> it would need to completely reconsider and recompile the TintableView class. Swift doesn't currently do that. In this case, I don't consider that a bug. I think this code is trying to be too magical and is abusing extensions, but that's just my opinion on it. If you believe Swift should handle this kind of case then I recommend opening a defect at bugs.swift.org.
Keep in mind what would happen if TintableView were in one module and the TintState == ControlState extension were in another (say in the module with the let a =). In that case, it would be impossible to get the behavior you're asking for, because one module can't respecialize another module (it may not have the source code available). Would you consider this code good if it behaved one way when these were in one module, but have different visible behaviors if they were in different modules? That's why I consider this too tricky and bug-prone. This split-module specialization problem happens all the time, but it mostly just impacts performance (and stdlib uses private compiler directives to improve that because it's a special case).

Is this the best way to convert Swift protocol to RxDelegateProxy?

Sorry I could not come up with better title than that, Ill modify it if anybody suggests a better one after.
I have a protocol
#objc public protocol MyCollectionViewProtocol {
func scrollViewShouldScrollToTop()
}
I have declared it to be #objc because unfortunately DelegateProxy does not work with non NSObject protocols (I assume, if somebody can clarify that, will be a great help)
My collectionView
public class MyCollectionView: UICollectionView {
weak var cvDelegate : MyCollectionViewProtocol?
... //rest of the code isnt related to this question in particular
Now I declare delegate proxy as
open class RxMyCollectionViewDelegateProxy : DelegateProxy<MyCollectionView, MyCollectionViewProtocol>
, DelegateProxyType
, MyCollectionViewProtocol {
public static func currentDelegate(for object: MyCollectionView) -> MyCollectionViewProtocol? {
return object.cvDelegate
}
public static func setCurrentDelegate(_ delegate: MyCollectionViewProtocol?, to object: MyCollectionView) {
object.cvDelegate = delegate
}
public weak private(set) var collectionView: MyCollectionView?
internal lazy var shouldScrollPublishSubject: PublishSubject<Void> = {
let localSubject = PublishSubject<Void>()
return localSubject
}()
public init(collectionView: ParentObject) {
self.collectionView = collectionView
super.init(parentObject: collectionView, delegateProxy: RxMyCollectionViewDelegateProxy.self)
}
// Register known implementations
public static func registerKnownImplementations() {
self.register { RxMyCollectionViewDelegateProxy(collectionView: $0) }
}
//implementation of MyCollectionViewProtocol
public func scrollViewShouldScrollToTop() {
shouldScrollPublishSubject.onNext(())
self._forwardToDelegate?.scrollViewShouldScrollToTop()
}
deinit {
shouldScrollPublishSubject.onCompleted()
}
}
Finally I declare my Reactive extension for MyCollectionView as
extension Reactive where Base: MyCollectionView {
public var delegate: DelegateProxy<MyCollectionView, MyCollectionViewProtocol> {
return RxMyCollectionViewDelegateProxy.proxy(for: base)
}
public var shouldScrollToTop: ControlEvent<Void> {
let source = RxMyCollectionViewDelegateProxy.proxy(for: base).shouldScrollPublishSubject
return ControlEvent(events: source)
}
}
Finally, I use it as
collectionView.rx.shouldScrollToTop.debug().subscribe(onNext: { (state) in
print("I should scroll to top")
}, onError: { (error) in
print("errored out")
}, onCompleted: {
print("completed")
}, onDisposed: {
print("Disposed")
}).disposed(by: disposeBag)
Question
Because none of the online tutorials(Raywenderlich)/courses (Udemy)/Books(Raywenderlich) explains how to convert the swift protocol to Rx style am confused as what I am doing is correct or wrong. The code works but even the worst designed code might work, hence I wanna be sure what am doing is correct or am messing something. I wrote the above code following the approach used in UIScrollView+Rx.swift and RxScrollViewDelegateProxy.swift
Though the code above works only for protocols without any return type example method I used above func scrollViewShouldScrollToTop() has no return type associated with it. I could not imagine how could I use the DelegateProxy above to convert the protocol methods with return types, like numberOfRowsInSection which has Int as return type.
I happened to look at the RxDataSource implementation and realized in order to convert cellForRowAtIndexPath RxDataSource constructor expects you to pass the block as a init parameter and executes it whenever tableView calls cellForRowAtIndexPath in its proxyDelegate.
Now I could do the same thing if thats the only way out. Need to know is that how am supposed to code it or can I modify ProxyDelegate implementation above to convert the protocol method with return types.

Composition rather than inheritance for shared variables

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.

Swift - How can I override an extension method in a concrete subclass

I have an extension on UIView implementing a protocol
protocol SomeProtocol {
var property : Int
}
extension UIView : SomeProtocol {
var property : Int {
get {
return 0
}
set {
// do nothing
}
}
}
in a concrete subclass I want to override this extension method:
class Subclass : UIView, SomeProtocol {
var _property : Int = 1
var property : Int {
get { return _property}
set(val) {_property = val}
}
}
I set breakpoints and see that the extension method is called and not the concrete subclass method:
var subclassObject = Subclass()
someObject.doSomethingWithConcreteSubclassObject(subclassObject)
// other code;
fun doSomethingWithConcreteSuclassObject(object : UIView) {
var value = object.property // always goes to extension class get/set
}
As others have noted, Swift does not (yet) allow you to override a method declared in a class extension. However, I'm not sure whether you'll ever get the behavior you want even if/when Swift someday allows you to override these methods.
Consider how Swift deals with protocols and protocol extensions. Given a protocol to print some metasyntactic variable names:
protocol Metasyntactic {
func foo() -> String
func bar() -> String
}
An extension to provide default implementations:
extension Metasyntactic {
func foo() -> String {
return "foo"
}
func bar() -> String {
return "bar"
}
}
And a class that conforms to the protocol:
class FooBar : Metasyntactic {
func foo() -> String {
return "FOO"
}
func bar() -> String {
return "BAR"
}
}
Swift will use dynamic dispatch to call the appropriate implementations of foo() and bar() based on each variable's runtime type rather than on the type inferred by the compiler:
let a = FooBar()
a.foo() // Prints "FOO"
a.bar() // Prints "BAR"
let b: Metasyntactic = FooBar()
b.foo() // Prints "FOO"
b.bar() // Prints "BAR"
If, however, we extend the protocol further to add a new method:
extension Metasyntactic {
func baz() -> String {
return "baz"
}
}
And if we override our new method in a class that conforms to the protocol:
class FooBarBaz : Metasyntactic {
func foo() -> String {
return "FOO"
}
func bar() -> String {
return "BAR"
}
func baz() -> String {
return "BAZ"
}
}
Swift will now use static dispatch to call the appropriate implementation of baz() based on the type inferred by the compiler:
let a = FooBarBaz()
a.baz() // Prints "BAZ"
let b: Metasyntactic = FooBarBaz()
b.baz() // Prints "baz"
Alexandros Salazar has a fantastic blog post explaining this behavior in depth, but suffice it to say that Swift only uses dynamic dispatch for methods declared in the original protocol, not for methods declared in protocol extensions. I imagine the same would be true of class extensions, as well.
I know this question has been asked a while ago. But this will be handy for someone who looking for an easier way. There is a way of overriding an extension methods. I know its bit hacky but it does the job beautifully.
If you declare your protocol with #objc
#objc protocol MethodOverridable {
func overrideMe()
}
In Extension
extension MainClass: MethodOverridable {
func overrideMe() {
print("Something useful")
}
}
Subclass - You can able to override it in your subclass. It works like a magic. Well, not really when adding #objc it exposes your protocol to Objective-C and its Runtime. That allows your subclass to override.
class SubClass: MainClass {
override func overrideMe() {
print("Something more useful")
}
}
Swift 5
class Class
{
#objc dynamic func make() { print("make from class") }
}
class SubClass: Class {}
extension SubClass {
override func make() {
print("override")
}
}
It looks like you can override property for 2nd super class property. For example, you can access UIView property by making extension to the UILabel wanting to override frame property of UIView. This sample works for me in Xcode 6.3.2
extension UILabel {
override public var frame: CGRect {
didSet {
println("\(frame)")
}
}
}
You can't do this through normal means.
It's in Apple's docs that you can't override a method in an extension in a subclass.
Also, extensions can add new functionality to a type, but they cannot override existing functionality.
https://docs.swift.org/swift-book/LanguageGuide/Extensions.html
I think you forgot to override the superclass property in your subclass:
class Subclass : UIView {
var _property : Int = 1
override var property : Int {
get { return _property}
set(val) {_property = val}
}
}

Resources