【问题标题】:How to use a value type object as a reference type?如何使用值类型对象作为引用类型?
【发布时间】:2017-06-09 13:31:40
【问题描述】:

在我的模型中,我有一些数组:

var thisArray = [Object]
var thatArray = [Object]
var anotherArray = [Object]

在我的视图控制器中,我想打开一个值来确定我将附加到哪个数组:

var whichArray: [Object]!
switch someValue {
    case .thisArray: whichArray = thisArray
    case .thatArray: whichArray = thatArray // "He went thatArray!"
    case .anotherArray: whichArray = anotherArray
}
whichArray.append(object)

但这当然行不通,因为 Array 是一种值类型。

有没有办法做到这一点?当然我可以做到以下几点:

switch someValue {
    case .thisArray: thisArray.append(object)
    case .thatArray: thatArray.append(object)
    case .anotherArray: anotherArray.append(object)
}

但这太不优雅和多余了!如果周围的代码中还有其他更复杂的事情发生,那就更是如此了。

这里有解决办法吗?是否可以创建对值类型的引用?

PS。更好的是,虽然确实是它自己的问题,但我是否可以使用案例的 name(例如,someValue = .thisArray 的“thisArray”)按名称设置数组(即,避免整个switch 语句,只需说objectName.append(object) 或类似的东西),但据我所知,这不是一回事。或者这可能吗?也许今天是我的生日?

【问题讨论】:

标签: swift


【解决方案1】:

由于Arrays值类型 - 正如您自己所说的那样 - 它们不能作为参考传递(或分配)。一种解决方案是为Array 创建一个包装类,然后它本身就是一个引用类型。然后,您可以分配这个包装类而不是数组本身。

现在,鉴于您还说过您可能更喜欢通过名称访问 Arrays 并完全摆脱 switch,您可以将设计更改为将 thisArraythatArrayanotherArray 存储在一个Dictionary,其中的键是someValue 的不同值。

这样您就可以简单地附加到所需的数组:

arrayDict[someValue]?.append(object)

(假设您事先已经正确设置了字典)

例如这样:

enum Value {
    case thisArray
    case thatArray
    case anotherArray
}

var arrayDict = [
    Value.thisArray : [String](),
    Value.thatArray : [String](),
    Value.anotherArray : [String]()
]

arrayDict[.thatArray]?.append("Some String.")

为了创建一个简短的工作示例,我将 Object 替换为 String 但这显然无关紧要。

【讨论】:

    【解决方案2】:

    我通常建议使用闭包来解决这个问题。它更强大,更安全。例如:

    let append: (Object) -> Void
    
    switch someValue {
    case .thisArray: append = { thisArray.append($0) }
    case .thatArray: append = { thatArray.append($0) }
    case .anotherArray: append = { anotherArray.append($0) }
    }
    
    append(object)
    

    (这里最好只说append = thisArray.append,但你现在不能在 Swift 中这样做。这是“变异函数的部分应用”,目前不合法。)

    【讨论】:

    • 与 OP 的第二个版本(立即附加到交换机内的数组)相比,这种方法是否还有另一个好处,除了这让您可以多次附加到同一个“选择”数组与append(object)?安全福利?还是您的意思是与UnsafeMutablePointer 方法相比更安全
    • @Keiwan 作为一种方法,它允许您进行任何操作。所以它不必是一个特定的数组。它可以添加到多个数组中,插入到一个集合中,或者是一个空操作。
    【解决方案3】:

    尽管 Swift 旨在减少指针操作,但指针仍然可用:

    var thisArray = [1,2,3]
    var thatArray = [4,5,6]
    var anotherArray = [7,8,9]
    var ptr: UnsafeMutablePointer<[Int]>
    
    let someValue = 2
    switch someValue {
        case 1: ptr = UnsafeMutablePointer(&thisArray)
        case 2: ptr = UnsafeMutablePointer(&thatArray)
        default: ptr = UnsafeMutablePointer(&anotherArray)
    }
    
    ptr.pointee.append(42)
    print(thatArray) // [4,5,6,42]
    

    对此的一个小烦恼是您必须调用ptr.pointee 才能访问目标数组。如果将指针分配给另一个变量(即let whichArray = ptr.pointee),对whichArray 的任何修改都不会反映在原始数组中。

    (我必须将您的 Object 类型更改为 Int 以便它在 IBM Swift Sandbox 中运行)

    【讨论】:

    • 这在 IMO 有点危险。不能保证数组在 switch 语句结束后仍然有效。允许 Swift 在最后一次直接引用它们之后释放它们。如果您通过其他方式知道它们的生命周期(如果已知它们是当前对象的属性),那么您可以侥幸逃脱,但我认为您在这里没有任何承诺。你真的应该使用withExtendedLifetime,这使它变得更加复杂。
    • "如果将指针分配给另一个变量(即 let whichArray = ptr.pointee),对 whichArray 的任何修改都不会反映在原始数组中。"正是因为这个问题,我才找到了这个问题和你的答案。我曾经(愚蠢地?)假设我可以将指针值分配给一个变量,并且在处理具有近 10 个字段的结构时不必说 .pointee this 和 .pointee that。有什么办法可以避免这种相当丑陋的语法吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-17
    • 1970-01-01
    相关资源
    最近更新 更多