I've searched quite a bit around and played within a playground but I had no success, so I ask here:
Any way to have variable containing a non-#objc protocol metatype and then call class/static methods from it?
e.g.:
protocol MyProtocol {
class func myFunc() -> Int
}
enum MyEnum: Int, MyProtocol {
case A
case B
static func myFunc() -> Int { return A.rawValue }
}
let foo: MyProtocol.Type = MyEnum.self
let bar = foo.myFunc()
p.s. it says the last call is unimplemented, so should I expect it in a future Swift release?
UPDATED for Swift Version 2.0 and above
Swift 2.0+ allows methods to be declared as static in the protocol definition. These must be satisfied with static/class methods in objects that implement the protocol.
You cannot satisfy a protocol definition for a instance method with a static method or vice-versa, which makes this an incomplete answer for the question above.
If you want to try this just use the keyword "static" in your protocol definition for methods you will implement as static or class methods in your conforming objects:
protocol InstanceVsStatic {
func someInstanceFunc()
static func someStaticFunc()
}
enum MyConformingEnum: InstanceVsStatic {
case someCase
static func someStaticFunc() {
// code
}
func someInstanceFunc() {
// code
}
}
class MyConformingClass: InstanceVsStatic {
class func someStaticFunc() {
// code
}
func someInstanceFunc() {
// code
}
}
struct MyConformingStruct: InstanceVsStatic {
static func someStaticFunc() {
// code
}
func someInstanceFunc() {
// code
}
}
You can have an instance method call a static/class method:
This allows you to execute static code when you need to conform to a protocol that requires an instance method.
struct MyConformingStruct: InstanceVsStatic {
static func doStuffStatically(){
// code
}
static func someStaticFunc() {
// code
}
func someInstanceFunc() {
MyConformingStruct.doStuffStatically()
}
}
Swift 1.2
Other than indirectly as above, there is no way to use static (class) methods to conform to a protocol in pure swift version 1.2 and below. It is a known bug / unimplemented feature: https://openradar.appspot.com/20119848
Class methods are only allowable in classes and protocols; an enum is neither.
Class methods are one type of Swift "type methods"; the other type is a static method, which is what you've declared in your enum. Class and static methods are different.
See the Swift methods docs for a few different patterns and examples.
p.s. it says the last call is unimplemented, so should I expect it in a future Swift release?
Yes.
Related
Problem
I have a type that takes one generic parameter that is required to inherit from UIView:
class Handler<View: UIView> {
...
}
Now, I want write a UIView extension to provide a property that returns Handler and uses Self as the generic parameter, so that in subclasses of UIView I'd always get the handler of type Handler<UIViewSubclass>:
extension UIView {
var handler: Handler<Self>? { return nil }
}
However this does not compile:
Covariant 'Self' can only appear at the top level of property type
I have also tried to define a protocol HandlerProvider first:
public protocol HandlerProvider {
associatedtype View: UIView
var handler: Handler<View>? { get }
}
(so far so good) and then extend UIView with that protocol:
extension UIView: HandlerProvider {
public typealias View = Self
public var handler: Handler<View>? { return nil }
}
But that does not compile either:
Covariant 'Self' can only appear as the type of a property, subscript or method result; did you mean 'UIView'?
Question
Is there a way in Swift to use Self as a generic parameter for properties in extension?
Here is possible approach (to think with generics in a bit different direction).
Tested with Xcode 11.4 / swift 5.2
// base handling protocol
protocol Handling {
associatedtype V: UIView
var view: V { get }
init(_ view: V)
func handle()
}
// extension for base class, will be called by default for any
// UIView instance that does not have explicit extension
extension Handling where V: UIView {
func handle() {
print(">> base: \(self.view)")
}
}
// extension for specific view (any more you wish)
extension Handling where V: UIImageView {
func handle() {
print(">> image: \(self.view)")
}
}
// concrete implementer
class Handler<V: UIView>: Handling {
let view: V
required init(_ view: V) {
self.view = view
}
}
// testing function
func fooBar() {
// handlers created in place of handling where type of
// handling view is know, so corresponding handle function
// is used
Handler(UIView()).handle()
Handler(UIImageView()).handle()
}
Output:
I'm trying to write a generic class function for Swift classes that would allow me to initialize classes using trailing closure syntax.
I have already got it working for specific classes, like for example UILabel.
// Extension for UILabel
extension UILabel {
class func new(_ initialization: (inout UILabel) -> Void) -> UILabel {
var label = UILabel()
initialization(&label)
return label
}
}
// Initialize new UILabel using trailing closure syntax and "new" function
let label = UILabel.new {
$0.textColor = .red
}
However, I want to have this functionality for all subclasses of NSObject, so I'm trying to implement a generic version of the "new" function above. So far I have come up with this:
extension NSObject {
class func new(_ initialization: (inout Self) -> Void) -> Self {
var newSelf = Self()
initialization(&newSelf)
return newSelf
}
}
But this produces the following error: 'Self' is only available in a protocol or as the result of a method in a class; did you mean 'NSObject'?
I am trying this in a playground with Swift 5.1 (Xcode 11 beta).
As Hamish said, maybe it's better to leave the init outside so it is more flexible. However there could be a kind of workaround for this using a protocol.
protocol Initializable {
init()
}
extension Initializable {
static func new(_ initialization: (inout Self) -> Void) -> Self {
var newSelf = Self()
initialization(&newSelf)
return newSelf
}
}
extension NSObject: Initializable {}
NSObject already have an init so it automatically conforms to Initializable.
Then write your extension on the protocol.
The only thing to be aware is that you cannot use class modifier now, as you're in a protocol.
Not sure if this can lead to problem for the NS_UNAVAILABLE modifier, I think it could crash at runtime when you use this on a class that is hiding the init.
So I was thinking about a custom pattern in my project, but I can't get it to work. The main idea is to change the typealias on every subclass to get access to the subclass specific interface.
protocol InstanceInterface: class {
typealias Interface
var interface: Interface { get }
}
// Baseclass
protocol FirstClassInterface: class { /* nothing here for the example */ }
class FirstClass: InstanceInterface, FirstClassInterface {
typealias Interface = FirstClassInterface
var interface: Interface { return self }
}
// Subclass
protocol SecondClassInterface: FirstClassInterface {
func foo()
}
class SecondClass: FirstClass, SecondClassInterface {
typealias Interface = SecondClassInterface // <--- This does nothing :(
func foo() { print("hello world") } // Swift 2.0 here
}
// Lets say I want to call foo trough the interface
let test = SecondClass()
test.interface.foo() // 'Interface' does not have a member named 'foo'
Is there something I'm doing wrong or do I misunderstand some Swift concepts here?! I do need to subclass here to not to implement everything from super class' protocols over and over again. Is my little pattern even possible? I'd appreciate any help. :)
Would something like this work for your purposes?
class MyClass<T> {
}
class MySubclass1: MyClass<String> {
}
class MySubclass2: MyClass<Int> {
}
Unfortunately there is no good workaround for this problem.
The main idea to override the typealias would work in this case but consider the following:
protocol TakeAndGet {
typealias T
func take(value: T)
func get() -> T
}
class FirstClass: TakeAndGet {
typealias T = FirstClass
var property = 0
func take(value: T) {
value.property = 4
}
func get() -> T {
return FirstClass()
}
}
class SecondClass: FirstClass {
typealias T = SecondClass
var property2 = "hello"
}
If the typealias of the SecondClass overrides the other one the take method would work since it takes a subclass which can be treated as the superclass. But the get method cannot implicitly convert FirstClass to SecondClass. Therefore it is not possible to override a typealias.
Now if we want to override the get function with get() -> SecondClass it wouldn't work since it has not the same signature as the one in the superclass. In addition we inherit the get method which results in an ambiguous use:
SecondClass().get() // which type gets returned? SecondClass or FirstClass
So you have to try a different approach.
I am not sure, it looks to me that it is some kind of bug or bad implementation with protocol extensions in Swift 2.0.
I have protocolA, protocolB extending protocolA and implementing methods in protocolB extension.
I have conformed an class instance to conform to protocolB, however when inspected by respondsToSelector for protocolA/B methods the results is false.
import Cocoa
import XCPlayground
protocol ProtocolA : NSObjectProtocol {
func functionA()
}
protocol ProtocolB : ProtocolA {
func functionB()
}
extension ProtocolB {
func functionA() {
print("Passed functionA")
}
func functionB() {
print("Passed functionB")
}
}
class TestClass : NSObject, ProtocolB {
override init () {
}
}
var instance:TestClass = TestClass()
instance.functionA() // Calls code OK..
if instance.respondsToSelector("functionA") {
print("Responds to functionA") // **False, never passing here**
}
if instance.respondsToSelector("functionB") {
print("Responds to functionB") // **False, never passing here**
}
Should be reported as a bug?
Interesting. Looks like a bug to me. It does recognize functions on a class, but not on extension. No matter what type Instance has. Moreover without an extension code would not be compilable, since protocol methods are non optional. So really looks like a bug/feature? in responds to selector implementation.
Is there a standard way to make a "pure virtual function" in Swift, ie. one that must be overridden by every subclass, and which, if it is not, causes a compile time error?
You have two options:
1. Use a Protocol
Define the superclass as a Protocol instead of a Class
Pro: Compile time check for if each "subclass" (not an actual subclass) implements the required method(s)
Con: The "superclass" (protocol) cannot implement methods or properties
2. Assert in the super version of the method
Example:
class SuperClass {
func someFunc() {
fatalError("Must Override")
}
}
class Subclass : SuperClass {
override func someFunc() {
}
}
Pro: Can implement methods and properties in superclass
Con: No compile time check
The following allows to inherit from a class and also to have the protocol's compile time check :)
protocol ViewControllerProtocol {
func setupViews()
func setupConstraints()
}
typealias ViewController = ViewControllerClass & ViewControllerProtocol
class ViewControllerClass : UIViewController {
override func viewDidLoad() {
self.setup()
}
func setup() {
guard let controller = self as? ViewController else {
return
}
controller.setupViews()
controller.setupConstraints()
}
//.... and implement methods related to UIViewController at will
}
class SubClass : ViewController {
//-- in case these aren't here... an error will be presented
func setupViews() { ... }
func setupConstraints() { ... }
}
There isn't any support for abstract class/ virtual functions, but you could probably use a protocol for most cases:
protocol SomeProtocol {
func someMethod()
}
class SomeClass: SomeProtocol {
func someMethod() {}
}
If SomeClass doesn't implement someMethod, you'll get this compile time error:
error: type 'SomeClass' does not conform to protocol 'SomeProtocol'
Another workaround, if you don't have too many "virtual" methods, is to have the subclass pass the "implementations" into the base class constructor as function objects:
class MyVirtual {
// 'Implementation' provided by subclass
let fooImpl: (() -> String)
// Delegates to 'implementation' provided by subclass
func foo() -> String {
return fooImpl()
}
init(fooImpl: (() -> String)) {
self.fooImpl = fooImpl
}
}
class MyImpl: MyVirtual {
// 'Implementation' for super.foo()
func myFoo() -> String {
return "I am foo"
}
init() {
// pass the 'implementation' to the superclass
super.init(myFoo)
}
}
You can use protocol vs assertion as suggested in answer here by drewag.
However, example for the protocol is missing. I am covering here,
Protocol
protocol SomeProtocol {
func someMethod()
}
class SomeClass: SomeProtocol {
func someMethod() {}
}
Now every subclasses are required to implement the protocol which is checked in compile time. If SomeClass doesn't implement someMethod, you'll get this compile time error:
error: type 'SomeClass' does not conform to protocol 'SomeProtocol'
Note: this only works for the topmost class that implements the protocol. Any subclasses can blithely ignore the protocol requirements. – as commented by memmons
Assertion
class SuperClass {
func someFunc() {
fatalError("Must Override")
}
}
class Subclass : SuperClass {
override func someFunc() {
}
}
However, assertion will work only in runtime.
This is what I usually do, to causes the compile-time error :
class SuperClass {}
protocol SuperClassProtocol {
func someFunc()
}
typealias SuperClassType = SuperClass & SuperClassProtocol
class Subclass: SuperClassType {
func someFunc() {
// ...
}
}
You can achieve it by passing function into initializer.
For example
open class SuperClass {
private let abstractFunction: () -> Void
public init(abstractFunction: #escaping () -> Void) {
self.abstractFunction = abstractFunction
}
public func foo() {
// ...
abstractFunction()
}
}
public class SubClass: SuperClass {
public init() {
super.init(
abstractFunction: {
print("my implementation")
}
)
}
}
You can extend it by passing self as the parameter:
open class SuperClass {
private let abstractFunction: (SuperClass) -> Void
public init(abstractFunction: #escaping (SuperClass) -> Void) {
self.abstractFunction = abstractFunction
}
public func foo() {
// ...
abstractFunction(self)
}
}
public class SubClass: SuperClass {
public init() {
super.init(
abstractFunction: {
(_self: SuperClass) in
let _self: SubClass = _self as! SubClass
print("my implementation")
}
)
}
}
Pro:
Compile time check for if each subclassimplements the required method(s)
Can implement methods and properties in superclass
Note that you can't pass self to the function so you won't get memory leak.
Con:
It's not the prettiest code
You can't use it for the classes with required init
Being new to iOS development, I'm not entirely sure when this was implemented, but one way to get the best of both worlds is to implement an extension for a protocol:
protocol ThingsToDo {
func doThingOne()
}
extension ThingsToDo {
func doThingTwo() { /* Define code here */}
}
class Person: ThingsToDo {
func doThingOne() {
// Already defined in extension
doThingTwo()
// Rest of code
}
}
The extension is what allows you to have the default value for a function while the function in the regular protocol still provides a compile time error if not defined