Reputation: 2848
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?
Upvotes: 1
Views: 63
Reputation: 273860
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.
Indeed you are right. But structs can conform to your HTTPClient
protocol too:
struct SomeStruct: HTTPClient {
var url: String?
func load() {}
}
If Feed
were passed an instance of SomeStruct
, then client.url = ""
would not work. Normally you cannot change the var
s of a struct-typed variable, if you declared the variable with let
.
let client = SomeStruct()
client.url = "" // error
The compiler doesn't know whether client
in Feed
is storing a struct or a class, so it tries to be safe and doesn't let you change url
.
You can make sure that only classes can conform to the protocol by adding : AnyObject
:
protocol HTTPClient: AnyObject {
// ...
}
Upvotes: 3