I was trying to implement a Networking Module for my personal project and I was following TDD. When I am writing the test cases I came across a compile error and I was not able to map the error with Swift concepts. I could have easily ignored it and done the implementation in a different way. But I was not feeling right to do it as I want to know the exact reason to the error.
This is the code snippet.
import UIKit
protocol HTTPClient {
var url: String? {get set}
func load()
}
class HTTPClientSpy: HTTPClient {
var url: String?
func load() {
}
}
class Feed {
let client: HTTPClient
init(client: HTTPClient) {
self.client = client
}
func loadFeed() {
client.url = "" //Compile Error -> Cannot assign to property: 'client' is a 'let' constant
client.load()
}
}
When I do the following change the error goes away
class Feed {
let client: HTTPClientSpy
init(client: HTTPClientSpy) {
self.client = client
}
func loadFeed() {
client.url = "" //No compile errors
client.load()
}
}
Swift classes are mutable. which means we should be able to change the properties of the instance even if we create a constant reference to the instance. It seems there is something to do with the protocol conformance in this case which I cannot understand.
Can someone please explain the theory behind this?
Indeed you are right. But structs can conform to your
HTTPClientprotocol too:If
Feedwere passed an instance ofSomeStruct, thenclient.url = ""would not work. Normally you cannot change thevars of a struct-typed variable, if you declared the variable withlet.The compiler doesn't know whether
clientinFeedis storing a struct or a class, so it tries to be safe and doesn't let you changeurl.You can make sure that only classes can conform to the protocol by adding
: AnyObject: