Reputation: 1651
I have a project where I want there are factories
with orders
(an array of Ints
) that can be mutated.
I want all the code mutating, adding, removing, validating, etc of orders in another class (ie: almost like a proxy pattern) and when ready update the factory with the new orders.
I follow a delegate pattern to kick the new orders back to the factory for updating, however the factory orders never update.
Note: I know this is because the factory is a struct
and that it is a value type
I am wondering if its possible to update the struct using a delegate pattern; or must I change it to a reference type (a class) in order to resolve the issue.
In the following code I've stripped out all the validation, push, pop and other features and am keeping it simple for this query by force changing the order array and then using a delegate to kick back the changed orders.
// Swift playground code
protocol OrderUpdatedDelegate {
mutating func ordersDidUpdate(_ orders: [Int])
}
// This class will handle all the validation to do with
// orders array, but for now; lets just force
// change the orders to test the delegate pattern
class OrderBook {
var delegate: OrderUpdatedDelegate?
var orders: [Int] = [Int]()
init(orders: [Int]) {
self.orders = orders
}
func changeOrders() {
self.orders = [7,8,1]
print ("updated orders to -> \(orders)")
delegate?.ordersDidUpdate(orders)
}
}
struct Factory {
var orders: [Int] = [Int]()
init(orders: [Int]) {
self.orders = orders
}
}
extension Factory: OrderUpdatedDelegate {
mutating func ordersDidUpdate(_ orders: [Int]) {
print ("recieved: \(orders)")
self.orders = orders
}
}
var shop = Factory(orders: [1,2,3])
let book = OrderBook.init(orders: shop.orders)
book.changeOrders()
print ("\nBook.orders = \(book.orders)")
print ("Shop.orders = \(shop.orders)")
Output:
Book.orders = [7, 8, 1]
Shop.orders = [1, 2, 3]
Again, I know the reason is because I've declared factory to be a struct
; but I'm wondering if its possible to use a delegate pattern to mutate the orders array within the struct?
If not, I'll change it to a class; but I appreciate any feedback on this.
With thanks
Upvotes: 0
Views: 1711
Reputation: 54755
There are 2 problems with your code, both of which needs fixing for it to work:
Once you set the delegate, you'll see ordersDidUpdate
actually getting called, but shop.orders
will still have its original value. That is because as soon as you mutate your Factory
, the delegate
set on OrderBook
will be a different object from the mutated Factory
, which was updated in the delegate call ordersDidUpdate
.
Using a reference type fixes this issue.
Couple of things to keep in mind when you switch to a class
delegate. Make your OrderUpdatedDelegate
be a class-bound protocol, then remove mutating
from the function declaration. And most importantly, always declare class-bound delegates as weak
to avoid strong reference cycles.
protocol OrderUpdatedDelegate: class {
func ordersDidUpdate(_ orders: [Int])
}
// This class will handle all the validation to do with
// orders array, but for now; lets just force
// change the orders to test the delegate pattern
class OrderBook {
weak var delegate: OrderUpdatedDelegate?
var orders: [Int] = []
init(orders: [Int]) {
self.orders = orders
}
func changeOrders() {
self.orders = [7,8,1]
print ("updated orders to -> \(orders)")
delegate?.ordersDidUpdate(orders)
}
}
class Factory {
var orders: [Int] = []
init(orders: [Int]) {
self.orders = orders
}
}
extension Factory: OrderUpdatedDelegate {
func ordersDidUpdate(_ orders: [Int]) {
print("receieved: \(orders)")
self.orders = orders
print("updated order: \(self.orders)")
}
}
var shop = Factory(orders: [1,2,3])
let book = OrderBook(orders: shop.orders)
book.delegate = shop
book.changeOrders()
print ("Book.orders = \(book.orders)")
print ("Shop.orders = \(shop.orders)")
Upvotes: 2
Reputation: 13713
As you said since Factory
is a struct, when setting OrderBook
delegate
its already copied there so the delegate
is actually a copy of your original factory instance.
A class
is the appropriate solution for this.
Upvotes: 1