Swift delegate does not inherit NSObject - ios

I am trying to implement some sort of delegate broadcaster (Observer Pattern) in Swift to register multiple delegates. To use the "isEqual" function I need the generic to inherit from NSObject
To avoid duplicate code I prepared a generic DelegateBroadcaster:
import UIKit
class DelegateBroadcaster<T : NSObject>: NSObject {
var delegates : [T]
override init() {
delegates = []
}
func addDelegate(newDelegate : T) {
delegates.append(newDelegate)
}
func removeDelegate(oldDelegate : T) {
for i in 0...delegates.count-1 {
if (oldDelegate.isEqual(delegates[i])) {
delegates.removeAtIndex(i)
break
}
}
}
}
and subclass this for any specific broadcaster.
import UIKit
class NavigationControllerBroadcaster : DelegateBroadcaster<UINavigationControllerDelegate> {
}
But I get a strange error: "DelegateBroadcaster requires that 'UINavigationControllerDelegate' inherit from NSObject"
This is strange because the class reference by apple (Class Reference) says that UINavigationControllerDelegate inherits from NSObject.
So why do I get an error?

You are confusing class NSObject (NSObject class) and protocol NSObject (NSObject protocol, in Swift called NSObjectProtocol).
UINavigationControllerDelegate is a protocol and cannot inherit from class NSObject, it inherits from NSObjectProtocol (switch your documentation to Swift, you will see the difference).

UINavigationControllerDelegate is not a concrete type, it is a Protocol and therefore cannot be used as the type signature for the DelegateBroadcaster

Related

Protocol extensions where Self is generic

I have a BaseViewController that is defined this way:
open class BaseViewController<ViewModel: ViewModelType, View: BaseView>: UIViewController { ... }
I'm trying to write an extension for a protocol that has a default behaviour for all my BaseViewControllers. Something like this:
protocol MyProtocol {
func doStuff()
}
extension MyProtocol where Self: BaseViewController<BaseViewModel, BaseView> {
func doStuff() { ... }
}
However. If I only tells that the generic types are the BaseViewModel and BaseView it doesn't works for my subclasses, even though those are the most lower level classes used here.
How can I write my protocol extension in a way it will works for all my BaseViewController classes?

Trying to subclass GADRewardBasedVideoAdDelegate on Swift

I am trying to create a singleton class, subclass of GADRewardBasedVideoAdDelegate. Something like this:
import Foundation
import GoogleMobileAds
class MyAdsManager : GADRewardBasedVideoAdDelegate {
private let id : String = "MY_ADMOB_ID"
private var selector : (()->Void)?
static let instance: MyAdsManager = {
return MyAdsManager()
}()
class func getInstance() -> MyAdsManager {
return instance
}
private init() {
loadVideo()
}
//more methods
}
The error message is:
Type 'MyAdsManager' does not conform to protocol 'NSObjectProtocol'
I am not sure if I am doing this correctly, but implementing NSObjectProtocol is not something I am looking for...
Thank you in advance people.
Replace
class MyAdsManager : GADRewardBasedVideoAdDelegate
with
class MyAdsManager : NSObject, GADRewardBasedVideoAdDelegate
Reason
GADRewardBasedVideoAdDelegate inherits from NSObjectProtocol so you have to implement all methods listed in NSObjectProtocol and since these methods are implemented inside NSObject subclasses so it does the job for you

Protocol inheritance issue

I try to set up various protocols that work hand in hand. Unfortunately I cannot make them work the way I want. Looking at the following code, I think my goal is obvious: I want to require a class that conforms to a protocol X. If it conforms to protocol Y instead but protocol Y inherits from protocol X, it should be accepted as a conforming class too. Instead I receive the following compile error
Unable to infer associated type 'VC' for protocol 'ViewModelType'
Inferred type 'ExampleViewControllerType' (by matching requirement 'viewController') is invalid: does not conform to 'ViewType'
Current setup:
protocol ViewModelType: class {
associatedtype VC: ViewType
weak var viewController: VC! { get set }
}
class ExampleViewModel: ViewModelType {
weak var viewController: ExampleViewControllerType!
}
protocol ViewType: class { }
protocol ExampleViewControllerType: ViewType { }
class ExampleViewController: UIViewController, ExampleViewControllerType {
}
I can see what you are getting at with the 'transitive' protocols, however your error is caused by your associatedtype declaration of VC as seen in the error.
Unable to infer associated type 'VC' for protocol 'ViewModelType'
I think the compiler is having difficulty here maybe because its an innapropriate use of the associatedtype declaration.
An associatedtype can be thought of as a placeholder for an unknown type.
By defining VC as an associatedtype you are letting any class that inherits ViewModelType decide what type VC should be.
In ExampleViewModel class you do this by setting the type using typealias in the conforming class.
Your viewController can then be an ExampleViewControllerType without causing the 'inferred' error
protocol ViewModelType: class {
associatedtype VC
var viewController: VC! { get set }
}
class ExampleViewModel: ViewModelType {
typealias VC = ExampleViewControllerType
weak var viewController: ExampleViewControllerType!
}
protocol ViewType: class { }
protocol ExampleViewControllerType: ViewType { }
class ExampleViewController: UIViewController, ExampleViewControllerType {
}
No!! it can't be conforming class (If it conforms to protocol Y instead but protocol Y inherits from protocol X, it should be accepted as a conforming class too). A protocol can inherit one or more other protocols and can add further requirements on top of the requirements it inherits. The syntax for protocol inheritance is similar to the syntax for class inheritance. you cannot extend a protocol to conform to another protocol. only a class satisfy all of the requirements enforced by protocol. you could extend the protocol to provide default implementations.
extension Y {
// default implementations
}
for more Protocol Inheritance

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.

Error conforming to a self made protocol in Swift

I've created a protocol in one of my ViewControllers above the class declaration like so:
#class_protocol protocol CRAAddCredentialDelegate {
func didAddCredential()
}
class CRAAddCredentialTableViewController: UITableViewController {
....
}
However, when I try to conform to this protocol:
class CRAMainViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, CRAAddCredentialDelegate {
....
}
I get an error:
What am I doing wrong?
Have you added the function didAddCredential() to your CRAMainViewController class?
By adding the , CRAAddCredentialDelegate to the list of protocols, you're indicating that your class will provide all of the variables and functions that protocol includes.
So you need to actually provide them.
class CRAAddCredentialTableViewController: UITableViewController {
func didAddCredential() {
// add code here
}
....
}
You should implement the required protocol. In your case func didAddCredential() declared in the protocol CRAAddCredentialDelegate is not implemented , so its giving error.

Resources