Search code examples
iosswift3nestedsubviews

Swift 3 - Access nested subviews properties in code


For a pure matter of training I'm developing a weather app coding the entire UI rather than using storyboard.

I have a nested structure of views as follows:

SuperView --> UIView (with 5 subviews of type UIView). Each of the 5 UIViews contains: 1 UIImageView, 2 UILabels

Now, when I'm calling my delegate function to retrieve the weather I'm having trouble updating those values with weather icon, weather description, day.

I tried using Tags for each of the subviews but no joy.

To give you something to look at:

This is where I retrieve my forecast data (icons, description, day):

//MARK: Forecast Wheel elements
let forecastWeatherWheel = UIView()
var forecastDays = [String]()
var forecastDescriptions = [String]()
var forecastIcons = [String]()


func setForecastWeather(forecast: ForecastWeatherData) {

    forecastDays = forecast.forecastDay
    forecastDescriptions = forecast.weatherDescription
    forecastIcons = forecast.icon

    for (index,forecastContainerView) in (forecastWeatherWheel.subviews.filter{$0 is UIView}).enumerated(){
        for (index,iconImageView) in (forecastContainerView.subviews.filter{$0 is UIImageView}).enumerated(){
            let iconImage = iconImageView as! UIImageView
            iconImage.image = UIImage(imageLiteralResourceName: forecastIcons[index])
        }
    }
}

With that nested for I've been - somehow - able to access the image property of my nested view but rather than looping through the array of icons it's using always the same Icon in all the 5 subviews...

Any help is highly appreciated as I'm struggling with this since more than 12 hrs :|


Solution

  • The real answer is of course to use a view subclass, with accessors for the image view and each label, instead of using the subview hierarchy like this. But here's what's wrong with what you're doing right now:

    for (index,forecastContainerView) in (forecastWeatherWheel.subviews.filter{$0 is UIView}).enumerated(){
    

    The filter here is pointless; everything in subviews is a UIView. You'll get 5 passes through here.

            for (index,iconImageView) in (forecastContainerView.subviews.filter{$0 is UIImageView}).enumerated(){
    

    Your filter here is only going to return a single view - the image view, since the others aren't image views. That means this loop is only going to execute once.

                let iconImage = iconImageView as! UIImageView
                iconImage.image = UIImage(imageLiteralResourceName: forecastIcons[index])
    

    Which means that index here is your inner index, which is always 0.

    Either use a different name for each index variable, or write it something like this (untested, typed in browser):

    for (index, forecastContainerView) in forecastWeatherWheel.subviews.enumerated() {
        let imageView = forecastContainerView.subviews.first(where: { $0 is UIImageView } ) as! UIImageView
        imageView.image = UIImage(imageLiteralResourceName: forecastIcons[index]
    }