Class-Only Protocols in Swift - ios

I want some of my classes (not all) to conform using 'Class-Only Protocols' from docs. What I am doing is
protocol RefreshData: class, ClassA, ClassB
{
func updateController()
}
and I am getting the errors
non class type 'RefreshData cannot inherit from classA
non class type 'RefreshData cannot inherit from classB
I'm not sure I am following exactly as in the docs. Does anyone have any ideas about this?

Swift 4 allows you to combine types, so you can have your protocol and then create, for example, a type alias to combine it with a specific class requirement.
For (a contrived) example:
typealias PresentableVC = UIViewController & Presentable
For the presented code:
The problem is that you're trying to limit to specific classes and Swift can't do that (at the moment anyway). You can only limit to classes and inherit from other protocols. Your syntax is for protocol inheritance but you're trying to use it as a class limitation.
Note that the purpose of class protocols is:
Use a class-only protocol when the behavior defined by that protocol’s requirements assumes or requires that a conforming type has reference semantics rather than value semantics.

The answers provided by Chris and Wain are correct. I'm just adding a few more details here.
Defining a protocol
You must distinguish the concept of declaring a protocol (available for classes)
protocol RefreshData: class {
func updateController()
}
Defining a class
...from the concept of conforming your class to a protocol
class ClassA: RefreshData {
func updateController() {
}
}
Conforming a class you don't own
Sometimes you want to conform a class to a protocol but you don't own the source code for that class. In this case you can use an extension
extension ClassB: RefreshData {
func updateController() {
}
}

Latest version of Swift can do it!
I would do a protocol and protocol extensions that target the classes you want! (constraint the extension to specific class)
protocol Movable {
func moveForward()
func moveBackward()
}
extension Movable where Self: Car {
func moveForward() {
self.location.x += 10;
}
func moveBackward() {
self.location.x -= 10;
}
}
extension Movable where Self: Bike {
func moveForward() {
self.x += 1;
}
func moveBackward() {
self.x -= 1;
}
}
class Car: Movable {
var location: CGPoint
init(atLocation location: CGPoint) {
self.location = location
}
}
class Bike: Movable {
var x: Int
init(atX x: Int) {
self.x = x
}
}

protocol RefreshData : class
{
func updateController()
}
class ClassA : RefreshData
{
func updateController() {}
}
class ClassB : RefreshData
{
func updateController() {}
}

Related

Non-'#objc' method does not satisfy requirement of '#objc' protocol [duplicate]

This question already has answers here:
Non-'#objc' method does not satisfy optional requirement of '#objc' protocol
(3 answers)
Closed 1 year ago.
I've put the following into a Playground to try and understand this and I just don't:
import Foundation
#objc protocol Sample {
var value: Int { get set }
func increase()
func decrese()
}
extension Sample {
func increase() {
value += 1
}
func decrease() {
value -= 1
}
}
class Test: Sample {
var value: Int = 0
}
The error appears next to the class declaration for Test saying:
Non-'#objc' method 'increase()' does not satisfy requirement of '#objc' protocol 'Sample'
If I re-declare increase() and decrease() in the class then the warning is silenced. Or also if I remove the declarations from the protocol. Could someone please explain?
EDIT
I do need an Objective-C class to conform to this protocol as well, hence the #objc at the start.
The problem is that you’re defining these methods in a protocol extension. This is used to define a “default implementation” for a protocol (i.e. if a type doesn’t implement the method, the protocol’s implementation will be called).
But Objective-C doesn’t have the concept of default implementations for protocols. So it doesn’t makes sense to declare the protocol as #objc and have default implementations within the Swift protocol extension. An Objective-C class conforming to this protocol would never be able to enjoy these Swift default implementations.
The below code works with empty protocol methods' implementation in the Protocol extension class
import Foundation
protocol Sample {
var value: Int { get set }
func increase()
func decrease()
}
extension Sample {
func increase() { }
func decrease() { }
}
class Test: Sample {
var value: Int = 0
}
or if you want some default implementation of Sample protocol methods in the extension then use
import Foundation
protocol Sample {
var value: Int { get set }
func increase()
mutating func decrease()
}
extension Sample {
func increase() {
print("do anything")
}
mutating func decrease() {
value -= 1
}
}
class Test: Sample {
var value: Int = 0
}
mutating is added before the protocol method decrease() because it modifies the Protocol variable value.
If the Protocol extension doesn't modify any of the Protocol variable (e.g. increase()), then there is no need of mutating keyword

Extend a Protocol with Multiple Constraints for One OR the Other - Swift

I want to extend protocol with a default implementation that satisfies OR ( || ) constraint.
class A { }
class B { }
protocol SomeProtocol { }
/// It will throw error for ||
extension SomeProtocol where Self: A || Self: B {
}
You can't extend a protocol with OR as you can't do it in a if let, because with this the compiler infers the type of self or of the var, so if it conforms 2 types, the compiler doesn't know of what type is self.
(When you type self. or any var. the compiler always knows what type of var is in compiler type, in that case it would be in runtime). So the easiest way is to make that the 2 types conforms a protocol and do a extension of that protocol. So the compiler knows that self conforms a protocol and he doesn't care of the exact type of Self (But you will be able to use only the properties declared in the protocol).
protocol ABType {
// Properties that you want to use in your extension.
}
class A: ABType, SomeProtocol { }
class B: ABType, SomeProtocol { }
protocol SomeProtocol { }
extension SomeProtocol where Self: ABType {
}
Also if you want to apply the extension to both types you have to do it one by one.
extension A: SomeProtocol { }
extension B: SomeProtocol { }
// Silly example:
(In this case is not really useful, but it is just to show how to make to make 2 classes conforms a protocol and to make a extension of it using a method declared in that protocol and creating a default implementation.)
protocol ABType {
func getName()
}
class AClass: ABType {
func getName() {
print ("A Class")
}
}
class BClass: ABType, someProtocol {
func getName() {
print ("B Class")
}
}
protocol someProtocol {
func anotherFunc()
}
extension someProtocol where Self: ABType {
func anotherFunc() {
self.getName()
}
}
let a = AClass()
// a.anotherFunc() <- Error, A cant call anotherFunc
let b = BClass()
b.anotherFunc()

Conformance issues even after fulfilling requirements using protocol extensions for #objc protocols

Let us consider this example which compiles without any issues :
protocol AProtocol {
func veryImportantMethod()
}
protocol BProtocol : AProtocol {
}
extension BProtocol {
func veryImportantMethod() {
print("A's protocol requirement satisfied!")
}
}
class ConcreteClass : BProtocol {
}
However, if we do this :
#objc protocol AProtocol { //Added #objc here
func veryImportantMethod()
}
protocol BProtocol : AProtocol {
}
extension BProtocol {
func veryImportantMethod() {
print("A's protocol requirement satisfied!")
}
}
class ConcreteClass : BProtocol {
}
It doesn't compile with a message saying :
Type 'ConcreteClass' does not conform to protocol 'AProtocol'
However, if we actually implement it,
class ConcreteClass : NSObject, BProtocol {
func veryImportantMethod() { }
}
the code compiles. Why is this happening? Is there anything that I am missing here?
I am trying to achieve this form of protocol hierarchy for UITableViewDataSource and I really do not want to repeat tableView:cellForRowAtIndexPath: code across conformants.
The compiler wants to make sure that the class can be compiled with ObjC. Once you inherit from an ObjC class (like NSObject) the compiler knows it, but you implement the extension before that point. You could avoid the error by defining the protocol to be implemented by a class that inherits from NSObject, like this:
#objc protocol AProtocol {
func veryImportantMethod()
}
protocol BProtocol : AProtocol {
}
class BProtocolClass: NSObject {
}
extension BProtocolClass {
func veryImportantMethod() {
print("A's protocol requirement satisfied!")
}
}
class ConcreteClass: BProtocolClass {
}

Delegate a structure in swift?

I am developing an app to increase a little more my knowledge about swift. One of my questions if is it possible to delegate a optional function with a structure as an argument.
What yes Im able to do:
#objc protocol someProtocol {
optional func optionalFunc(someClass: someClass)
}
class someClass: NSObject {
}
But, what I want to do (problems representing a structure in objc):
#objc protocol someProtocol {
optional func optionalFunc(someStructure: someStructure)
}
struct someStructure {
}
And Im not able to find the way to solve this problem.
And the other thing I want, is similar to this but with enums instead of structs:
#objc protocol someProtocol {
optional func optionalFunc(someEnum: someEnum)
}
enum someEnum {
case example
}
If somebody can help me, I will be very grateful!
Lot of thanks! Luciano!
Swift 2.0 lets you do default implementations of protocols.
protocol someProtocol {
func optionalFunc(someStructure: SomeStructure)
}
extension someProtocol {
func optionalFunc(someStructure: SomeStructure){
// optional, leave empty
}
}
struct SomeStructure {
}
This way you can get around using the optional-decoration and do what you wanted.
You cannot pass the parameters as struct or enum, because it's only valid on Swift language, so it cannot be represented in Objective-C.
Another approach, you can declare a function as variable instead of func:
protocol someProtocol {
var optionalFunc: (someStructure) -> ()? { get set}
}
Implementation:
class someClass : someProtocol {
var optionalFunc: (someStructure) -> ()? = { yourStruct in
// Do anything with yourStruct
return
}
}
Using:
var someVar:someClass = someClass()
var result = someVar.optionalFunc(someStructure())
The result is a ()?. If you do not implement the variable, result will nil

How to declare a function with a concrete return type conforming to a protocol?

EDIT:
This question was written before swift added the some keyword, making it obsolete
In objective-c I could declare a method with a return type:
-(UIView<MyProtocol> *)someMethod;
In this example the method returns a UIView that conforms to a protocol MyProtocol.
I want to do something like that in swift:
protocol MyProtocol {
var someProperty : Int {get set}
}
protocol MyDelegate {
func someMethod() -> UIView : MyProtocol // the view should conform to the protocol - I don't care what kind of view it is - I don't want to define a specific type of view
}
In general - The delegate should return a UIView with the var "someProperty"
I don't want to define a concrete UIView class.
I want the user to be able to return any type of UIView (As long as it conforms to the protocol)
The syntax I wrote is invalid - How should I be writing it?
You could just use the protocol as type:
protocol MyDelegate {
func someMethod() -> MyProtocol
}
And use it like this:
protocol MyProtocol {
var someProperty : Int {get set}
}
class CustomView: UIView, MyProtocol {
var someProperty = 2
}
protocol MyDelegate {
func someMethod() -> MyProtocol
}
struct Delegate: MyDelegate {
func someMethod() -> MyProtocol {
return CustomView()
}
}
let delegate = Delegate()
let view = delegate.someMethod()
let property = view.someProperty // property = 2
This is not possible in Swift. Not everything possible in Obj-C has to be possible in Swift. When creating a type requirement you can only combine protocols using the protocol<..., ...> syntax but you can't combine a class and a protocol.
Technically, this should be good for your architecture. You can probably find a workaround but I would advice against it. There is a reason to avoid combining classes with protocols because the interfaces are much more difficult to handle. Most OOP languages don't have that syntax. Many commonly used languages don't even have a syntax to combine protocols.
protocol MyProtocol {
var someProperty : Int {get set}
}
protocol MyDelegate {
func someMethod<T: UIView & MyProtocol>() -> T // the view should conform to the protocol - I don't care what kind of view it is - I don't want to define a specific type of view
}
class MyDelegateTestView : UIView, MyProtocol {
var someProperty: Int = 10
}
class MyDelegateTestClass : MyDelegate {
func someMethod<T>() -> T where T : UIView, T : MyProtocol {
return MyDelegateTestView() as! T
}
}
The question was written before the days of swift-ui
The "some" keyword has solved it by allowing opaque types to be returned from functions
protocol MyDelegate {
func someMethod() -> some MyProtocol
}
Here below is a way.
func myMethod(string: String) -> MyClass:MyProtocol? {
}
You can use without optional type as MyClass: MyProtocol.

Resources