Array&的地址删除(at :) IOS

时间:2018-05-10 22:46:50

标签: arrays swift

我通过ViewControllers之间的引用传递特定模型的数组。

如果我更改了数组中特定元素的任何值,它在所有ViewControllers中都能很好地反映,但是当我从该数组中删除一个元素时,它不会反映给其他控制器。

remove(at: )函数是否创建新数组并引用另一个地址?

如果是这样,如何删除元素而不更改数组的地址,以便它可以在其他视图控制器上反映这种变化?

2 个答案:

答案 0 :(得分:0)

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用于存储模型的内容。

答案 1 :(得分:0)

如果您需要通过引用传递数组(或任何其他值类型),您可以通过一个中间结构来管理您的间接。

[EDIT]已更改为使用Swift 4中提供的KeyPath。

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