So I have a protocol, and in it I want a variable that is a class type. That way I can init that class from the variable.
Keep in mind that there will be many different classes. I made a quick example.
I get the error "type 'CashRegister' does not conform to protocol 'RegisterProtocol'"
This example isn't exactly what I'm doing, but it gets the point across. Thanks for the help.
protocol RegisterProtocol {
var currentBill: DollarBillProtocol {get set}
func makeNewBill()->DollarBillProtocol
}
extension RegisterProtocol {
func printCurrentBill() {
Swift.print(currentBill)
}
}
class CashRegister: RegisterProtocol {
var currentBill = OneDollarBill.self
func makeNewBill() -> DollarBillProtocol {
return currentBill.init()
}
}
protocol DollarBillProtocol {
// protocol that all bills have in common
}
class OneDollarBill: DollarBillProtocol {
required init(){
}
}
class FiveDollarBill: DollarBillProtocol {
required init(){
}
}
The way you declare currentBill in CashRegister makes it a var of type class. But the protocol RegisterProtocol requires this variable to be of type DollarBillProtocol in any class that implements the protocol. The compile error is because of this mismatch.
To make this more clear, you could declare the var with the explicit type, as follows:
class CashRegister: RegisterProtocol {
var currentBill: DollarBillProtocol = OneDollarBill() // or other initial value
}
Related
I am implementing HasDelegate protocol to the IWDeviceManager.
In all the posts which I have read, no one has wrote getter & setter for this public var delegate property.
The compiler is explicitly asking me to write getter & setter for public var delegate. Why it's required in my case?
I tried writing but my code crashes when I try to get or set the delegate.
How do I solve this issue?
I have shared the code below
extension IWDeviceManager: HasDelegate {
public typealias Delegate = IWDeviceManagerDelegate
// Compiler explicitly asks to write getter and setter for this.
public var delegate: IWDeviceManagerDelegate? {
get { // Crashes here
return IWDeviceManager.shared()?.delegate
}
set(newValue) { // crashes here
IWDeviceManager.shared()?.delegate = newValue
}
}
}
Below is interface for IWDeviceManager
open class IWDeviceManager : NSObject {
weak open var delegate: IWDeviceManagerDelegate!
open class func shared() -> Self!
open func initMgr()
open func initMgr(with config: IWDeviceManagerConfig!)
}
Instead of using HasDelegate try this:
class IWDeviceManagerDelegateProxy
: DelegateProxy<IWDeviceManager, IWDeviceManagerDelegate>
, DelegateProxyType
, IWDeviceManagerDelegate {
init(parentObject: IWDeviceManager) {
super.init(parentObject: parentObject, delegateProxy: IWDeviceManagerDelegateProxy.self)
}
static func currentDelegate(for object: IWDeviceManager) -> Delegate? {
return object.delegate
}
static func setCurrentDelegate(_ delegate: IWDeviceManagerDelegate?, to object: IWDeviceManager) {
object.delegate = delegate
}
static func registerKnownImplementations() {
self.register { IWDeviceManagerDelegateProxy(parentObject: $0) }
}
}
I am not familiar with Objective-C so I am not able to understand this.
My message structure is different than JSQMessage so I want to create my own class.
Here is my class
class ChatMessage:NSObject {
var createdAt:Double?
var createdName:String?
var createdUid:String?
var imageUrl:String?
var name:String?
var text:String?
var uColor:String?
var uid:String?
}
If you're implementing this in Swift, and you want to make it usable within that framework, you should make your class conform to JQMessageData. You just need to implement the required methods and variables.
class ChatMessages: NSObject, JSQMessageData {
// MARK: Required methods
func senderId() -> String! {
// your code here, return a unique ID for your sender
}
func senderDisplayName() -> String! {
// your code here, return the display name of your sender
}
func date() -> Date! {
// your code here, return your message date
}
func isMediaMessage() -> Bool {
// your code here, return whether your message contains media
}
func messageHash() -> UInt {
// your code here, return a unique identifier for your message
}
// MARK: Optional methods
func text() -> String! {
// your code here, return your message text
}
func media() -> JSQMessageMediaData! {
// your code here, return your message media if required
}
// MARK: Other methods and variables
// ...
}
Check the documentation for what to return in those methods.
There are a number of other questions floating around with various complicated answers for this question, but as far as I can see, none of them answer the basic question being posed:
How do you write a factory function that takes a type and returns an instance when the return type is known?
That is:
func factory<T>(T) -> Fooish { ... }
// Usage:
class Something : Fooish { ... }
let x:Fooish = factory(Something)
For example, this code:
public class Fooish {
var x:String = ""
public func foo() -> String {
return x
}
}
public class FooA : Fooish {
public override init() {
super.init()
x = "Hello"
}
}
public class FooB : Fooish {
public override init() {
super.init()
x = "World"
}
}
// This works
print(FooA().foo())
print(FooB().foo())
// This does not work
func factory<U>(type:U) -> Fooish {
return U()
}
print(factory(FooA).foo())
print(factory(FooB).foo())
Results in this error:
Sources/main.swift:32:10: error: 'U' cannot be constructed because it has no accessible initializers
return U()
^
<unknown>:0: error: build had 1 command failures
So what is the bound to place on T, such that we can call T() and know that the returned instance is a some Fooish?
Some answers suggest using a protocol for it, such as:
protocol IsFoo {
init()
}
factory<T: IsFoo>(t:T) -> Fooish { .. }
However, this doesn't seem to work:
error: cannot invoke 'factory' with an argument list of type '((FooA).Type)'
expected an argument list of type '(U)'
Every answer to this question seems to have multiple conflicting and updated answers; please, just simply post the snippet above, with a working implementation of the function factory, for swift 2.2.
Make a protocol which defines a common initializer to be called by the factory method:
protocol FactoryInitializable {
init ()
}
func factory<T: FactoryInitializable>(type: T.Type) -> T {
return T()
}
public class Fooish {
var x = ""
public func foo() -> String {
return x
}
}
public class FooA : Fooish, FactoryInitializable {
required public override init() {
super.init()
x = "This is FooA"
}
}
public class FooB : Fooish, FactoryInitializable {
required public override init() {
super.init()
x = "This is FooB"
}
}
let a = factory(FooA)
let b = factory(FooB)
print(a.x) // print: This is FooA
print(b.x) // print: This is FooB
Currently I'm working on my new App written with Swift 2.0. Today I faced two strange errors in Xcode beta 5. I'd love if someone with a previous beta version of Xcode can confirm if I'm right or not. I also could misunderstand something, so I'll appreciate any feedback.
Here is some example code that made me struggle a while:
// Frist bug
protocol SomeProtocol {
var someArray: [String] { get set } // #1 bug
}
extension SomeProtocol {
func someFunction(someString: String) {
self.someArray.append(someString) // #1: Immutable value of type '[String]' only has mutating members named 'append'
}
}
// Second bug
protocol SomeInterfaceProtocol {
var someBool: Bool { get set } // #2 bug
}
class SomeClass: SomeInterfaceProtocol {
var someBool: Bool = false
func returnInterface() -> SomeInterfaceProtocol {
return self
}
}
let someInstance = SomeClass()
// can't set the value
someInstance.returnInterface().someBool = true // #2: Cannot assign to property: function call returns immutable value
The first error can be solved if you add the modifier mutating before the extension func declaration like this:
mutating func someFunction(someString: String) {
I suspect that's a change in the language.
The other one puzzles me as well. At least, here's a work-around:
var c = someInstance.returnInterface()
c.someBool = true
I think the second one isn't a bug as well for the same reason that you can't modify an item in a dictionary directly, or that you can't change elem in for elem in array { ... }.
Something has to be saved to be able to change it. Because you're returning the protocol type, the compiler can't know whether it's a struct or a class, whereas if it's a struct the operation of changing it would have no effect because it's not persisted in any way and structs aren't passed by reference. That's why Thomas' workaround works. Maybe it'll work too if returnInterface returned a class instance, instead of the protocol type.
EDIT: Just tried it out: Indeed it works either if you return SomeClass instead of SomeInterfaceProtocol or if you change the protocol to a class protocol, as it can't be a struct
protocol SomeInterfaceProtocol : class {
var someBool: Bool { get set }
}
class SomeClass: SomeInterfaceProtocol {
var someBool: Bool = false
func returnInterface() -> SomeInterfaceProtocol {
return self
}
}
or
protocol SomeInterfaceProtocol {
var someBool: Bool { get set }
}
class SomeClass: SomeInterfaceProtocol {
var someBool: Bool = false
func returnInterface() -> SomeClass {
return self
}
}
both work
I'm trying to write a generic class in Swift who's generic type both inherits from a class and conforms to a protocol. However, the following code results in a compiler crash with Segmentation fault: 11.
protocol Protocol {
var protocolProperty: Any? { get }
}
class Class {
var classProperty: Any?
}
class GenericClass<T: Class where T: Protocol> {
var genericProperty: T?
func foo() {
let classProperty: Any? = genericProperty!.classProperty
// This is the culprit
let protocolProperty: Any? = genericProperty!.protocolProperty
}
}
Commenting out the access to the protocol property allows the program to compile. There is no way to access anything from the protocol without the compiler crashing. Is there a workaround to creating a generic class that works like this?
As MikeS notes, you should open a radar for the crash. It should never crash.
But the solution is to focus on what protocol (i.e. list of methods) you actually need T to conform to rather than getting wrapped up in the class. For instance:
protocol WhatGenericClassHolds : Protocol {
var classProperty: Any? { get }
}
class GenericClass<T: WhatGenericClassHolds> { ... }
There is a problem in your declaration. conform your class to the protocol as below
protocol A {
var somePropertyInt : Int? {get }
}
class B:A {
var someProperty : String?
var somePropertyInt:Int?;
}
class GenericClass<T: B where T: A > {
var someGenericProperty : T?
func foo() {
println(someGenericProperty!.someProperty)
println(someGenericProperty!.somePropertyInt)
}
}
var someGen = GenericClass()
someGen.someGenericProperty?.somePropertyInt
someGen.someGenericProperty?.someProperty