I am trying to migrate some code using a Repository pattern from Vapor 3 to Vapor 4. I have gone through the documentation of this specific pattern from the Vapor 4 documentation, and I think I understand it for the most part.
The one thing I am not getting, however, is the way that the repository factory gets set within the Application extension. The example from the documentation shows this:
extension Application {
private struct UserRepositoryKey: StorageKey {
typealias Value = UserRepositoryFactory
}
var users: UserRepositoryFactory {
get {
self.storage[UserRepositoryKey.self] ?? .init()
}
set {
self.storage[UserRepositoryKey.self] = newValue
}
}
}
If I am reading the getter method correctly (and I might not be - I'm far from a Swift expert), a new instance of the UserRepositoryFactory structure will be created and returned when app.users is referenced. At that time, however, it does not appear that the contents of self.storage[UserRepositoryKey.self] is changed in any way. So if I happened to access app.users two times in a row, I would get 2 different instances returned to me and self.storage[UserRepositoryKey.self] would remain set to nil.
Following through the rest of the sample code in the document, it appears to define the make function that will be used by the factory when configuring the app as so:
app.users.use { req in
DatabaseUserRepository(database: req.db)
}
Here it seems like app.users.use would get a new factory instance and call its use function to set the appropriate make method for that instance.
Later, when I go to handle a request, I use the request.users method that was defined by this Request extension:
extension Request {
var users: UserRepository {
self.application.users.make!(self)
}
}
Here it seems like self.application.users.make would be invoked on a different repository factory instance that is referenced by self.application.users. It would therefore not apply the factory's make method that was set earlier when configuring the application.
So what am I missing here?
It looks like the docs are slightly out of date for that. You can have a look at how views or client is done, but somewhere you need to call initialize() to set the repository. Here's what my working repository looks like:
import Vapor
extension Application {
struct Repositories {
struct Provider {
let run: (Application) -> ()
public init(_ run: #escaping (Application) -> ()) {
self.run = run
}
}
final class Storage {
var makeRepository: ((Application) -> APIRepository)?
init() { }
}
struct Key: StorageKey {
typealias Value = Storage
}
let application: Application
var repository: APIRepository {
guard let makeRepository = self.storage.makeRepository else {
fatalError("No repository configured. Configure with app.repositories.use(...)")
}
return makeRepository(self.application)
}
func use(_ provider: Provider) {
provider.run(self.application)
}
func use(_ makeRepository: #escaping (Application) -> APIRepository) {
self.storage.makeRepository = makeRepository
}
func initialize() {
self.application.storage[Key.self] = .init()
}
private var storage: Storage {
if self.application.storage[Key.self] == nil {
self.initialize()
}
return self.application.storage[Key.self]!
}
}
var repositories: Repositories {
.init(application: self)
}
}
That autoinitializes itself the first time it's used. Note that APIRepository is the protocol used for my repostiory. FluentRepository is the Fluent implementation of that protocol. Then like you I have an extension on Request to use it in request handlers:
extension Request {
var repository: APIRepository {
self.application.repositories.repository.for(self)
}
}
Finally, you need to configure it to use the right repository. So in my configure.swift I have:
app.repositories.use { application in
FluentRepository(database: application.db)
}
and in tests I can switch it for the in-memory repository that doesn't touch the DB:
application.repositories.use { _ in
return inMemoryRepository
}
I have managed to get the example from the docs working as-is.
Tracing through the execution with the debugger, there is the predictable call to get, as you say, and this returns the instance from .init() as the failover from not having a previously stored value. Included in the example you refer to is:
struct UserRepositoryFactory {
var make: ((Request) -> UserRepository)?
mutating func use(_ make: #escaping ((Request) -> UserRepository)) {
self.make = make
}
}
This use function is executed next, which is mutating and updates the variable make. I believe it is this change to make that then triggers a call to set. It certainly happens immediately after use and before execution moves on in configure.swift. So, by the time the server formally starts and you actually use the Repository in a route, there is a stored instance that is reused as required.
Related
I'm using Axe DevTools and I'm trying to figure out how to tag multiple scans with the same build information. Right now I have my tests running like this:
class MyTestCase : XCTestCase {
func myTest() {
Attest.that(view: view)
.isAccessible({ result in })
.andPushResult(withTags: [myBuild])
}
}
How can I add the myBuild tag globally to all tests that I run?
I would build my own class that utilizes the Axe DevTools (Attest) APIs. Then have my test cases interact with my own class instead of interacting with Attest itself!
class AccessibilityTestUtils {
static let buildTag:String = Bundle.main.object(
forInfoDictionaryKey: "CFBundleShortVersionString"
) as! String
init(build: String) {
self.buildTag = build
}
static func runAccessibilityTestOn(aView : View) {
Attest.that(view: aView).isAccessible({ result in })
.andPushResult(withTags: [buildTag])
}
}
Example Usage
class YourTestClass {
func yourTestCase() {
AccessibilityTestUtils.runAccessibilityTestOn(aView)
}
}
Note: This approach also protects you from future changes to the Attest library by making it so that you only have to change one line of code in the event of non backwards compatible changes.
I am working in an iOS application called ConnectApp and I am using a framework called Connector. Now, Connector framework completes actual connection task with BLE devices and let my caller app (i.e. ConnectApp) know the connection request results through ConnectionDelegate. Let's see example code,
ConnectApp - host app
class ConnectionService: ConnectionDelegate {
func connect(){
var connector = Connector()
connector.setDelegate(self)
connector.connect()
}
func onConnected(result: ConnectionResult) {
//connection result
}
}
Connector Framework
public class ConnectionResult {
// many complicated custom variables
}
public protocol ConnectionDelegate {
func onConnected(result: ConnectionResult)
}
public class Connector {
var delegate: ConnectionDelegate?
func setDelegate(delegate: ConnectionDelegate) {
self.delegate = delegate
}
func connect() {
//…..
// result = prepared from framework
delegate?.onConnected(result)
}
}
Problem
Sometimes developers have no BLE device and we need to mock the Connector layer of framework. In case of simple classes (i.e. with simpler methods) we could have used inheritance and mock the Connector with a MockConnector which might override the lower tasks and return status from MockConnector class. But when I need to deal with a ConnectionDelegate which returns complicated object. How can I resolve this issue?
Note that framework does not provide interfaces of the classes rather we need to find way around for concrete objects like, Connector, ConnectionDelegate etc.
Update 1:
Trying to apply Skwiggs's answer so I created protocol like,
protocol ConnectorProtocol: Connector {
associatedType MockResult: ConnectionResult
}
And then injecting real/mock using strategy pattern like,
class ConnectionService: ConnectionDelegate {
var connector: ConnectorProtocol? // Getting compiler error
init(conn: ConnectorProtocol){
connector = conn
}
func connect(){
connector.setDelegate(self)
connector.connect()
}
func onConnected(result: ConnectionResult) {
//connection result
}
}
Now I am getting compiler error,
Protocol 'ConnectorProtocol' can only be used as a generic constraint because it has Self or associated type requirements
What am I doing wrong?
In Swift, the cleanest way to create a Seam (a separation that allows us to substitute different implementations) is to define a protocol. This requires changing the production code to talk to the protocol, instead of a hard-coded dependency like Connector().
First, create the protocol. Swift lets us attach new protocols to existing types.
protocol ConnectorProtocol {}
extension Connector: ConnectorProtocol {}
This defines a protocol, initially empty. And it says that Connector conforms to this protocol.
What belongs in the protocol? You can discover this by changing the type of var connector from the implicit Connector to an explicit ConnectorProtocol:
var connector: ConnectorProtocol = Connector()
Xcode will complain about unknown methods. Satisfy it by copying the signature of each method it needs into the protocol. Judging from your code sample, it may be:
protocol ConnectorProtocol {
func setDelegate(delegate: ConnectionDelegate)
func connect()
}
Because Connector already implements these methods, the protocol extension is satisfied.
Next, we need a way for the production code to use Connector, but for test code to substitute a different implementation of the protocol. Since ConnectionService creates a new instance when connect() is called, we can use a closure as a simple Factory Method. The production code can supply a default closure (creating a Connector) like with a closure property:
private let makeConnector: () -> ConnectorProtocol
Set its value by passing an argument to the initializer. The initializer can specify a default value, so that it makes a real Connector unless told otherwise:
init(makeConnector: (() -> ConnectorProtocol) = { Connector() }) {
self.makeConnector = makeConnector
super.init()
}
In connect(), call makeConnector() instead of Connector(). Since we don't have unit tests for this change, do a manual test to confirm we didn't break anything.
Now our Seam is in place, so we can begin writing tests. There are two types of tests to write:
Are we calling Connector correctly?
What happens when the delegate method is called?
Let's make a Mock Object to check the first part. It's important that we call setDelegate(delegate:) before calling connect(), so let's have the mock record all calls in an array. The array gives us a way to check the call order. Instead of having the test code examine the array of calls (acting as a Test Spy which just records stuff), your test will be cleaner if we make this a full-fledged Mock Object — meaning it will do its own verification.
final class MockConnector: ConnectorProtocol {
private enum Methods {
case setDelegate(ConnectionDelegate)
case connect
}
private var calls: [Methods] = []
func setDelegate(delegate: ConnectionDelegate) {
calls.append(.setDelegate(delegate))
}
func connect() {
calls.append(.connect)
}
func verifySetDelegateThenConnect(
expectedDelegate: ConnectionDelegate,
file: StaticString = #file,
line: UInt = #line
) {
if calls.count != 2 {
fail(file: file, line: line)
return
}
guard case let .setDelegate(delegate) = calls[0] else {
fail(file: file, line: line)
return
}
guard case .connect = calls[1] else {
fail(file: file, line: line)
return
}
if expectedDelegate !== delegate {
XCTFail(
"Expected setDelegate(delegate:) with \(expectedDelegate), but was \(delegate)",
file: file,
line: line
)
}
}
private func fail(file: StaticString, line: UInt) {
XCTFail("Expected setDelegate(delegate:) followed by connect(), but was \(calls)", file: file, line: line)
}
}
(That business with passing around file and line? This makes it so that any test failure will report the line that calls verifySetDelegateThenConnect(expectedDelegate:), instead of the line that calls XCTFail(_).)
Here's how you'd use this in ConnectionServiceTests:
func test_connect_shouldMakeConnectorSettingSelfAsDelegateThenConnecting() {
let mockConnector = MockConnector()
let service = ConnectionService(makeConnector: { mockConnector })
service.connect()
mockConnector.verifySetDelegateThenConnect(expectedDelegate: service)
}
That takes care of the first type of test. For the second type, there's no need to test that Connector calls the delegate. You know it does, and it's outside your control. Instead, write a test to call the delegate method directly. (You'll still want it to make a MockConnector to prevent any calls to the real Connector).
func test_onConnected_withCertainResult_shouldDoSomething() {
let service = ConnectionService(makeConnector: { MockConnector() })
let result = ConnectionResult(…) // Whatever you need
service.onConnected(result: result)
// Whatever you want to verify
}
You could try
protocol MockConnector: Connector {
associatedType MockResult: ConnectionResult
}
Then, for each connector you need to mock, define a concrete class that conforms to this mock connector
class SomeMockConnector: MockConnector {
struct MockResult: ConnectionResult {
// Any mocked variables for this connection result here
}
// implement any further requirements from the Connector class
var delegate: ConnectionDelegate?
func connect() {
// initialise your mock result with any specific data
let mockResult = MockResult()
delegate?.onConnected(mockResult)
}
}
Does the following code demonstrate proper use of Strategy design pattern for a simple networking layer in swift 3?
Some code smells I'm unsure about:
violates Single responsibiility principle. Each strategy class such as Find, has a method for a different type of implementation. This is because I could want to find an image, or a user, or a chatroom. which are stored at different nodes in Firebase. all these different find methods are clumped together in Find class.
At the call sight of a request, if I need to make multiple async request, I nest the next request call inside the closure of the call back. Is this Ok?
The request object allows access to every type of insert, and find method. so in my signup VC I could i have the option to download a chatroom. Is even having access to that kind of implementation bad?
I have posted the code below, and left out all the actual implementation for brevity.
Any tips or guidance is much appreciated!
// USE CASE: Would go in viewDidLoad of ViewController
func testMyRequest () {
let myRequest = Request(insert: Insert(), find: Find())
myRequest.find?.user(with: "id", handler: { (user) in
myRequest.find?.nearbyUsers(user: user, handler: { (users) in
// update collectionView datasource
})
})
}
// Is this protocol necessary?
protocol RequestProtocol {
// - Family of algorithms, related actions.
var insert: Insert? { get set }
var find: Find? { get set }
}
// ---------------------------
class Request: RequestProtocol {
var insert: Insert?
var find: Find?
init(insert: Insert?, find: Find?) {
self.insert = insert
self.find = find
}
}
// Use a singleton maybe for the classes below? Why wouldn't I?
class Insert {
init() { }
func user(_ user: User) {
// insert user to firebase implementation
}
func message(_ message: Message) -> Void {
// insert message to firebase impelmentation
}
func image(data: Data, user: User) {
// insert image to firebase impelmentation
}
}
class Find {
init() { }
func user(with id: String, handler: #escaping (_ user: User) -> Void ) {
// find user implementation
}
func allChatrooms(handler: #escaping ([Chatroom]) -> Void) {
// find all chatrooms implementation
}
func nearbyUsers(user: User, handler: #escaping ([User]) -> Void ) {
// find nearby Users relative to current User location implementation
}
// Private helper method
private func findChatPartners (currentUser: User, chatrooms: [Chatroom] ) -> Set<String> {
}
}
I'm trying to create a way to build compassable objects in Swift. I feel like I'm almost there with what I have but it's still not 100% correct.
What I'm aiming for is to have a FlowController object that can create our UIViewControllers and then give them any of the dependencies that they need.
What I'd also like to do is make this work as loosely as possible.
I have a small example here that works but is not ideal. I'll explain...
Here are two objects that can be used as components... Wallet and User.
class Wallet {
func topUp(amount: Int) {
print("Top up wallet with £\(amount)")
}
}
class User {
func sayHello() {
Print("Hello, world!")
}
}
We then define a Component enum that has cases for each of these...
enum Component {
case Wallet
case User
}
... And a protocol that defines a method requiresComponents that returns an array of Components.
This is where the problem arises. In order for the "factory object" to put the components into a Composable object we need to define the user and wallet properties in the protocol also.
protocol Composable {
var user: User? {get set}
var wallet: Wallet? {get set}
func requiresComponents() -> [Component]
}
In an attempt to make these properties "optional" (not Optional) I have defined an extension to the Composable protocol that defines these vars as nil.
extension Composable {
var user: User? {
get {return nil}
set {}
}
var wallet: Wallet? {
get {return nil}
set {}
}
}
Now I declare the class that I want to make Composable. As you can see it requires the User component and declares the variable.
class SomeComposableClass: Composable {
var user: User?
func requiresComponents() -> [Component] {
return [.User]
}
}
Now the FlowController that will create these and add the components to them. You can see here that I have had to take the object, create a local var version of it and then return the updated object. I think this is because it doesn't know the type of objects that will be conforming to the protocol so the parameter can't be mutated.
class FlowController {
func addComponents<T: Composable>(toComposableObject object: T) -> T {
var localObject = object
for component in object.requiresComponents() {
switch component {
case .Wallet:
localObject.wallet = Wallet()
print("Wallet")
case .User:
localObject.user = User()
print("User")
}
}
return localObject
}
}
Here I create the objects.
let flowController = FlowController()
let composable = SomeComposableClass()
And here I add the components. In production this would be done all inside the FlowController.
flowController.addComponents(toComposableObject: composable) // prints "User" when adding the user component
compassable.user?.sayHello() // prints "Hello, world!"
As you can see, it works here. The user object is added.
However, as you can also see. Because I have declared the vars in the protocol the composable object also has a reference to a wallet component (although it will always be nil).
composable.wallet // nil
I feel like I'm about 95% of the way there with this but what I'd like to be able to do is improve how the properties are declared. What I'd like is for that last line... composable.wallet to be a compile error.
I could do this by moving the declaration of the properties out of the protocol but then I have the problem of not being able to add the properties to any object that conforms to the Composable protocol.
What would be awesome is for the factory object to be able to add the properties without relying on the declaration. Or even have some sort of guard that says "if this object has a property call user then add the user component to it". Or something like that.
If anyone knows how I could get the other 5% of this working it would be awesome. Like I said, this works, just not in an ideal way.
Thanks :D
Hacky Edit
Hmm... As a quick tacky, horrible, "no-one-should-do-this" edit. I have changed my protocol extension to be like this...
extension Composable {
var user: User? {
get {fatalError("Access user")}
set {fatalError("Set user")}
}
var wallet: Wallet? {
get {fatalError("Access wallet")}
set {fatalError("Set waller")}
}
}
Now at least the program will crash if I try to access a variable I have not defined. But it's still not ideal.
Edit after reading Daniel's blog
OK, I think I've done what I wanted. Just not sure that it's exactly Swifty. Although, I also think it might be. Looking for a second opinion :)
So, my components and protocols have become this...
// these are unchanged
class Wallet {
func topUp(amount: Int) {
print("Top up wallet with £\(amount)")
}
}
// each component gets a protocol
protocol WalletComposing {
var wallet: Wallet? {get set}
}
class User {
func sayHello() {
print("Hello, world!")
}
}
protocol UserComposing {
var user: User? {get set}
}
Now the factory method has changed...
// this is the bit I'm unsure about.
// I now have to check for conformance to each protocol
// and add the components accordingly.
// does this look OK?
func addComponents(toComposableObject object: AnyObject) {
if var localObject = object as? UserComposing {
localObject.user = User()
print("User")
}
if var localObject = object as? WalletComposing {
localObject.wallet = Wallet()
print("Wallet")
}
}
This allows me to do this...
class SomeComposableClass: UserComposing {
var user: User?
}
class OtherClass: UserComposing, WalletComposing {
var user: User?
var wallet: Wallet?
}
let flowController = FlowController()
let composable = SomeComposableClass()
flowController.addComponents(toComposableObject: composable)
composable.user?.sayHello()
composable.wallet?.topUp(amount: 20) // this is now a compile time error which is what I wanted :D
let other = OtherClass()
flowController.addComponents(toComposableObject: other)
other.user?.sayHello()
other.wallet?.topUp(amount: 10)
This seems like a good case for applying the Interface Segregation Principle
Specifically, rather than having a master Composable protocol, have many smaller protocols like UserComposing and WalletComposing. Then your concrete types that wish to compose those various traits, would just list their "requiredComponents" as protocols they conform to, i.e:
class FlowController : UserComposing, WalletComposing
I actually wrote a blog post that talks about this more extensively and gives more detailed examples at http://www.danielhall.io/a-swift-y-approach-to-dependency-injection
UPDATE:
Looking at the updated question and sample code, I would only suggest the following refinement:
Going back to your original design, it might make sense to define a base Composing protocol that requires any conforming class to create storage for composed traits as a dictionary. Something like this:
protocol Composing : class {
var traitDictionary:[String:Any] { get, set }
}
Then, use protocol extensions to add the actual composable trait as a computed property, which reduces the boilerplate of having to create those properties in every conforming class. This way any class can conform to any number of trait protocols without having to declare a specific var for each. Here's a more complete example implementation:
class FlowController {
static func userFor(instance:UserComposing) -> User {
return User()
}
static func walletFor(instance:WalletComposing) -> Wallet {
return Wallet()
}
}
protocol Composing : class {
var traitDictionary:[String:Any] { get, set }
}
protocol UserComposing : Composing {}
extension UserComposing {
var user:User {
get {
if let user = traitDictionary["user"] as? User {
return user
}
else {
let user = FlowController.userFor(self)
traitDictionary["user"] = user
return user
}
}
}
}
protocol WalletComposing {}
extension WalletComposing {
var wallet:Wallet {
get {
if let wallet = traitDictionary["wallet"] as? Wallet {
return wallet
}
else {
let wallet = FlowController.walletFor(self)
traitDictionary["wallet"] = wallet
return wallet
}
}
}
}
class AbstractComposing {
var traitDictionary = [String:Any]()
}
Not only does this get rid of those pesky optionals you have to unwrap everywhere, but it makes the injection of user and wallet implicit and automatic. That means that your classes will already have the right values for those traits even inside their own initializers, no need to explicitly pass each new instance to an instance of FlowController every time.
For example, your last code snippet would now become simply:
class SomeComposableClass: AbstractComposing, UserComposing {} // no need to declare var anymore
class OtherClass: AbstractComposing, UserComposing, WalletComposing {} //no vars here either!
let composable = SomeComposableClass() // No need to instantiate FlowController and pass in this instance
composable.user.sayHello() // No unwrapping the optional, this is guaranteed
composable.wallet.topUp(amount: 20) // this is still a compile time error which is what you wanted :D
let other = OtherClass() // No need to instantiate FlowController and pass in this instance
other.user.sayHello()
other.wallet.topUp(amount: 10) // It all "just works" ;)
New to IOS programming but just wondering where is the best place to put functions that I would use throughout my code. For example, I want to write a few functions to perform a POST request to a web service and return a dictionary. Maybe another function to do some calculations. Is it best to create another .swift file and put all my functions there. And what would be a good name to give the file if so?
public func postRequest() -> [String:String] {
// do a post request and return post data
return ["someData" : "someData"]
}
The best way is to create a helper class with static functions, like this:
class Helper{
static func postRequest() -> [String:String] {
// do a post request and return post data
return ["someData" : "someData"]
}
}
Now every time you need to use postRequest you can just use like so: Helper.postRequest()
I usually create a separate class if I have functions that will be used by multiple classes, especially for the ones involving network operations.
If you just have separate functions that will be used, you can simply create static functions inside that class so it is easily accessible by other classes in a static way:
class DataController {
static func getData() -> [String:String] {
// do some operations
return ["someData" : "someData"]
}
}
let data = DataController.getData() // example
However, what often has been the case for me (especially if it involves more complicated operations) was that these network operations needed to establish an initial connection beforehand or required some initial setups, and they also performed asynchronous operations that needed to be controlled. If this is the case and you will often be calling such methods, you might want to create a singleton object that you could use throughout different classes and functions. This way, you could do the initial setup or establish an initial connection just once, and then do the rest as needed with the other functions, instead of doing them every time the function gets called.
Creating a singleton object is pretty simple in Swift:
class DataController {
static let sharedInstance = DataController() // singleton object
init() {
// do initial setup or establish an initial connection
}
func getData() -> [String:String] {
// do some operations
return ["someData" : "someData"]
}
}
let data = DataController.sharedInstance.getData() // example
For the name of the class, I usually name it something like DataController or DataHelper, but anything that makes sense as a "helper" class would work.
Hope this helps :)
For reusable functions it depends what I decide to use. For this specific case I use a separate file, because posting to a backend will become more complicated when the application evolves. In my app I use a backend class, with all kinds of helper classes:
struct BackendError {
var message : String
}
struct SuccessCall {
var json : JSON
var containsError : Bool {
if let error = json["error"].string {
return true
}
else {
return false
}
}
}
typealias FailureBlock = (BackendError) -> Void
typealias SuccessBlock = (SuccessCall) -> Void
typealias AlamoFireRequest = (path: String, method: Alamofire.Method, data: [String:String]) -> Request
typealias GetFunction = (path: String , data: [String : String], failureBlock: FailureBlock, successBlock: SuccessBlock) -> Void
class Backend {
func getRequestToBackend (token: String )(path: String , data: [String : String], failureBlock: FailureBlock, successBlock:
}
For other cases I often use extensions on Swift classes. Like for getting a random element from an Array.
extension Array {
func sampleItem() -> T {
let index = Int(arc4random_uniform(UInt32(self.count)))
return self[index]
}
}
This very old question but I would like to chirp some more points.
There are a few option, basically you can write your utility functions in Swift -
A class with static function. For example
class CommonUtility {
static func someTask() {
}
}
// uses
CommonUtility.someTask()
Also, you can have class method's as well instead of static method but those functions can be overridden by subclasses unlike static functions.
class CommonUtility {
class func someTask() {
}
}
// uses
CommonUtility.someTask()
Secondly, you can have Global functions as well, that are not part of any class and can be access anywhere from your app just by name.
func someTask() {
}
Though, selecting one over other is very subjective and I thing this is ok to make a class with static function in this particular case, where you need to achieve networking functionality but if you have some functions which perform only one task than Global function is a way to go because Global functions are more modular and separate out single tasks for a single function.
In case of static functions, if we access one of the static member, entire class gets loaded in memory. But in case of global function, only that particular function will be loaded in mem
You can create a separate swift class, might name it WebServicesManager.swift, and write all methods related to web requests in it.
You can use class methods, or singleton pattern to access the methods.