Andrea Miotto Andrea Miotto - 3 months ago 18
Swift Question

Swift: Why is this immutable?

Can you tell me why this code does not work?

I have several arrays of

[AnyObject]
that contain UILabels and UITextForm.
This
func
should take as parameter an array and make all the labels and the text form disabled. I've tried with map, but still i have the same problem, the compiler tells me that or the variable is a constant or that is immutable.

func disableSectionForm(formSection section: inout [AnyObject]) {
for i in 0...section.count {
if section[i] is UILabel || section[i] is UITextField {
section[i].isEnabled = false
}
}
}

Answer

There are many compile errors here

Issue #1 (this is just a suggestion)

inout is not needed here because you are not mutating the section array, you are mutating the objects inside it instead.

Issue #2

The inout should go before the param name (if you are using Swift 2.2)

Issue #3

You should use self when comparing with dynamicType

Issue #4

You can't write section[i].isEnabled = false because AnyObject has no member isEnabled so you should do a cast

Issue #5

You are accessing an index outside of your array so this

0...section.count

should become this

0..<section.count

Code Version #1

Now your code looks like this

func disableSectionForm(formSection section: [AnyObject]) {
    for i in 0..<section.count {
        if section[i].dynamicType == UILabel.self {
            (section[i] as? UILabel)?.enabled = false
        } else if section[i].dynamicType == UITextField.self {
            (section[i] as? UITextField)?.enabled = false
        }
    }
}

Test

let a = UILabel()
a.enabled = true
var list: [AnyObject] = [a]
disableSectionForm(formSection: list)
print(list.first?.enabled) // false

Code Version #2

Since:

  1. you can iterate your elements in a safer way
  2. you should use conditional cast instead of dynamicType comparation

you can write

func disableSectionForm(formSection section: [AnyObject]) {
    section.forEach {
        switch $0 {
        case let label as UILabel: label.enabled = false
        case let textField as UITextField: textField.enabled = false
        default: break
        }
    }
}

Code Version #3

Let's define a protocol to represents classes with an enabled Bool property.

protocol HasEnabledProperty:class {
    var enabled: Bool { get set }
}

Let's conform to it UILabel and UITextLabel

extension UILabel: HasEnabledProperty { }
extension UITextField: HasEnabledProperty { }

And finally...

func disableSectionForm(formSection section: [AnyObject]) {
    section.flatMap { $0 as? HasEnabledProperty }.forEach { $0.enabled = false }
}