I have several ViewControllers all with several methods like the below (and these are virtually the only methods in the classes.)
#IBAction func witnessNameAction(sender: RoundCornerButton) {
presentTextEntryFromViewController(self, initialText: incidentReport.witnessName, completion: { [unowned self] text in
self.incidentReport.witnessName = text
})
sender.setTapped()
}
#IBAction func witnessDescriptionAction(sender: RoundCornerButton) {
presentTextEntryFromViewController(self, initialText: incidentReport.witnessDescription, completion: { [unowned self] text in
self.incidentReport.witnessDescription = text
})
sender.setTapped()
}
Notice that the only difference between the two methods above is which text variable is being get/set. I'm open to any ideas on how to refactor these methods.
Coming from a Java and reading some of Microsoft's excuses for their suggested approaches on MSDN for C#, there are a few ways I can see this being approached.
If the method will only ever have two parameters, create a method that would allow both:
function witness(paramA, paramB) {
if (paramA != null) {
// Target A
}
if (paramB != null) {
// Target B
}
}
This makes me think "I have object A and need to create a unified concept in object B"
Otherwise, an enumeration or static integers would work too:
function witness(target, param) {
switch (target) {
case TARGET_A:
// Target A
break;
case TARGET_B
// Target B
break;
}
}
Which makes me think "I have an object that has fields that I would like external access to change"
You could even use if statements which would allow you to specify multiple targets:
function witness(targets, param) {
if (targets.contains(TARGET_A) {
// Target A
}
if (targets.contains(TARGET_B) {
// Target B
}
}
Which is the same as above in it's own ways.
And last but not least, you could separate the concept and just give self.incidentReport.whatYouNeed as a target:
function witness(target, param) {
target = param;
}
But to me, this is more so "I have an undefined concept of an object that must be set through validation or pre-op", which may be code smell in it's own way. I don't see a problem with a setIfValid() or prepareForSet() style function in the Java world, but that's an entirely different can of worms from my experience. The more I look at it, the more I feel like it all depends on a bunch of other factors that you would have to know as the developer - "Will I ever add more parameters?" "What objects know of what other objects?" "Should I be restricting access anyway?"
Related
I’m new to Swift so I’ve been using the Swift Playgrounds app. On level 2 “Two Experts”, I initialized two experts:
let expert1 = Expert()
let expert2 = Expert()
What I wanted to do was create a function and pass whichever instance into it, access it’s methods etc, something like:
func actions(who: Item, distance: Int, turn: String) {
for 0 to distance {
who.moveforward()
}
ff turn == “Left” {
who.turnleft()
} else if turn == “Right” {
who.turnright()
}
}
Where who is expert1 or expert2.
I couldn’t find a way of doing this so had to write the same actions twice:
Func actions(who: String, distance: Int, turn:String) {
if who == “expert1” {
for 0 to distance {
expert1.moveforward()
} Etc
if who == “expert2” {
for 0 to distance {
expert2.moveforward()
} Etc
Is there a way of passing an instance into a function then perform certain actions if it’s of a particular class?
Since your experts is of type Expert, then the who parameter in your actions method should be of type Expert, if I understand the code correctly. Then you don't need two functions for each of the Experts. Let me know if I understood you correctly, and if it worked out.
Update
#Alexander mentioned that you can also have these methods in an extension on Expert, like so:
extension Expert {
func actions(distance: Int, turn: String) {
// Add method code here
}
}
When adding the method in an extension, every Expert object can use the method. So you could write expert1.actions(1, "Left") or something like that. Here's a link to the official Swift Programming Language guide about extensions.
Say we have this enum
enum Action: String {
case doThing
case doOtherThing
}
This enum is used this way:
func run(action: Action, block: () -> Void)
Now, I unit test the run method so I need to pass an Action this way:
func testActionRun() {
let expect = expectation(description: #function)
let sut = ActionRunner()
sut.run(action: .doThing) {
expect.fulfill()
// Assert something
}
waitForExpectations(timeout: 0.1, handler: nil)
}
As I need to test other situations on ActionRunner, I ended with a lot of .doThing spread over the whole test suite.
The problem is: if I make a change in production code and change case doThing to case doThatThing now all my test suite fails because there is no a case doThing.
The perfect thing would be to declare a dummy case in test code to allow something like
sut.run(action: .dummyAction) {
}
but enum does not allow that as it doesn't allows inheritance nor a extension to add a case.
The first option that came to my mind was to convert Action into a protocol, but that change is unnecessary in production and its only purpose is to accomplish something in test code.
So, is it there another option to achieve this?
The question of how to avoid coupling when using enums is a tricky one. I bumped into that myself a few times with no solid answer :/
One point you raise is the one of using a protocol, and that feels unnecessary in production. I sort of agree with that, but most time it's the necessary evil.
In the example you showed though I think maybe a tweak in the design might solve part of the problem.
In particular when looking at this code
func run(action: Action, block: () -> Void) {
// ...
}
func testActionRun() {
let expect = expectation(description: #function)
let sut = ActionRunner()
sut.run(action: .doThing) {
expect.fulfill()
// Assert something
}
waitForExpectations(timeout: 0.1, handler: nil)
}
What comes to mind to me is that your Action specifies a certain behaviour. That is when you test the run method passing .doThing you expect a different behaviour than when passing .doOtherThing.
If that's right, is there any reason why you need to pass the action enum instance and an action block to the run function?
You could separate the code that defines the behaviour from the one performs the actual action even more that what you've done already. For example:
protocol Actionable {
var action: () -> () { get }
}
enum Action: Actionable {
case doThing
case doOtherThing
var action {
switch self {
case .doThing: return ...
case .doOtherThing: return ...
}
}
class ActionRunner {
func run(actionable: Actionable) {
actionable.action()
}
}
func testActionRun() {
let expect = expectation(description: #function)
let sut = ActionRunner()
sut.run(actionable: FakeActionable()) {
expectation.fulfill()
}
waitForExpectations(timeout: 0.1, handler: nil)
}
class FakeActionable: Actionable {
let action = { }
}
func testDoThing() {
let sut = Action.doThing
sut.action()
// XCTAssert for the expected effect of the action
}
Note: I haven't actually compiled that code, so bear with me if it has some mistakes. It should give the idea though.
This way you have ActionRunner which only purpose is to properly run a given Actionable, and the Action enum which only purpose is to describe what different actions should do.
This example code is rather restrict in what it can do, only run () -> () actions, but you could build on top of it to achieve more advanced behaviours.
If you change your production code you have to change your test code too in order to test those new changes.
Maybe you can set the value on an Action variable in the setUp func of your XCTestCase class
import XCTest
class SharingKitTests: XCTestCase {
var theAction: Action!
override func setUp() {
super.setUp()
self.theAction = .doThing
}
}
Then you will be able to use this theAction var in all your test methods, and if you need to change the value you only need to change it in one place.
I have a large method that does some loading and calculating so it shows an activity indicator view to inform the users they should wait. The logic is pretty complex so there are 4 places in which the data processing might break or return (everything is done on closures). Anyway, I didn't want to repeat this code:
DispatchQueue.main.async {
activityView.hide()
activityView.removeFromSuperview()
}
in 4 places so I figured that I would write a nested function:
func removeActivityView() {
DispatchQueue.main.async {
activityView.hide()
activityView.removeFromSuperview()
}
}
but then I realised that in Swift I could also do:
let removeActivityView = {
DispatchQueue.main.async {
activityView.hide()
activityView.removeFromSuperview()
}
}
which is used exactly in the same way and does exactly the same from the user's point of view.
So what is the actual difference between one approach and the other?
They are the same in this case. In Swift:
Nested functions are closures that have a name and can capture values from their enclosing function.
Source
In fact, you could also do:
func foo() {
print("Foo!")
}
let bar = foo
Now foo() and bar() would yield the same result. This can be done for any function that takes in no arguments.
I'm not sure how/if the compiler differentiates these two. If anyone has more information with respect to that, I would be very interested!
In my Swift code, I have a few methods that look like this:
protocol EditorDelegate {
// ...
func didStartSearch(query: String) -> Bool
}
class Editor: UIViewController {
func search(sender: AnyObject) {
let wasHandled = self.delegate?.didStartSearch(query) ?? false
if !wasHandled {
// do default searching behavior
}
}
}
This works, but it's not self-documenting. The didStartSearch method doesn't really communicate that it's returning a flag indicating whether the default behavior should be skipped.
What are some good options for handling this?
I tried to think of a better way to name the delegate function, below is what I came up with that makes the most sense to me. Enums are very powerful in swift, using them can make code more understandable at a glance. Also I like to think of things in terms of different states, which can be clearly defined with enums.
enum SearchStatus {
case Ready
case Processing
case Complete(result: String)
}
protocol EditorDelegate: class {
func statusForSearch(with query: String) -> SearchStatus
}
class Editor: UIViewController {
weak var delegate: EditorDelegate?
func search(sender: AnyObject) {
let query = "some input.."
guard let status = delegate?.statusForSearch(with: query) else {
// delegate not set
return
}
switch status {
case .Ready:
// actually do your search
break
case .Processing:
// search in progress
break
case .Complete(let result):
// do something with result
print("result = \(result)")
break
}
}
}
Think about the relationship between the delegating object and the object being delegated to, and the "message" (in high-level semantics, not just code) that a call to the delegate method is about. That is, does a delegate method call mean, "hey, in case you're interested, this thing happened," or, "this thing happened, what should I do about it?". If the delegate returns a value to the delegating object, you're probably in the second category.
Per Coding Guidelines for Cocoa, delegate methods should:
Start by identifying the delegating object (e.g. the tableView in tableView:didSelectRow: or the window in windowWillClose:). This is important because delegation can be a many-to-one relationship — if you have a delegate property (or setDelegate method) on one class, there's nothing preventing one object from being the delegate of many others, and indeed that can be a useful pattern for whoever adopts your delegate protocol.
If the method asks something of the delegate, either name the thing being asked (e.g. cellForRowAtIndexPath), or for Boolean conditions, describe the consequence of a positive value — this usually involves language like "should" (e.g. windowShouldClose, tableView:shouldSelectRowAtIndexPath:).
In your case, it's not entirely clear what "should" happen as a result of the delegate returning true or false, but here's a guess:
protocol EditorDelegate {
func editor(_ editor: Editor, shouldShowDefaultResultsForSearch query: String) -> Bool
}
The use of return flags is often considered problematic for many reasons. See this link for one of many explanations of the arguments for and against. Nevertheless, one solution that might help in this case would be to use a typealias.
typealias useDefaultBehaviour = Bool
protocol EditorDelegate {
func didStartSearch(query: String) -> useDefaultBehaviour
}
I have some expensive promises that get called in different spots. Ideally, I'd like to just chain off an existing in-flight promise (with an optional force), so I find myself doing something like this:
class Expensive {
var fooPromise : Promise<Foo>?
var barPromise : Promise<Bar>?
func doExpensiveFoo(force: bool = false) -> Promise<Foo> {
if let existing = fooPromise where existing.pending || (existing.fufilled && !force) {
// Return the existing promise
return existing
}
// Start a new Foo
return firstly {
// ...
}
}
func doExpensiveBar(force: bool = false) -> Promise<Bar> {
if let existing = barPromise where existing.pending || (existing.fufilled && !force) {
// Return the existing promise
return existing
}
// Start a new Bar
return firstly {
// ...
}
}
}
But that feels like a fair amount of boiler-plate (a local variable for each promise, and the existing chunk at the start of each function), so I'm wondering if anyone has seen a good pattern for abstracting away the variables and wrapper?
To borrow a term from Python, I'm looking for a decorator that would hide all that. Something like:
class Expensive {
private func startFoo() -> Promise<Foo> {
return firstly {
//..
}
}
public doExpensiveFoo = wrapExpensive(startFoo)
}
Any suggestions, or should I look at rolling my own?
I'm no expert, but this pattern worked for me:
private var fooPromise : Promise<Foo>?
func doExpensiveFoo() -> Promise<Foo> {
if let fooPromise = self.fooPromise, fooPromise.isPending {
// return the pending promise
return fooPromise
}
// reassign a newly created promise
fooPromise = firstly {
// do your thing
...
}
return fooPromise!
}
What I like about this pattern is that the method handles pending state internally, and that the promise automatically re-executes if called after it is finished. This allows callers to be ignorant of the internal mechanism or the state of the promise. Obviously, if you need to caller to be part of the decision, then keep the "force" flag approach.
I do not see any common base of Foo and Bar in your example. But even if they would have one Swift still does not support covariance on generic type parameters. At first you would need to create a common protocol for both types. Maybe this helps you to get on track:
Storing generic objects in Swift Array