I created my protocol as below:
import Foundation
protocol ITcpCLient: class {
func OnMessageReceived(_ message: String);
}
The class using protocol as below:
import Foundation
class tcpConnection {
var tcpClientdelegate: ITcpCLient?
init(client: ITcpCLient) {
self.tcpClientdelegate? = client
if self.tcpClientdelegate == nil {
print("tcpClient Delegate is nil!")
}
}
func trigger() {
tcpClientdelegate?.OnMessageReceived("From Trigger")
}
}
My ViewController Class is below:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
print("viewDidLoad!")
let myTcpConnection = tcpConnection(client: self)
myTcpConnection.trigger()
}
}
extension ViewController: ITcpCLient {
func OnMessageReceived(_ message: String) {
print("onMessageReceived")
print(message)
}
}
The output is: tcpClient Delegate is nil!
If I create delegate without question mark, the code working as expected.But when I use optional type, I cant assign viewcontroller class as a delegate.
Since self.tcpClientdelegate is nil then appending ? operator will cause whole statement not to be run => which causes that delegate to be un-assinged = nil
self.tcpClientdelegate? = client
so replace with
self.tcpClientdelegate = client
The problem lies in the init:
self.tcpClientdelegate? = client
The postfix ? operator will not carry out whatever operation you specified if its operand is nil.
Here, self.tcpClientdelegate is nil, so the value is not assigned.
From the Swift Language Reference:
Optional-chaining expressions must appear within a postfix expression,
and they cause the postfix expression to be evaluated in a special
way. If the value of the optional-chaining expression is nil, all of
the other operations in the postfix expression are ignored and the
entire postfix expression evaluates to nil.
Just assign it normally to fix the problem, because you don't care about whether self.tcpClientdelegate was nil or not:
self.tcpClientdelegate = client
Related
I have this sample protocol having a default valued property with extension.
protocol SampleProtocol{
var sample:String?{get set}
}
extension SampleProtocol{
var sample:String?{ get { return nil } set{} }
}
Now, my TestClass implements SampleProtocol as below.
class TestClass:SampleProtocol {
var sample: String?{
return "TestClass"
}
}
And there's one helper method that prints a sample value from the SampleProtocol.
func printValue(_ value: SampleProtocol){
print(value.sample)
}
Now the problem is
let testObj = TestClass()
print(testObj.sample) // prints "TestClass"
printValue(testObj) // prints nil
From the above result, I need to understand why when the testObj is typecasted into SampleProtcol, it is considering default implementation from extension instead of the implementation from the TestClass?
The problem is that the TestClass is not implementing the SampleProtocol so when you pass it in the printValue method that takes a SampleProtocol, it will call the default implementation in the protocol extension(since the instance you pass does not implement the protocol method).
In the SampleProtocol you have defined the variable as {get set} but in the TestClass variable you have only provided a getter, this does not match the requirements (If you remove the protocol extension you will see an error that the class does not conform to the protocol).
It will work if you provide a setter:
class TestClass: SampleProtocol {
var sample: String? {
get {
return "TestClass"
} set { }
}
}
protocol BasePresenterProtocol : class {}
protocol DashboardPresenterProtocol : BasePresenterProtocol {}
final class DashboardPresenter {
weak var view: DashboardPresenterProtocol?
init() {
self.view = DashboardViewController()
}
func test() {
print("Hello")
}
}
extension DashboardPresenter: DashboardViewProtocol { }
protocol BaseViewProtocol : class {
weak var view: BasePresenterProtocol? { get set }
}
protocol DashboardViewProtocol : BaseViewProtocol {
}
class DashboardViewController {
}
extension DashboardViewController: DashboardPresenterProtocol { }
In the above code, I get an error at following line
extension DashboardPresenter: DashboardViewProtocol { }
that, DashboardPresenter doesn't confirm to protocol DashboardViewProtocol, but I have declared weak var view: DashboardPresenterProtocol? in DashboardPresenter . Although I have declared
Why am I getting this error ? Please let me know what I am doing wrong in this code.
You cannot implement a read-write property requirement of type BasePresenterProtocol? with a property of type DashboardPresenterProtocol?.
Consider what would happen if this were possible, and you upcast an instance of DashboardPresenter to DashboardViewProtocol. You would be able to assign anything that conforms to BasePresenterProtocol to a property of type DashboardPresenterProtocol? – which would be illegal.
For this reason, a read-write property requirement has to be invariant (although it's worth noting that a readable-only property requirement should be able to be covariant – but this currently isn't supported).
I am using Swift 2.2 on XCode 7.3.1 and trying to call a Generic function from another Generic function.
Code
class Thing1 {
let variable: SomeProtocol
init<A: SomeProtocol>(variable: A) {
self.variable = variable
self.add1(self.variable)
}
func add1<A: SomeProtocol>(stuff: A) {
let thing: Thing2 = Thing2()
thing.add2(stuff)
}
}
class Thing2 {
func add2<A: SomeProtocol>(stuff: A) {
}
}
protocol SomeProtocol { }
add1("a") // Cannot invoke 'add1' with an argument list of type '(String)'
add1(4) // Cannot invoke 'add1' with an argument list of type '(Int)'
I get the error.
'Cannot invoke add with an argument of list type '(Whatever type I used to call the function)''
The problem is that abstract types in Swift don't necessarily conform to themselves – therefore you cannot use a SomeProtocol typed thing as a concrete typed thing that conforms to SomeProtocol (which is what your add1 generic function expects as an argument).
The simplest solution in your case therefore is just to use the generic variable argument, rather than the variable property, as because it's a generic, it's typed as a concrete thing that conforms to SomeProtocol, which can therefore be passed into your add1 function:
init<A: SomeProtocol>(variable: A) {
self.variable = variable
add1(variable)
}
However in order to prevent these kind of issues later down the line, you may want to consider making your class generic, assuming that your variable property should be of constant type throughout the lifetime of a given Thing1 instance:
class Thing1<A:SomeProtocol> {
let variable: A
init(variable: A) {
self.variable = variable
add1(variable)
}
func add1(stuff: A) {
let thing = Thing2()
thing.add2(stuff)
}
}
Or, you could refactor your code to use the abstract type SomeProtocol, which will allow you to work with any type that conforms to SomeProtocol (e.g allowing you to mix different Thing1 instances with different variable types in an array):
class Thing1 {
let variable: SomeProtocol
init(variable: SomeProtocol) {
self.variable = variable
add1(variable)
}
func add1(stuff: SomeProtocol) {
let thing = Thing2()
thing.add2(stuff)
}
}
class Thing2 {
func add2(stuff: SomeProtocol) {
}
}
Although you should always be aware of the extra costs that come with using abstract types, see this great WWDC talk for more info.
Adding the extensions to String and Int and constructing Thing1 objects makes it work:
extension String: SomeProtocol{}
extension Int: SomeProtocol{}
Thing1(variable: "a").add1("a")
Thing1(variable: 2).add1(4)
I'm trying to check if an object is of a given type and I'm getting an error:
'expectedClass' is not a type
My code below.
func testInputValue(inputValue: AnyObject, isKindOfClass expectedClass: AnyClass) throws {
guard let object = inputValue as? expectedClass else {
// Throw an error
let userInfo = [NSLocalizedDescriptionKey: "Expected an inputValue of type \(expectedClass), but got a \(inputValue.dynamicType)"]
throw NSError(domain: RKValueTransformersErrorDomain, code: Int(RKValueTransformationError.UntransformableInputValue.rawValue), userInfo: userInfo)
}
}
I'm trying to figure out what can be wrong here.
You should be able to do this with generics:
func testInputValue<T>(inputValue: AnyObject, isKindOfClass expectedClass: T.Type) throws {
guard let object = inputValue as? T else {
...
}
}
You should not do class comparisons with == as suggested in one of the other answers, unless you specifically want to test if the type of the object tested should exactly match the expected class and it is not allowed to be a subclass of the tested class.
You can use the instance method isKindOfClass to accomplish this, taking subclassing into account. See below for a code example.
NOTE: You may be surprised that this works on a pure Swift class type, given an instance method with the same name exists in NSObject / NSObjectProtocol. It does indeed work in pure Swift (as shown with the example code below – tested with Xcode 7.3, Swift 2.2.1), with no #objc types involved, as long as you import Foundation. I am presuming based on this that this instance method is added as an extension method in Foundation to all class types.
import Foundation
class A { }
class B { }
class C: B { }
enum ValueTestError: ErrorType {
case UnexpectedClass(AnyClass)
}
func testInputValue(inputObj:AnyObject, isKindOfClass expectedClass:AnyClass) throws {
guard inputObj.isKindOfClass(expectedClass) else {
throw ValueTestError.UnexpectedClass(inputObj.dynamicType)
}
}
let a = A()
let b = B()
let c = C()
do {
try testInputValue(c, isKindOfClass: B.self)
} catch {
print("This does not get printed as c is of type B (C is subclass of B).")
}
do {
try testInputValue(a, isKindOfClass: B.self)
} catch {
print("This gets printed as a is not of type B.")
}
Also, importantly although isKindOfClass is available as an instance method on AnyObject, trying to call it on an arbitrary Swift class typed object will only work if you first cast that object to AnyObject (which will always of course succeed). Example code illustrating this point is presented below, and there's more on this question over here.
import Foundation
class A {}
let a = A()
// the following compiles and returns 'true'
(a as AnyObject).isKindOfClass(A.self)
// the following fails to compile with "Value of type 'A' has no member 'isKindOfClass'"
a.isKindOfClass(A.self)
Not the greatest answer ever, but comparing with inputValue.dynamicType works:
if inputValue.dynamicType == expectedClass {
print("inputValue.dynamicType \(inputValue.dynamicType) equals expectedClass \(expectedClass)")
// ...
}
I'd like to use swift generics in a way described below:
class ResponseContainer {
}
protocol DisplayManageable {
func getModel<ModelType: ResponseContainer>() -> ModelType?
}
class DisplayBaseManager<ObtainedModelType: ResponseContainer>: NSObject, DisplayManageable {
var modelObtained: ObtainedModelType? = nil
func getModel<ObtainedModelType>() -> ObtainedModelType? {
return modelObtained
}
}
But I have a problem with this code, more precisely there is a problem in this line:
return modelObtained
And I'm getting the error:
Cannot convert return expression of type 'ObtainedModelType?' to
return type 'ObtainedModelType?'
And now my simple question, why can't I do that? What's wrong with that?
Generics in protocol's function and in class definitions are the same. Everything looks fine in my opinion and logically is ok, so why cannot I do so?
In
func getModel<ObtainedModelType>() -> ObtainedModelType? { ... }
ObtainedModelType introduces a local generic placeholder, and that
hides the ObtainedModelType from the class definition
class DisplayBaseManager<ObtainedModelType: ResponseContainer>
This causes the strange looking error message
Cannot convert return expression of type 'ObtainedModelType?' to return type 'ObtainedModelType?'
because return modelObtained has the generic type ObtainedModelType? from the
class definition, but the expected return type is ObtainedModelType?
from the method definition.
What you probably want is a protocol with an associated type
protocol DisplayManageable {
associatedtype ModelType: ResponseContainer
func getModel() -> ModelType?
}
and a class adopting this protocol with ModelType == ObtainedModelType:
class DisplayBaseManager<ObtainedModelType: ResponseContainer>: NSObject, DisplayManageable {
var modelObtained: ObtainedModelType? = nil
func getModel() -> ObtainedModelType? {
return modelObtained
}
}
Łukasz, I don't now why it doesn't compile but I found the way to compile it. Just change the return statement:
return modelObtained as? ObtainedModelType
But I'm still waiting for someone to explain the reason for error in the original code.