【问题标题】:Swift - unable to access typealias properties once setSwift - 设置后无法访问 typealias 属性
【发布时间】:2020-01-22 15:06:15
【问题描述】:

我有大量使用名为“SheetField”的类创建的 UIView 对象。

对象通常在整个应用程序中初始化如下:

objectx = SheetField(title: "example", value: "example")

我需要为这些对象添加一个附加属性“字母”以在应用程序的一部分中访问,因此我创建了一个类型别名,如下所示:

typealias NewSheetField = (field: SheetField, letter: String?)

因此,我将这些字段对象声明如下:

private var fieldX: NewSheetField
private var fieldY: NewSheetField   
private var fieldZ: NewSheetField

我这样初始化它们:

fieldX = NewSheetField(field: SheetField(title: "example", value: "example"), letter: nil)
fieldY = NewSheetField(field: SheetField(title: "example", value: "example"), letter: nil)
fieldZ = NewSheetField(field: SheetField(title: "example", value: "example"), letter: nil)

然后我想为这些字段分配特定的字母。所以,我有一本字母字典:

private let letters = [0: "A", 1: "B", 2: "C", 3: "D", 4: "E", 5: "F", 6: "G", 7: "H"]

还有一个循环来应用字母值:

func createLettersForFields(fields: [NewSheetField]) {
    for (index, var f) in fields.enumerated() {
        if let letterToAdd = letters[index] {
            f.letter = letterToAdd
        }
    }
}

所以我这样调用函数:

createLettersForFields(fields: [fieldX, fieldY, fieldZ]

但是,我似乎无法正确分配字母。我在循环中添加了几个打印语句:

func createLettersForFields(fields: [NewSheetField]) {
    for (index, var f) in fields.enumerated() {
        if let letterToAdd = letters[index] {
            f.letter = letterToAdd
            print("\(f.letter)")
            print("\(fieldX.letter)") 
        }
    }
}

循环显然每次都能很好地打印出 f.letter(f 是我们传入的字段),但它根本不会打印出特定的字段字母 - 值始终为 nil。我所期望的是 print("(fieldX.letter)") 将打印 nil 直到循环命中 fieldX 字段,然后将打印分配的值。显然 print 语句并不重要,但它解释了为什么我无法在需要它的其他函数中访问 fieldX.letter。

任何帮助将不胜感激。

更新:

我在循环中添加了一个条件语句如下:

if f == fieldX {
print("TEST")
}

并在此条件中添加了一个断点。我从来没有这么清楚地打过这部分我在这里使用的'f'不等于我正在初始化的字段......但是当我从函数中打印'f'并从init中打印'fieldX'时,它们似乎是同一个对象:

PRINTED FROM METHOD: (field: <SheetField: 0x125e56240; frame = (0 0; 0 0); layer = <CALayer: 0x2824c70a0>>, letter: Optional("A"))

PRINTED FROM INIT : (field: <SheetField: 0x125e56240; frame = (0 0; 0 0); layer = <CALayer: 0x2824c70a0>>, letter: nil)

更新 2:

奇怪的事情发生了!我简化了for循环,去掉了枚举部分:

func createLettersForFields(fields: [NewSheetField]) {
    for var field in fields {
        if field == fieldX {
            fieldX.letter = "A"
        }
    }
}

这有效并将'A'分配给fieldX。当我记录 fieldX.letter 时,我得到“A”。但是,当我将 'fieldX' 换成 'field' 时,它仍然不会分配:

func createLettersForFields(fields: [NewSheetField]) {
    for var field in fields {
        if field == fieldX {
            field.letter = "A"
        }
    }
}

这里,打印日志返回 nil。 当它到达 field.letter = "A" 时,肯定是 fieldX !

【问题讨论】:

    标签: swift xcode for-loop swift5 type-alias


    【解决方案1】:

    你陷入了价值类型陷阱

    在这一行

    for (index, var f) in fields.enumerated() {
    

    ffields 的副本,参数数组和对象fieldXfieldYfieldZ 保持不变。你难道不奇怪你没有收到关于fields cannot be modified because it is a constant的错误吗?

    即使是数组[fieldX, fieldY, fieldZ] 中的字段也是这三个字段的副本。

    如果保留对原始对象的引用至关重要,请使用引用类型的类。

    否则您必须将数组创建为变量,将其作为inout 传递并直接修改数组中的项目。请注意,枚举中的element 未使用,因为您必须将letterToAdd 直接分配给数组中的项目

    由于letter 是可选的,因此可选绑定是多余的

    private var fieldX = NewSheetField(field: SheetField(title: "example", value: "example"), letter: nil)
    private var fieldY = NewSheetField(field: SheetField(title: "example", value: "example"), letter: nil)
    private var fieldZ = NewSheetField(field: SheetField(title: "example", value: "example"), letter: nil)
    
    private let letters = [0: "A", 1: "B", 2: "C", 3: "D", 4: "E", 5: "F", 6: "G", 7: "H"]
    
    func createLettersForFields(fields: inout [NewSheetField]) {
        for (index, _) in fields.enumerated() {
            fields[index].letter = letters[index]
        }
    }
    
    var theFields = [fieldX, fieldY, fieldZ]
    createLettersForFields(fields: &theFields)
    print(theFields)
    

    请注意,即使采用这种方式,private var fieldX/Y/Z 的内容也不会改变。

    【讨论】:

    • 非常感谢!我有一种感觉,这与值与引用类型有关,但只是无法弄清楚。感谢您的帮助!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-14
    • 2021-03-02
    • 1970-01-01
    • 1970-01-01
    • 2014-11-10
    • 2014-09-19
    相关资源
    最近更新 更多