Creating a function with For Loop

array

(Bruno) #1

Dears,
How can I create a function to perform a FOR in LOOP in some specified arrays, and present the values in some UILabels?

Basically, I have a file called Themes.swift, with the following content:
class Themes: UITableViewCell {

struct LabelTheme {
    let color: UIColor
    let font: UIFont
    
    static let menuOption = LabelTheme(color: .white, font: UIFont.systemFont(ofSize: 26))
    static let type2 = LabelTheme(color: .yellow, font: UIFont.italicSystemFont(ofSize: 26))
    static let type3 = LabelTheme(color: .black, font: UIFont.systemFont(ofSize: 26))
    
    func set(to label: UILabel) {
        label.textColor = color
        label.font = font
    }
}

struct LabelContent {
    let text: String
    let theme: LabelTheme
    
    func set(to label: UILabel) {
        label.text = text
        theme.set(to: label)
    }
}

}

In the other file, called: Contents.Swift, I have
import UIKit

class Contents: Themes {
static let navContent = [
LabelContent(text: "NAV IDENT", theme: .menuOption),
LabelContent(text: "WPT LIST", theme: .menuOption),
LabelContent(text: "WPT LIST1", theme: .menuOption),
LabelContent(text: "WPT LIST2", theme: .menuOption),
LabelContent(text: "WPT LIST3", theme: .menuOption),
LabelContent(text: "WPT LIST4", theme: .menuOption),
LabelContent(text: "WPT LIST5", theme: .menuOption),
LabelContent(text: "WPT LIST6", theme: .menuOption),
LabelContent(text: "WPT LIST7", theme: .menuOption),
LabelContent(text: "WPT LIST8", theme: .menuOption),
LabelContent(text: "WPT LIST9", theme: .menuOption),
LabelContent(text: "WPT LIST10", theme: .menuOption),
]

}

And, on the view controller I have the following code:
import UIKit

class ViewController: UIViewController {

@IBOutlet var lbLeft: [UILabel]!
@IBOutlet var lbRight: [UILabel]!


override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}


@IBAction func btnRadio(_ sender: UIButton) {

    var itemsLabelLeft: Int = 1
    var itemsLabelRight: Int = 1
    
    for items in 0...Contents.navContent.count-1 {
        
        switch items {
        case 0...5:
            lbLeft[itemsLabelLeft].text = Contents.navContent[items].text
            itemsLabelLeft += 2
        case 6...11:
            lbRight[itemsLabelRight].text = Contents.navContent[items].text
            itemsLabelRight += 2
        default:
            print("nah")
        }
        
    }
}

}

But, once I'll have to perform the same FOR FUNCTION above, a lot of times, I think it's better to create a function. I would like to create a function, where I could pass the array's name (I'll have a lot of arrays, similar of that mentioned above, with different contents), and the code would fill the labels as it's doing with the code provided above.

How can I do it?
Thank you


(Quinn “The Eskimo!”) #2

I’m not quite sure I’ve interpreted your requirements correctly — so please correct me if I’m wrong — but I believe you can tidy up this code by adding a function like this:

func apply(content: ArraySlice<LabelContent>, to labels: [UILabel]) {
    for (offset, content) in content.enumerated() {
        labels[offset * 2 + 1].text = content.text
    }
}

and then calling it like this:

apply(content: Contents.navContent[0..<6], to: lbLeft)
apply(content: Contents.navContent[6..<12], to: lbRight)

There’s a bunch of subtle stuff here:

  • The apply(content:to:) takes an array slice, because that’s what the subscript at the call site generates.

  • The enumerated method on a sequence returns a sequence of pair tuples, where:

    • The first item is the offset into the sequence (it always starts at 0, even if the first index isn’t 0).

    • The second item is the corresponding element of the sequence.

    The for loop unpacks that into offset and content, which makes the body of the loop pretty clean.

  • The body of the for loop calculates the index into the label array by multiplying by 2 (you seem to only set every other item) and then adding 1 (you start at item 1, not item 0).

Give this a whirl and do let me know if I missed something.

Share and Enjoy

Quinn “The Eskimo!” @ DTS @ Apple


(Bruno) #5

That's exactly what I was looking for.

I've made just a small adaption to clear the unused labels on my view, as you can see below:
public func apply(content: ArraySlice, to labels: [UILabel]) {

    for index in 0..<labels.count {
        labels[index].text = ""
    }
    
    for (offset, content) in content.enumerated() {
        labels[offset * 2 + 1].text = " "
        labels[offset * 2 + 2].text = content.text
    }
}

Is there any way to start this "filling process" by the second element of my array, I mean not the element 0, but the next one... and attribute this first element of the array to another label, called UITitleLabel?

Thank you so much