Protocol Extension, Mutating Function - ios

I am using swift 2.0, I have a protocol and an extension on the protocol to create a default implementation of a method, the code is as fallows:
protocol ColorImpressionableProtocol {
var lightAccentColor: UIColor? {get set}
var accentColor: UIColor? {get set}
var darkAccentColor: UIColor? {get set}
var specialTextColor: UIColor? {get set}
mutating func adoptColorsFromImpresion(impresion: ColorImpressionableProtocol?)
}
extension ColorImpressionableProtocol {
mutating func adoptColorsFromImpresion(impresion: ColorImpressionableProtocol?){
lightAccentColor = impresion?.lightAccentColor
accentColor = impresion?.accentColor
darkAccentColor = impresion?.darkAccentColor
specialTextColor = impresion?.specialTextColor
}
}
I am later on in my code trying to call this method and am getting an error that reads:
"cannot use mutating member on immutable value:'self' is immutable"
The code is as fallows:
init(impresion: ColorImpressionableProtocol?){
super.init(nibName: nil, bundle: nil)
adoptColorsFromImpresion(impresion)
}
The only thing I can think of is that 'Self' in this case is a protocol, not a class. However I have to be missing something to make this concept work, A default implementation of a method defined by a protocol that edits values also defined by the same protocol.
Thank you for your help and time :)

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.

You are adopting this protocol in a class so the self (which is reference type) is immutable. The compiler expects self to be mutable because of the mutable method declared in protocol. That's the reason you are getting this error.
The possible solutions are :
1) Implement a non mutating version of the method where the protocol
being adopted. ie: implement the method in adopting class instead as a
protocol extension.
class MyClass : ColorImpressionableProtocol {
func adoptColorsFromImpresion(impresion: ColorImpressionableProtocol?){
lightAccentColor = impresion?.lightAccentColor
accentColor = impresion?.accentColor
darkAccentColor = impresion?.darkAccentColor
specialTextColor = impresion?.specialTextColor
}
}
2) Make the protocol as class only protocol. This way we can remove the mutating keyword. It's the easiest solution but it can be only used in class.
To make protocol class only :
protocol MyProtocolName : AnyObject { }
OR
protocol MyProtocolName : class { }
3) Make sure only value types adopt this protocol.This may not be useful in
all scenarios.
Here is the detailed explanation and solution for this case.

Related

NSManagedObject and protocol conformance

Here is my problem, I have an type (MyManObj) which is a subclass of NSManagedObject.
This type has two fields: fieldOne,fieldTwo:Int16
I also have a protocol defined this way:
#objc protocol MyProtocol {
var fieldOne:Int16 {get set}
var fieldTwo:Int16 {get set}
}
I need to express the fact that MyManObj conforms to MyProtocol. And I don't know how to do it.
I have tried to add code like this, but it does not work:
extension MyManObj:MyProtocol {}
Precisely I get this message:
Type 'MyManObj' does not conform to protocol 'MyProtocol'.
I have then tried a few more variations, but with no interest because they failed.
You are getting this error because the variables/ properties in your protocol are not marked optional [i.e. they are required] and your compiler is asking you to implement all the method/ properties declared in your protocol.
To resolve this issue you can do:
#objc protocol MyProtocol: class {
optional var fieldOne:Int16 {get set}
optional var fieldTwo:Int16 {get set}
}
OR
extension MyManObj:MyProtocol {
var fieldOne:Int16 {
get{}
set{}
}
var fieldTwo:Int16 {
get{}
set{}
}
}

Delegate a structure in swift?

I am developing an app to increase a little more my knowledge about swift. One of my questions if is it possible to delegate a optional function with a structure as an argument.
What yes Im able to do:
#objc protocol someProtocol {
optional func optionalFunc(someClass: someClass)
}
class someClass: NSObject {
}
But, what I want to do (problems representing a structure in objc):
#objc protocol someProtocol {
optional func optionalFunc(someStructure: someStructure)
}
struct someStructure {
}
And Im not able to find the way to solve this problem.
And the other thing I want, is similar to this but with enums instead of structs:
#objc protocol someProtocol {
optional func optionalFunc(someEnum: someEnum)
}
enum someEnum {
case example
}
If somebody can help me, I will be very grateful!
Lot of thanks! Luciano!
Swift 2.0 lets you do default implementations of protocols.
protocol someProtocol {
func optionalFunc(someStructure: SomeStructure)
}
extension someProtocol {
func optionalFunc(someStructure: SomeStructure){
// optional, leave empty
}
}
struct SomeStructure {
}
This way you can get around using the optional-decoration and do what you wanted.
You cannot pass the parameters as struct or enum, because it's only valid on Swift language, so it cannot be represented in Objective-C.
Another approach, you can declare a function as variable instead of func:
protocol someProtocol {
var optionalFunc: (someStructure) -> ()? { get set}
}
Implementation:
class someClass : someProtocol {
var optionalFunc: (someStructure) -> ()? = { yourStruct in
// Do anything with yourStruct
return
}
}
Using:
var someVar:someClass = someClass()
var result = someVar.optionalFunc(someStructure())
The result is a ()?. If you do not implement the variable, result will nil

Set and protocols in Swift

I would like to initialize a Set with values corresponding to the Hashable protocol and a custom protocol.
I tried :
protocol CustomProtocol: Hashable {}
let set = Set<CustomProtocol>()
But Xcode complains :
Using 'CustomProtocol' as a concrete type conforming to protocol
'Hashable' is not supported
How can I achieve that ?
Thanks in advance.
The immediate reason why you can't do what you want to do is that Hashable is a generic protocol. Thus it — or a protocol that derives from it — cannot be used as a Set's element type. A generic type can used only as a constraint in another generic. You will notice that you can't declare a Set<Hashable> either, even though a set's element type must conform to Hashable.
The simplest approach is to make, not a set of protocols, but a set of some object type. For example, if S is a struct that conforms to CustomProtocol (because it conforms to Hashable plus whatever else CustomProtocol entails), you can declare a set of S.
Example:
protocol CustomProtocol: Hashable {
}
func ==(lhs:S,rhs:S) -> Bool {
return lhs.name == rhs.name
}
struct S : CustomProtocol {
var name : String
var hashValue : Int { return name.hashValue }
}
let set = Set<S>()
If the problem you're trying to solve is that you want a collection of mixed types which are nevertheless in some way equatable to one another, then that is the very same problem solved by protocol extensions, as explained by the discussion in the Protocol-Oriented WWDC 2015 video.
But it would be simpler just to make all your types classes that derive from NSObject. You can still make them adopt some secondary protocol, of course, but the set won't be defined as a set of that protocol but of NSObject.
In Swift 3, one solution is to use the AnyHashable structure.
For instance, to create a Observers/Observable pattern, we could do :
protocol Observer {
func observableDidSomething(_ observable: Observable)
}
class Observable {
private var observersSet: Set<AnyHashable> = []
private var observers: [Observer] {
return observersSet.flatMap { $0 as? Observer }
}
func add<O>(_ observer: O) where O : Observer, O : Hashable {
observersSet.insert(observer)
}
func remove<O>(_ observer: O) where O : Observer, O : Hashable {
observersSet.remove(observer)
}
// ...
private func doSomething() {
// do something ...
observers.forEach { $0.observableDidSomething(self) }
}
}
Notice that I separate the Hashable protocol from my protocol Observer.

Swift Cannot assign to immutable expression of type for protocol enforced variable [duplicate]

I am using swift 2.0, I have a protocol and an extension on the protocol to create a default implementation of a method, the code is as fallows:
protocol ColorImpressionableProtocol {
var lightAccentColor: UIColor? {get set}
var accentColor: UIColor? {get set}
var darkAccentColor: UIColor? {get set}
var specialTextColor: UIColor? {get set}
mutating func adoptColorsFromImpresion(impresion: ColorImpressionableProtocol?)
}
extension ColorImpressionableProtocol {
mutating func adoptColorsFromImpresion(impresion: ColorImpressionableProtocol?){
lightAccentColor = impresion?.lightAccentColor
accentColor = impresion?.accentColor
darkAccentColor = impresion?.darkAccentColor
specialTextColor = impresion?.specialTextColor
}
}
I am later on in my code trying to call this method and am getting an error that reads:
"cannot use mutating member on immutable value:'self' is immutable"
The code is as fallows:
init(impresion: ColorImpressionableProtocol?){
super.init(nibName: nil, bundle: nil)
adoptColorsFromImpresion(impresion)
}
The only thing I can think of is that 'Self' in this case is a protocol, not a class. However I have to be missing something to make this concept work, A default implementation of a method defined by a protocol that edits values also defined by the same protocol.
Thank you for your help and time :)
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.
You are adopting this protocol in a class so the self (which is reference type) is immutable. The compiler expects self to be mutable because of the mutable method declared in protocol. That's the reason you are getting this error.
The possible solutions are :
1) Implement a non mutating version of the method where the protocol
being adopted. ie: implement the method in adopting class instead as a
protocol extension.
class MyClass : ColorImpressionableProtocol {
func adoptColorsFromImpresion(impresion: ColorImpressionableProtocol?){
lightAccentColor = impresion?.lightAccentColor
accentColor = impresion?.accentColor
darkAccentColor = impresion?.darkAccentColor
specialTextColor = impresion?.specialTextColor
}
}
2) Make the protocol as class only protocol. This way we can remove the mutating keyword. It's the easiest solution but it can be only used in class.
To make protocol class only :
protocol MyProtocolName : AnyObject { }
OR
protocol MyProtocolName : class { }
3) Make sure only value types adopt this protocol.This may not be useful in
all scenarios.
Here is the detailed explanation and solution for this case.

How to declare a function with a concrete return type conforming to a protocol?

EDIT:
This question was written before swift added the some keyword, making it obsolete
In objective-c I could declare a method with a return type:
-(UIView<MyProtocol> *)someMethod;
In this example the method returns a UIView that conforms to a protocol MyProtocol.
I want to do something like that in swift:
protocol MyProtocol {
var someProperty : Int {get set}
}
protocol MyDelegate {
func someMethod() -> UIView : MyProtocol // the view should conform to the protocol - I don't care what kind of view it is - I don't want to define a specific type of view
}
In general - The delegate should return a UIView with the var "someProperty"
I don't want to define a concrete UIView class.
I want the user to be able to return any type of UIView (As long as it conforms to the protocol)
The syntax I wrote is invalid - How should I be writing it?
You could just use the protocol as type:
protocol MyDelegate {
func someMethod() -> MyProtocol
}
And use it like this:
protocol MyProtocol {
var someProperty : Int {get set}
}
class CustomView: UIView, MyProtocol {
var someProperty = 2
}
protocol MyDelegate {
func someMethod() -> MyProtocol
}
struct Delegate: MyDelegate {
func someMethod() -> MyProtocol {
return CustomView()
}
}
let delegate = Delegate()
let view = delegate.someMethod()
let property = view.someProperty // property = 2
This is not possible in Swift. Not everything possible in Obj-C has to be possible in Swift. When creating a type requirement you can only combine protocols using the protocol<..., ...> syntax but you can't combine a class and a protocol.
Technically, this should be good for your architecture. You can probably find a workaround but I would advice against it. There is a reason to avoid combining classes with protocols because the interfaces are much more difficult to handle. Most OOP languages don't have that syntax. Many commonly used languages don't even have a syntax to combine protocols.
protocol MyProtocol {
var someProperty : Int {get set}
}
protocol MyDelegate {
func someMethod<T: UIView & MyProtocol>() -> T // the view should conform to the protocol - I don't care what kind of view it is - I don't want to define a specific type of view
}
class MyDelegateTestView : UIView, MyProtocol {
var someProperty: Int = 10
}
class MyDelegateTestClass : MyDelegate {
func someMethod<T>() -> T where T : UIView, T : MyProtocol {
return MyDelegateTestView() as! T
}
}
The question was written before the days of swift-ui
The "some" keyword has solved it by allowing opaque types to be returned from functions
protocol MyDelegate {
func someMethod() -> some MyProtocol
}
Here below is a way.
func myMethod(string: String) -> MyClass:MyProtocol? {
}
You can use without optional type as MyClass: MyProtocol.

Resources