Treehouse Intermediate Course - Part 8 (Generics 6)

So the sixth and final part on generics! It's been tough but I've accepted that it's all part of learning Swift at a deeper level, rather than learning specific code for particular projects! Let's do this!

Start Time - 15:46

So creating a couple of protocols - linked to views and data. By specifying a protocol as the type, we can specify any type that conforms to that protocol.

So errors are coming up. Here's Pasan's code -

protocol DataProvider {
    
    associatedtype Object
    
    func object(atIndex index: Int) -> Object
}

protocol ConfigurableView {
    
    associatedtype Data
    
    func configure(with data: Data)
}

class ViewController<View: ConfigurableView, DataSource: DataProvider> {
    
    let view: View
    let data: DataSource
    
    init(view: View, data: DataSource) {
        self.view = view
        self.data = data
    }
    
    func start() {
        let data = data.object(atIndex: 0)
        view.configure(with: object)
    }

}

OK the point is that the start function doesn't compile. There is other code from Pasan that does work!

struct StringDataProvider: DataProvider {
    
    let data = ["someValue", "anotherValue"]
    
    func object(atIndex index: Int) -> String {
        return data[index]
    }
}

struct IntView: ConfigurableView {
    
    func configure(with data: Int) {
        //
    }
}

struct StringView: ConfigurableView {
    func configure(with data: String) {
        //
    }
}

let controller = ViewController(view: IntView(), data: StringDataProvider())

The associated type is key here. The two different types above are defined by their associated events. 

When defining generic constraints, if the constraints are protocols with associated types, then you have access to the associated types. 

The class has been added to - 

class ViewController<View: ConfigurableView, DataSource: DataProvider> where View.Data == DataSource.Object

We are NOT saying that they have to be the same instance but they do need to be the same type - where the == part is. 

Now that function that wasn't working will be!

Ah mine doesn't - still an error! This must be do with the Swift language having evolved beyond this code.  Nope - scratch that, I did a typo (needed object not data!).

So, again, a lot of this is over my head. But it is all about exposure to this higher level stuff. I am not going to get bogged down too much with it! Final video straight on!

Extending Generic Types

Here we go! So the point of extensions is to add further functionality to a certain type. In the example below (kindly added by another user on Treehouse as Pasan didn't), there is a long winded code about weather....

struct Weather {
    let temperature: Double
    let humidity: Double
    let chanceOfRain: Double
    let icon: String
    let highTemperature: Double
    let lowTemperature: Double
    let sunrise: Date
    let sunset: Date
}

let current = Weather(temperature: 63, humidity: 0.36, chanceOfRain: 0.04, icon: "Cloudy", highTemperature: 67, lowTemperature: 50, sunrise: Date(), sunset: Date())

protocol PrettyPrintable {
    
    var prettyDescription: String { get }
}

extension Weather: PrettyPrintable {
    var prettyDescription: String {
        return "Temperature: \(temperature)\nHumidity: \(humidity)\nChance of Rain: \(chanceOfRain)\nIcon: \(icon)\nHigh Temperature: \(highTemperature)\nLow Temperature: \(lowTemperature)\nSunrise Time: \(sunrise)\nSunset Time: \(sunset)"
    }
}

let tuesday = Weather(temperature: 63, humidity: 0.36, chanceOfRain: 0.04, icon: "Cloudy", highTemperature: 67, lowTemperature: 50, sunrise: Date(), sunset: Date())

let wednesday = Weather(temperature: 63, humidity: 0.36, chanceOfRain: 0.04, icon: "Cloudy", highTemperature: 67, lowTemperature: 50, sunrise: Date(), sunset: Date())

let thursday = Weather(temperature: 63, humidity: 0.36, chanceOfRain: 0.04, icon: "Cloudy", highTemperature: 67, lowTemperature: 50, sunrise: Date(), sunset: Date())

let week = [current, tuesday, wednesday, thursday]

extension Array where Element: PrettyPrintable {
    var prettyDescription: String {
        var output = ""
        
        for (index, element) in self.enumerated() {
            output += "\n\n*******\n\nIndex: \(index)\n\n\(element.prettyDescription)"
        }
        
        return output
    }
    
}

print(week.prettyDescription)


We have here a structure with key properties. Extensions are used various times to add things like the description etc. My question is why keep adding these and not just put them in the original code?


So this is about extending the array type, filtering by prexies, where there is the prefix containing protocol conformance going on....wowzers!

protocol PrefixContaining {
    func hasPrefix(_ prefix: String) -> Bool
}

extension String: PrefixContaining {}

// Enter code below

extension Array where Element: PrefixContaining {
    
    func filter(byPrefix prefix: String) -> [Element] {
        
        var newArray: [Element] = []
        
        for item in self {
            
            if item.hasPrefix(prefix) {
                newArray.append(item)
                
            }
            
        }

        return newArray
    }

}


I did it with lots of help! The for and if bits were actually pretty simple. Was expecting it to be much worse!

Finish Time - 16:31 (45 minutes)

So that's generics! Yes I could go back over bits but I honestly don't think it will help. Tomorrow I will begin closures and definitely revisit generics at some point! The issue is that my capacity for understanding them any better is limited. So I'd rather crack on having spent six separate entries on generics! Until tomorrow!

Comments

Popular posts from this blog

*Xcode Project Entry 2* F1 Quiz - part 1

Angela Yu Course Part 10 (up to lesson 112)

Angela Yu Xcode 12 Course - Part 7 (lectures 74 to 79)