简体   繁体   English

在结构上使用 Swift 协议委托来更改值?

[英]Using Swift protocol delegation on a struct to change values?

I have a project where I want there are factories with orders (an array of Ints ) that can be mutated.我有一个项目,我希望有可以变异的orders (一个Ints数组)的factories

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.我希望另一个 class 中的所有代码变异、添加、删除、验证等订单(即:几乎像代理模式),并在准备好时用新订单更新工厂。

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注意:我知道这是因为工厂是一个struct并且它是一个值类型

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: Output:

Book.orders = [7, 8, 1] Book.orders = [7, 8, 1]

Shop.orders = [1, 2, 3] Shop.orders = [1, 2, 3]

Again, I know the reason is because I've declared factory to be a struct ;同样,我知道原因是因为我已将 factory 声明为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;如果没有,我将其更改为 class; but I appreciate any feedback on this.但我很感激对此的任何反馈。

With thanks感谢

There are 2 problems with your code, both of which needs fixing for it to work:您的代码存在 2 个问题,这两个问题都需要修复才能正常工作:

  • using a value type使用值类型
  • not setting the delegate不设置委托

Once you set the delegate, you'll see ordersDidUpdate actually getting called, but shop.orders will still have its original value.设置委托后,您将看到ordersDidUpdate实际被调用,但shop.orders仍将具有其原始值。 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 .这是因为一旦你改变了你的FactoryOrderBook上的delegate集将与变异的Factory不同的 object ,后者在委托调用ordersDidUpdate中更新。

Using a reference type fixes this issue.使用引用类型可解决此问题。

Couple of things to keep in mind when you switch to a class delegate.切换到class代表时要记住几件事。 Make your OrderUpdatedDelegate be a class-bound protocol, then remove mutating from the function declaration.使您的OrderUpdatedDelegate成为类绑定协议,然后从 function 声明中删除mutating And most importantly, always declare class-bound delegates as weak to avoid strong reference cycles.最重要的是,始终将类绑定委托声明为weak ,以避免强引用循环。

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)")

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.正如您所说,由于Factory是一个结构,因此在设置OrderBook delegate时,它已经复制到那里,因此该delegate实际上是您原始工厂实例的副本。

A class is the appropriate solution for this. class是适合此问题的解决方案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM