import Foundation
class IProtocol {
func meth1(arg: Int){}
}
class IObserver: IProtocol {
private var className: String
init(name: String) {
className = name
}
override func meth1(arg: Int) {
print(className, ":", arg)
}
}
class Notifier<T> {
private var listOfObservers = NSMutableArray()
func addObserver(observer: T) {
listOfObservers.add(observer)
}
func callObservers<ARG, RET>(function: (T)->(ARG)->RET, arg: ARG) {
for obj in listOfObservers {
let observer = obj as! T
_ = function(observer)(arg)
}
}
}
let a = IObserver(name: "First I Observer")
let b = IObserver(name: "Second I Observer")
let n = Notifier<IProtocol>()
n.addObserver(observer: a)
n.addObserver(observer: b)
n.callObservers(function: IProtocol.meth1, arg: Int(1))
OUTPUT
First I Observer: 1
Second I Observer: 1
The above example fails and does not build giving Command failed due to signal: Segmentation Fault: 11, when I change IProtocol to protocol from class. I have different protocols and different observer classes confirming those protocols. I am trying to implement a Notifier class that notifies the observers by taking the method from the protocol and arguments to be passed for that method.It will be great, if someone can explain what am I doing wrong!
I am using Swift 3 and Xcode 8.2
As of today, Swift does not handle direct references to protocol methods:
protocol IProtocol {
func meth1()
}
class IObserver: IProtocol {
func meth1() { print("success") }
}
let x = IProtocol.meth1 // This causes the compiler crash
x(IObserver())()
And coming to the solution for my problem was to pass a closure instead of the method. This is how it looks:
import Foundation
protocol IProtocol {
func meth1(arg: Int)
}
class IObserver: IProtocol {
private var className: String
init(name: String) {
className = name
}
func meth1(arg: Int) {
print(className, ":", arg)
}
}
class Notifier<T> {
private var listOfObservers = NSMutableArray()
func addObserver(observer: T) {
listOfObservers.add(observer)
}
func callObservers<ARG>(function: (T, ARG) -> (), arg: ARG) {
for obj in listOfObservers {
let observer = obj as! T
function(observer, arg)
}
}
}
let a = IObserver(name: "First I Observer")
let b = IObserver(name: "Second I Observer")
let n = Notifier<IProtocol>()
n.addObserver(observer: a)
n.addObserver(observer: b)
n.callObservers(function: {obs, ar in
obs.meth1(arg: ar)
}, arg: Int(1))
Related
I'm stuck about generics, and generic methods in swift.
Why this code that uses Swift generics method, gives EXC_BAD_ACCESS when invoking method1?
You can test it using Playground.
import UIKit
import Foundation
protocol SomeProtocol {
func printMe()
}
class SomeClass : SomeProtocol {
let value : String
init(value: String) {
self.value = value
}
func printMe() {
print("\(value)")
}
}
class BaseClass {
func method1<T>(_ param: T) {
print("passing into method 1 with param: \(param)")
method2(param)
}
func method2<T>(_ param: T) {
}
}
class ConcreteClass : BaseClass {
override func method2<T>(_ param: T) where T : SomeProtocol {
print("passing into method 2 with param: \(param.printMe())")
}
}
let someClass = SomeClass(value: "Hi")
let obj = ConcreteClass()
obj.method1(someClass)
The fact that you've managed to override the method with where closure without a compilation error really looks like a bug.
But there is a workaround for your use case:
class ConcreteClass : BaseClass {
override func method2<T>(_ param: T) {
print("Base param \(param)")
if let printable = param as? SomeProtocol {
printable.printMe()
}else {
super.method2(param)
}
}
}
struct System {
var method: (() -> ())?
var curMethod: Int
init() {
method = nil
curMethod = 0
}
mutating func method1() {
curMethod = 1
}
mutating func method2() {
curMethod = 2
}
}
var sys = System()
sys.method = System.method1
sys.method!()
I get an error cannot assign value of type (inout System) -> () -> ()' to type '(() -> ())?. What am I doing wrong?
First of all, your line sys.method = System.method1 is wrong, as it would require method1 to be a static function (like a class function) rather than an instance function, so it should be changed to sys.method = sys.method1. But this isn't allowed - the error is "error: partial application of 'mutating' method is not allowed".
If you make System a class (rather than a struct), it will work if you replace the System.method1 with sys.method1.
The reason for this is that a mutating func is actually quite a lot more than a simple function under the hood - it is a curried function (curried with a compiler generated function) that effectively creates a new copy of the struct with the "new" value - hence, you A) can't access it it directly ("partial application is not allowed") and B) you can't assign it to a ()->() variable.
So, there're 3 variants suggested by participants. Everything is working, and using class instead of struct seems to me less complicated.
struct System1 {
var method: (() -> ())?
var curMethod: Int
init() {
method = nil
curMethod = 0
}
mutating func method1() { curMethod = 1 }
mutating func method2() { curMethod = 2 }
}
struct System2 {
var method: ((inout System2) -> ())?
var curMethod: Int
init() {
method = nil
curMethod = 0
}
mutating func callCurrentMethod() { method?(&self) }
mutating func method1() { curMethod = 1 }
mutating func method2() { curMethod = 2 }
}
class System3 {
var method: (() -> ())?
var curMethod: Int
init() {
method = nil
curMethod = 0
}
func method1() { curMethod = 1 }
func method2() { curMethod = 2 }
}
var struct1 = System1()
var struct2 = System2()
var class1 = System3()
print(struct1.curMethod)
let curried = System1.method1
let unsafe = curried(&struct1)
unsafe()
print(struct1.curMethod)
print(struct2.curMethod)
struct2.method = { $0.method1() }
struct2.callCurrentMethod()
print(struct2.curMethod)
print(class1.curMethod)
class1.method = class1.method1
class1.method!()
print(class1.curMethod)
MyClass is a generic class which has a generic delegate.
AClass contains two iVar instances of MyClass and also implements MyClassDelegate.
Where AClass implements MyClassDelegate, how can I distinguish which object is calling into the interface? With non-generic classes, == is acceptable.
Please see the comments and error messages at the bottom of this code snippet.
protocol MyClassDelegate: class {
func myClass<T>(_ myClass: MyClass<T>, valueDidChange value: T)
}
class MyClass<T: Comparable> {
private var _value: T
var value: T {
set {
delegate?.myClass(self, valueDidChange: newValue)
}
get {
return _value
}
}
var delegate: MyClassDelegate?
init(value: T) {
_value = value
}
}
class AClass {
private var thing1 = MyClass(value: Int(10))
private var thing2 = MyClass(value: Int(100))
private var thing3 = MyClass(value: TimeInterval(10))
private var thing4 = MyClass(value: TimeInterval(100))
init() {
thing1.delegate = self
thing2.delegate = self
thing3.delegate = self
thing4.delegate = self
}
}
extension AClass: MyClassDelegate {
func myClass<T>(_ myClass: MyClass<T>, valueDidChange value: T) {
// This fails to complile
// Binary operator '==' cannot be applied to operands of type 'MyClass<T>' and 'MyClass<Int>'
if myClass == thing1 {
}
// Binary operator '==' cannot be applied to operands of type 'MyClass<T>' and 'MyClass<TimeInterval>' (aka 'MyClass<Double>')
else if myClass == thing3 {
}
}
}
Restrict the T type in your protocol method signature func myClass<T>(...) to be Comparable. Since you restricted it only in one particular extension of that protocol, the method in AClass can take any kind of T, not just Comparable ones.
I tried and tried but couldn't configure the generic delegate in a manner where I could compare callers.
I read the answer from NRitH, but couldn't get the compiler to accept the syntax. Perhaps there is a way to do this, but I went a different route with success.
I gave up on the protocol/delegate technique and ended up using a callback closure. Instead of defining a delegate in MyClass and implementing that delegate in AClass, I defined a callback closure in MyClass in implemented that in AClass like so:
class MyClass<T: Comparable>: Equatable {
var valueChanged: ((_ clazz: MyClass) -> Void)?
private var _value: T
var value: T {
set {
_value = newValue
valueChanged?(self)
}
get {
return _value
}
}
init(value: T) {
_value = value
}
static public func ==(lhs: MyClass<T>, rhs: MyClass<T>) -> Bool {
return lhs.value == rhs.value
}
}
class AClass {
fileprivate var thing1: MyClass<Int> = MyClass(value: 10)
fileprivate var thing2: MyClass<Int> = MyClass(value: 100)
fileprivate var thing3: MyClass<TimeInterval> = MyClass(value: 10)
fileprivate var thing4: MyClass<TimeInterval> = MyClass(value: 100)
init() {
thing1.valueChanged = { (thing) in
// You can compare here, but you already know which object is callling back
if thing == self.thing1 {
}
}
thing2.valueChanged = { (thing) in
print("Thing2 changed: \(thing.value)")
}
}
}
I have a random protocol as example
protocol testP {
init(param1: String)
}
And I have a class, which take Any as parameter as example:
class testC {
var aClass: Any
}
How can I check if aClass conforms to protocol testP and if it does, create a new object using protocol initializer, as example:
let newObject = aClass(param1: "Hello World!")
Please, help
You can test it as other type checking with if-let:
protocol TestP {
init(param1: String)
}
class TestC {
var aClass: Any
init(_ aClass: Any) {
self.aClass = aClass
}
}
class MyClassA: TestP {
required init(param1: String) {
//
}
}
class MyClassB {
}
let containerA = TestC(MyClassA.self)
let containerB = TestC(MyClassB.self)
if let testPType = containerA.aClass as? TestP.Type {
var a = testPType.init(param1: "abc")
print(a) //->MyClassA
}
if let testPType = containerB.aClass as? TestP.Type {
print("This print statement is not executed")
}
By the way, if you assign only class types to aClass, consider using AnyClass or Any.Type.
I am trying to create a couple of objects which are dependent one to each other and they mush have a method to downcast directly the concrete class of the other object. Something like this:
protocol aProt
{
var bVar:bProt! { get set }
}
protocol bProt
{
var aVar:aProt! { get set }
}
class a: aProt
{
var bVar: bProt!
func bConcrete() -> b {
return bVar as! b
}
}
class b: bProt
{
var aVar: aProt!
func aConcrete() -> a {
return aVar as! a
}
Now, the problem is that I want this behavior (func aConcrete(),func bConcrete()) to be inherited by the subclasses of a and b. Then I thought the perfect way of doing this was using generics, but... There's no way of doing this.
class a: aProt
{
var bVar: bProt!
func bConcrete() -> T {
return bVar as! T
}
}
class b: bProt
{
var aVar: aProt!
func aConcrete<T>() -> T {
return aVar as! T
}
You can do it but when you have to use it you must downcast the variable anyway, so there is no way of doing it in a clean manner:
let aObject = a()
let bSubclassObject = a.bConcrete() // The compiler complains it cannot infer the class of T
let bSubclassObject = a.bConcrete() as! bSubclass // this works, but this is exactly which I wanted to avoid... :(
Define the generic function and add where to T:
protocol aProt {
var bVar: bProt! { get set }
}
protocol bProt {
var aVar:aProt! { get set }
}
class a: aProt {
var bVar: bProt!
func bConcrete<T: b>(_ type: T.Type) -> T? {
return bVar as? T
}
}
class b: bProt {
var aVar: aProt!
func aConcrete<T: a>(_ type: T.Type) -> T? {
return aVar as? T
}
}
class a1: a { }
class b1: b {
var fullName: String = "new object"
}
let aObj = a()
aObj.bVar = b1()
let bObj = aObj.bConcrete(b1.self)
bObj?.fullName
According to your requirement, calls bConcrete(b1.self) might still not good enough, but at least you need to know what type of data you are expecting to return.