Адрес Array & Remove (по адресу :) IOS - PullRequest
0 голосов
/ 11 мая 2018

Я передаю массив определенной модели по ссылке между ViewControllers.

Если я изменяю любое значение определенного элемента в массиве, оно хорошо отражается во всех ViewControllers, но когда я удаляю элемент из этогомассив, который не отражается на других контроллерах.

Создает ли функция remove(at: ) новый массив и ссылается на другой адрес?

А если так, как удалить элемент без изменения адреса массива, чтобы он мог отражать это изменение на других контроллерах представления?

Ответы [ 2 ]

0 голосов
/ 11 мая 2018

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

[ПРАВКА] изменено для использования KeyPaths, доступных в Swift 4.

// Generic class to hold a "weak" reference to a property from an object
// including properties that are valued types such as arrays, structs, etc.
// This is merely an encapsulation of Swift's native KeyPath feature
// to make the code a bit more readable and simpler to use
//
class ReferenceTo<ValueType> { var value:ValueType! { get { return nil} set {} } }
class Reference<OwnerType:AnyObject,ValueType>:ReferenceTo<ValueType>
{  
   internal weak var owner:OwnerType!
   internal var property:ReferenceWritableKeyPath<OwnerType,ValueType>! = nil
   internal var valueRef:KeyPath<OwnerType,ValueType>! = nil

   init(_ owner:OwnerType, _ property:ReferenceWritableKeyPath<OwnerType,ValueType>)
   { (self.owner,self.property) = (owner,property) }

   init(_ owner:OwnerType, get valueRef:KeyPath<OwnerType,ValueType>)
   { (self.owner,self.valueRef) = (owner,valueRef) }

   override var value:ValueType! 
   { 
     get { return valueRef != nil ? owner?[keyPath:valueRef] : owner?[keyPath:property] }
     set { owner?[keyPath:property] = newValue }
   }
}

С помощью этого универсального класса вы можете создавать ссылки на свойства ценного типа экземпляров объекта и манипулировать ими в любом месте вашего кода, как если бы свойство ценного типа было ссылочным типом.

// Example class with a read/write and a read-only property:
class MyObject
{
   var myArray = [1,2,3,4]
   var total:Int { return myArray.reduce(0,+) }
}
var instance:MyObject! = MyObject()

// create a reference to the array (valued type)
// that can be used anywhere and passed around as a parameter
let arrayRef = Reference(instance, \.myArray)

// the value is accessed and manipulated using the
// "value" property of the reference
arrayRef.value.remove(at:2)
arrayRef.value.append(5)
print(instance.myArray) // [1,2,4,5]

// Read-only properties can also be manipulated as
// references
let valueRef = Reference(instance, get:\.total)
print(valueRef.value) // 12

Класс Reference позволяет передавать значение в качестве ссылки на параметры функции

// a function that expects a reference to an array
// would be declared as follows
func changeArray(_ array:ReferenceTo<[Int]>)
{ array.value.insert(9, at: 1) }

// the reference can also be used as an inout parameter
func shift(_ array:inout [Int])
{ array = Array(array.dropFirst()) + Array(array.prefix(1)) }

changeArray(arrayRef)
shift(&arrayRef.value!)
print(instance.myArray) // [9,2,4,5,1]

...

// the reference uses a weak link to the owner
// of the referenced property or value
// so there will be no strong reference cycle issues even
// if the reference is used in an object held strongly 
// by the owner itself
instance = nil
print(arrayRef.value) // none ... no more value after the owner is gone
0 голосов
/ 11 мая 2018

Swift Arrays - это типы значений (в частности, массив - это структура), а не ссылочные типы, поэтому вы ошибаетесь, когда говорите, что «передаете массив конкретной модели по ссылке между контроллерами представления».В качестве значения можно передавать только массив Swift.

Массивы, как и другие структуры, имеют семантику копирования при изменении.Как только вы измените сам массив , будет сделана копия и изменение будет сделано в копии.

Теперь в вашем случае массив содержит ссылок на модельобъекты;Когда вы обновляете объект модели, вы изменяете сам объект, а не ссылку, хранящуюся в массиве, поэтому вы видите изменение, отраженное во всех ваших контроллерах представления.

Аналогией может быть разница между добавлением дома к улице (которая меняет саму улицу) и изменением жильцов существующего дома на улице.

Я бы предложил вам реализоватьобъект модели, обеспечивающий абстрагирование от базового массива, чтобы у вас был более качественный код и избежать проблемы со ссылками на массивы.

Один из подходов может выглядеть примерно так:

struct MyModel {
    let name: String
    let size: Int
}

class MyData {
    private var _models = [MyModel]()

    var models: [MyModel] {
        return _models
    }

    func insert(model: MyModel) {
        self._models.append(model)
    }

    func removeModel(at: Int) {
        guard at >= 0 && at < _models.count else {
            return
        }

        self._models.remove(at: at)
    }
}

Хотя это не такидеал, поскольку он все еще требует, чтобы модельные потребители знали индексы в базовом массиве.Я бы предпочел что-то вроде этого:

struct MyModel: Hashable {
    let name: String
    let size: Int
}

class MyData {
    private var _models = [MyModel]()

    var models: [MyModel] {
        return _models
    }

    func insert(model: MyModel) {
        self._models.append(model)
    }

    func remove(model: MyModel) -> Bool {
        if let index = self._models.index(of: model) {
            _models.remove(at: index)
            return true
        } else {
            return false
        }
    }
}

Теперь мне не нужно знать, что внутренняя коллекция MyData использует для хранения моделей.

...