Использование делегирования протокола Swift в структуре для изменения значений? - PullRequest
0 голосов
/ 16 июня 2020

У меня есть проект, в котором я хочу, чтобы factories с orders (массив Ints) можно было изменять.

Я хочу, чтобы весь код изменялся, добавлялся, удалялся, проверялся , et c заказов в другом классе (ie: почти как шаблон прокси) и когда будет готов обновить фабрику с новыми заказами.

Я следую шаблону делегата, чтобы отбросить новые заказы обратно в завод для обновления, однако заводские заказы никогда не обновляются.

Примечание: я знаю, что это потому, что завод - это struct и что это тип значения

Мне интересно, можно ли обновить структуру с помощью шаблона делегата; или я должен изменить его на ссылочный тип (класс), чтобы решить проблему.

В следующем коде я исключил все проверки, pu sh, pop и другие функции, и я чтобы упростить этот запрос, принудительно изменив массив заказов, а затем используя делегата, чтобы отбросить измененные заказы.

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

Вывод:

Book.orders = [7 , 8, 1]

Shop.orders = [1, 2, 3]

Опять же, я знаю, что причина в том, что я объявил factory как struct ; но мне интересно, можно ли использовать шаблон делегата для изменения массива заказов в структуре?

Если нет, я заменю его на класс; но я ценю любые отзывы по этому поводу.

С благодарностью

Ответы [ 2 ]

1 голос
/ 16 июня 2020

В вашем коде есть 2 проблемы, обе из которых нужно исправить, чтобы он работал:

  • с использованием типа значения
  • без установки делегата

После установки делегата вы увидите, что на самом деле вызывается ordersDidUpdate, но shop.orders все равно будет иметь свое исходное значение. Это потому, что как только вы измените свой Factory, delegate, установленный на OrderBook, будет отличаться от измененного Factory, который был обновлен при вызове делегата ordersDidUpdate.

Использование ссылочного типа устраняет эту проблему.

Несколько вещей, о которых следует помнить, когда вы переключаетесь на делегата class. Сделайте ваш OrderUpdatedDelegate протоколом с привязкой к классу, затем удалите mutating из объявления функции. И, что наиболее важно, всегда объявляйте делегаты с привязкой к классу как 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)")
1 голос
/ 16 июня 2020

Как вы сказали, поскольку Factory является структурой, при настройке OrderBook delegate он уже скопирован туда, поэтому delegate фактически является копией вашего исходного экземпляра factory.

A class является подходящим решением для этого.

...