Is that a bug in Swift Compiler? - ios

I write a protocol (in Xcode playground),and want it be conform by specified class , eg: Root.
Because I used Swift 4.1 , So there are new syntax for this :
protocol Delegate where Self:Root{
var titleImage:UIImage? {get}
}
(PS:If you want to know more about this , please follow the link : How to make Swift protocol conformed by a specific kind of Class?)
And I also write class Root and Foo :
class Root:Delegate{
var titleImage:UIImage?
func willDo(){
let foo = Foo()
foo.delegate = self
foo.invoke()
}
}
class Foo{
var delegate:Delegate!
func invoke(){
if let image = delegate.titleImage{
print("have a image [\(image)")
}else{
print("not have a image")
}
}
}
Problem is that when I call :
let r = Root()
r.willDo()
Here are runtime error :
But when I changed Delegate code to this :
protocol Delegate{
var titleImage:UIImage? {get}
}
That's all right!!! But it can't limited Delegate to be conform by class Root anymore!
Could anyone can tell me Why is it? Why when add " Self:Root " to Delegate will trigger a BAD_ACCESS Runtime error???
Is this a Bug in Swift or I misunderstand something???
Thanks a lot ;)

Add #objc when declaring your protocol
#objc protocol Delegate where Self: Root{
var titleImage: UIImage? {get}
}
This is a current bug in swift so wrapping it in #objc should work

Related

How can assing generic (associated type require) protocol as delegate to any controller?

I have a protocol that have associatedtype named MessageType.
protocol MessageProtocol: class {
associatedtype MessageType
func sendMessage(_ with: MessageType)
}
Then implemented it in the controller
extension MainController: MessageProtocol{
typealias MessageType = String
func sendMessage(_ with: MessageType) {
// sending message
}
}
My purpose is using the protocol as delegate in other controller like below.
final class AnotherController {
weak var messagerDelegate: MessageProtocol?
...
}
But I get error of that
Protocol 'MessageProtocol' can only be used as a generic constraint
because it has Self or associated type requirements
Is there any way to handle this error?
I've reading Big Nerd Ranch blog post about this situation.
https://www.bignerdranch.com/blog/why-associated-type-requirements-become-generic-constraints/
I've learned about the situation but no idea about how it can be achived?
Thanks,
I handle the situation like that.
final class AnotherController<T: MessageProtocol> where T.MessageType == String {
weak var messagerDelegate: T?
...
}
And if I want to create anotherController instance programmatically, I created like that.
let instance = AnotherController<MainController>(frame: CGRect.zero)
instance.delegate = self
...
Because of MainController is comfortable with MessageProtocol from
extension MainController: MessageProtocol{}
Probably it's not common case but worked for me.

Trying to understand the implementation of delegates with protocols in Swift

After doing loads of research I am still a little confused about how to use and implement delegates. I have tried writing my own, simplified example, to aid my understanding - however it does not working - meaning I must be a little lost.
//the underlying protocol
protocol myRules {
func sayName(name: String);
}
//the delegate that explains the protocols job
class myRulesDelegate: myRules {
func sayName(name: String){
print(name);
}
}
//the delegator that wants to use the delegate
class Person{
//the delegator telling which delegate to use
weak var delegate: myRulesDelegate!;
var myName: String!;
init(name: String){
self.myName = name;
}
func useDels(){
//using the delegate (this causes error)
delegate?.sayName(myName);
}
}
var obj = Person(name: "Tom");
obj.useDels();
I have read and watched so many tutorials but am still struggling. I no longer get error (cheers guys). But still get no output from sayName.
which demonstrates I must be misunderstanding how delegate patterns work.
I would really appreciate a corrected version of the code, with a simple explanation as to why it works, and why it is helpful.
I hope this helps others too. Cheers.
In Swift you omit the first parameter's external name, so your function call should be delegate.sayName("Tom")
Also, it is dangerous to use an implicitly unwrapped optional for your delegate property, as you have found. You should use a weak optional:
//the underlying protocol
protocol MyRulesDelegate: class {
func sayName(name: String)
}
//the delegator that wants to use the delegate
class Person {
//the delegator referencing the delegate to use
weak var delegate: MyRulesDelegate?
var myName: String
init(name: String){
self.myName = name
}
func useDels() {
//using the delegate
delegate?.sayName(myName)
}
}
Finally, your delegate must be an object, so you can't use a delegate in the way you have shown; you need to create another class that can set an instance of itself as the delegate
class SomeOtherClass: MyRulesDelegate {
var myPerson: Person
init() {
self.myPerson = Person(name:"Tom")
self.myPerson.delegate = self
}
func sayName(name: String) {
print("In the delegate function, the name is \(name)")
}
}
var something = SomeOtherClass()
something.myPerson.useDels()
Output:
In the delegate function, the name is Tom

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.

Protocol Extension, Mutating Function

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.

Compiler error when assigning the Delegate for a Protocol in Swift iOS

I have a problem assigning the delegate for an object that is an instance of a class that defines a protocol in Swift as follows:
I simplified the code to the bare bones to exemplify the issue:
This is the class with the protocol
protocol TheProtocol {
func notifyDelegate()
}
class ClassWithProtocol: NSObject {
var delegate: TheProtocol?
fire() {
delegate?.notifyDelegate()
}
}
This is the class the conforms to the Protocol
class ClassConformingToProtocol: NSObject, TheProtocol {
var object: ClassWithProtocol?
func notifyDelegate() {
println("OK")
}
init() {
object = ClassWithProtocol()
object?.delegate = self // Compiler error - Cannot assign to the result of this expression
object?.fire()
}
}
I have tried all sort of alternatives to assign the delegate without success. Any idea what I am missing?
The Known Issues section of the Release Notes says:
You cannot conditionally assign to a property of an optional object.
(16922562)
For example, this is not supported:
let window: NSWindow? = NSApplication.sharedApplication.mainWindow
window?.title = "Currently experiencing problems"
So you should do something like if let realObject = object { ... }

Resources