Protocol Extension, Mutating Function
If you intend to use the protocol only for classes then you can make
it a class protocol (and remove the mutating
keyword):
protocol ColorImpressionableProtocol : class {
// ...
func adoptColorsFromImpresion(impresion: ColorImpressionableProtocol?)
}
Then
init(impresion: ColorImpressionableProtocol?){
super.init(nibName: nil, bundle: nil)
adoptColorsFromImpresion(impresion)
}
compiles without problems.
Swift 2 Error using mutating function in Protocol extension Cannot use mutating member on immutable value: 'self' is immutable
The problem is that, in the protocol you mark the function as mutating, which you need to do if you want to use the protocol on a struct. However, the self that is passed to testFunc
is immutable (it's a reference to a instance of the class) and that is tripping up the compiler. This would make sense if testClass was actually a struct and you could make the function mutating to resolve the issue.
I can see two work arounds:
make the protocol class only
protocol MTKAnimateValueDelegate: class { ...
Make testClass a struct and mark testFunc as mutating.
Either way, I think this is a bug that needs to be reported to Apple.
Edit
- Another way around it is to make a mutable copy of
self
func testFunc() {
var animValue = MTKAnimateValue(fromValue: 10, toValue: 20, inSeconds: 2)
animValue.isAnimating = true
var mutableSelf = self
mutableSelf.mtkAnimQueAppend(animValue)
}
Since mutableSelf
is a reference, any changes the mutating function makes will still be reflected in self
's state.
What happens when a Class conforms to a protocol, which contains mutating function?
I don't see what the "confusion" is. You've elucidated the rules beautifully! A struct may implement a protocol's mutating
function as nonmutating, but it may not implement a protocol's nonmutating function as mutating
. Once you've said those rules, there's nothing to be "confused" about. The rules are the rules.
Classes don't have mutating functions so your investigations there are sort of irrelevant. If you had declared your protocol as a class
protocol, your mutating
annotation in the protocol would have been illegal.
Swift: Can't use mutating method in Protocol Extension
This code:
extension myViewController: ScreenSizeProtocolExt {
let imageToUse = setupBG()
// Here is get an error: 'Use of instance member 'setupBG' on type 'inout Self'; did you mean to use a value of type 'inout self' instead?
let image = UIImage(named: imageToUse)
imageView.image = image
}
isn't legal. The main thing is that extensions can't add new stored properties -- so you can't do:
let imageToUse = setupBG()
In an extension.
Also, this line:
imageView.image = image
Is illegal outside of a func
.
As to what you need here, this all seems like overkill. Why extend this to the viewControllers with protocols? You have a function that returns an imageName -- that could be anywhere (just a free func, not in a class).
Then, in the viewControllers, just set the image view's image to the name returned by this function.
Extensions are a way to give more interface to a class -- you can't make the class call the methods automatically just via extension.
Why does a mutating method in a Swift protocol infinitely recurse unless only an extension method?
With your change in the second example, by including the m
in the protocol definition, that instructs Swift to employ dynamic dispatch. So when you call p.m()
, it dynamically determines whether the object has overridden the default implementation of the method. In this particular example, that results in the method recursively calling itself.
But in the first example, in the absence of the method being part of the protocol definition, Swift will employ static dispatch, and because p
is of type P
, it will call the m
implementation in P
.
By way of example, consider where the method is not part of the protocol definition (and therefore not in the “protocol witness table”):
protocol P {
// func method()
}
extension P {
func method() {
print("Protocol default implementation")
}
}
struct Foo: P {
func method() {
print(“Foo implementation")
}
}
Because the foo
is a P
reference and because method
is not part of the P
definition, it excludes method
from the protocol witness table and employs static dispatch. As a result the following will print “Protocol default implementation”:
let foo: P = Foo()
foo.method() // Protocol default implementation
But if you change the protocol to explicitly include this method, leaving everything else the same, method
will be included in the protocol witness table:
protocol P {
func method()
}
Then the following will now print “Foo implementation”, because although the foo
variable is of type P
, it will dynamically determine whether the underlying type, Foo
, has overridden that method:
let foo: P = Foo()
foo.method() // Foo implementation
For more information on dynamic vs static dispatch, see WWDC 2016 video Understanding Swift Performance.
Why can't I change variables in a protocol extension where self is a class?
Your example doesn't compile because MyProtocol
isn't class-bound, and as such can have mutating
requirements and extension members. This includes property setters, which are by default mutating
. Such members are free to re-assign a completely new value to self
, meaning that the compiler needs to ensure they're called on mutable variables.
For example, consider:
public protocol MyProtocol {
init()
var i: Int { get set } // implicitly `{ get mutating set }`
}
extension MyProtocol {
var i: Int {
get { return 0 }
// implicitly `mutating set`
set { self = type(of: self).init() } // assign a completely new instance to `self`.
}
}
public protocol MyProtocol2 : class, MyProtocol {}
public extension MyProtocol2 where Self : AnyObject {
func a() {
i = 0 // error: Cannot assign to property: 'self' is immutable
}
}
final class C : MyProtocol2 {
init() {}
}
let c = C()
c.a()
If this were legal, calling c.a()
would re-assign a completely new instance of C
to the variable c
. But c
is immutable, therefore the code is not well formed.
Making MyProtocol
class bound (i.e protocol MyProtocol : AnyObject
or the deprecated spelling protocol MyProtocol : class
) works because now the compiler knows that only classes can conform to MyProtocol
. Therefore it imposes reference semantics by forbidding mutating
requirements and extension members and therefore prevents any mutations of self
.
Another option at your disposal is to mark the setter for the requirement i
as being nonmutating
– therefore meaning that it can only be satisfied by a non-mutating setter. This makes your code once again well-formed:
public protocol MyProtocol {
init()
var i: Int { get nonmutating set }
}
public protocol MyProtocol2 : class, MyProtocol {}
public extension MyProtocol2 where Self : AnyObject {
func a() {
i = 0 // legal
}
}
Related Topics
Can't Send Push Notifications Using the Server API
Cannot Show Modal Viewcontroller in iOS7
Firebase Dynamic Link Always Goes to App Store Url Even If the App Is Installed
Gamecenter iOS 9 Gamecenter Gklocalplayerlistener Methods Not Called
Does iOS Calendar Support a Url Scheme
How to Convert String to Unicode(Utf-8) String in Swift
Flutter iOS Build Failure Error with Multiple Commands After the Xcode Upgrade
Choosing Units with Measurementformatter
Facebook App Requests Aren't Shown on iOS Devices
Xcode Duplicate Symbols for Architecture Error After Updating Cocoa Pods
What Does It Mean for Something to Be Thread Safe in iOS
Why Does "Try Catch" in Objective-C Cause Memory Leak
Perform Action by Clicking on Some Word in Uitextview or Uilabel
Onfocuschange Not Triggered in Swiftui Tvos