Hi
I'm trying to figure out the following gives me an error.
protocol SomeProtocol
{
var name: String
{
get
set
}
}
class SomeName : SomeProtocol
{
public var name: String
init()
{
self.name = ""
}
init(name: String)
{
self.name = name
}
}
class SomeContext
{
private init()
{
}
open static let shared = SomeContext()
public func someMethod(with value: inout T, age: [Int])
{
print("before: \(value.name)")
value.name = "foo"
print("after: \(value.name)")
print("age: \(age)")
}
}
func createSomeName()
{
var value = SomeName(name: "Fred")
testInout(value: &value)
print(value.name)
}
func testInout(value: inout SomeProtocol)
{
SomeContext.shared.someMethod(with: &value, age: [1,2,3])
}
createSomeName()On line 47, I get this error:
error: cannot pass immutable value as inout argument: implicit conversion from 'SomeName' to 'SomeProtocol' requires a temporary
testInout(value: &value)
On line 53, I get this error:
error: in argument type 'inout SomeProtocol', 'SomeProtocol' does not conform to expected type 'SomeProtocol'
SomeContext.shared.someMethod(with: &value, age: [1,2,3])
Basically I need to be able to pass class/or struct to a method, which passes it to another method which can modify the value i.e name. I tried using a struct but ended up with the same errors.
If I replace line 47 with line 53, it seems to work fine with either a struct or class
Any ideas how to work around this problem?
Thanks
Something munged your code listing so that it doesn’t compile. I’ve fixed it by presuming that line 34 should be this:
public func someMethod<T : SomeProtocol>(with value: inout T, age: [Int])Let me know if that’s incorrect.
The error on line 47 is because the
inout protocol parameter could change the concrete type of the value. That is, you could pass it a value of
SomeName and get back a value of
SomeOtherName, a different concrete type that conforms to
SomeProtocol. There’s two ways to fix this:
If you only care that
conforms tovalue
, change line 46 to this:SomeProtocolvar value = SomeName(name: "Fred") as SomeProtocol.
Alternatively, you could write something like this:
func createSomeName() { var value = SomeName(name: "Fred") var t = value as SomeProtocol testInout(value: &t) print(value.name) }and then deal with the fact that
might come back as a different type thent
.valueNote that
is the “temporary” mentioned by the error.t
The error on line 53 is because
someMethod(…) is expecting a concrete type that conforms to
SomeProtocol, but
testInout(…) doesn’t have a concrete type, it has a value of the protocol type. You don’t need
inout to trigger this issue; the following code has the same problem:
protocol MyProtocol { }
func callee<T: MyProtocol>(value: T) { }
func caller(value: MyProtocol) {
callee(value: value)
// Cannot invoke 'callee' with an argument list of type '(value: MyProtocol)'
}The most obvious fix here is to make
testInout(…) also generic:
func testInout<T2 : SomeProtocol>(value: inout T2)
{
SomeContext.shared.someMethod(with: &value, age: [1,2,3])
}Now
T is a concrete type that conforms to
SomeProtocol, so when you call
someMethod(…) you’re calling it with a concrete type (albeit a generic one).
Share and Enjoy
—
Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware
let myEmail = "eskimo" + "1" + "@apple.com"