[SOLVED] How to iterate through subviews in Swift for macOS and return object types


After finding this question and answers, I thought I would try to reduce the size of my code considerably by looping through various objects in the view and set parameters.

I cannot use the tag value because I do not set tags, except in rare circumstances. I set plain language identifiers for all of my UI elements. I will use NSTextField as an example to try and set the delegate for each NSTextField in the view.

import Cocoa

class ViewController: NSViewController, NSTextFieldDelegate {

    @IBOutlet var myTextField1: NSTextField!
    // ... and many, many more NSTextFields ...

    override func viewDidLoad {

        let textFields = self.view.subviews.filter { $0.isKind(of: NSTextField.self) } 
        for textField in textFields {
            if textField.identifier!.rawValue[textField.identifier!.rawValue.startIndex] != "_" { // Avoiding Swift assigned identifiers
                textField.delegate = self

I am being told that Value of type 'NSView' has no member 'delegate', which makes sense because the NSView of the NSTextField is what is actually being placed into the list, not the actual NSTextField object.

Since IBOutlet Collections aren’t available for macOS, I can’t simply iterate through a collection to do what I want to do. At least as a far as I know of.


I assume the goal is to get textFields to have type [NSTextField].

Right now, you have filter with is (which doesn’t change type)

let textFields = self.view.subviews.filter { $0.isKind(of: NSTextField.self) }

You should change this to compactMap with as? (which does change type).

let textFields = self.view.subviews.compactMap { $0 as? NSTextField }

Answered By – TheLivingForce

Answer Checked By – David Marino (BugsFixing Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *