Let's say that I have a pure Swift protocol (not marked with #objc statement), this protocol serves as a delegate in some other class. This protocol has two methods: old method that I'd like to deprecate and new method that I'd like to introduce as a replacement:
protocol TestProtocol: AnyObject {
#available(*, deprecated, renamed: "newMethod()")
func deprecatedMethod()
func newMethod()
}
class TestClass {
weak var delegate: TestProtocol?
func testDelegates() {
// Warning: 'deprecatedMethod()' is deprecated: renamed to 'newMethod()'.
delegate?.deprecatedMethod()
delegate?.newMethod()
}
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let testClass = TestClass()
testClass.delegate = self
testClass.testDelegates()
}
}
extension ViewController: TestProtocol {
func deprecatedMethod() {
print("Deprecated method.")
}
func newMethod() {
print("New method.")
}
}
Since class still has to call deprecated method of the protocol it causes warning. I'd like to prevent this warning. Are there any ideas on how this can be fixed?
Related
Ideally, I want to create a BaseViewController class that takes in a protocol type (of a delegate) and have a weak variable as the delegate. Something like this:
class BaseViewController<Delegate: AnyObject> {
weak var delegate: Delegate?
init(delegate: Delegate) {
self.delegate = delegate
super.init(...)
}
}
And then inherit from a view controller like so:
protocol MyDelegate: AnyObject {
func funcA()
func funcB()
}
class SomeViewController: BaseViewController<MyDelegate> {
func doSomething() {
delegate?.funcA()
}
}
This doesn't work as the compiler complains:
'BaseViewController' requires that 'MyDelegate' be a class type
How can I work this around to achieve what I need?
Thanks in advance :)
Thats because in swift protocols doesn't confirm to them selves, you can't use "MyProtocol" as concrete type confirming to protocol "MyDelegate"
What you can rather do is
protocol MyDelegate: AnyObject {
func funcA()
func funcB()
}
class BaseViewController<Delegate: MyDelegate> {
weak var delegate: Delegate?
init(delegate: Delegate) {
self.delegate = delegate
super.init(...)
//keeping OPs code as is
}
}
class SomeOtherDelegateClass: MyDelegate {
func funcA() {
//some code here
}
func funcB() {
//some code here
}
}
class SomeViewController: BaseViewController<SomeOtherDelegateClass> {
func doSomething() {
self.delegate?.funcA()
}
}
EDIT 1:
As OP mentioned in comment, he is trying to introduce a generic property in BaseViewController that will simply hold a weak reference to any instance whose class is decided/declared by Child classes of BaseViewController using generics, I am simplifying the above answer a bit
Try this
protocol MyDelegate {
func funcA()
func funcB()
}
class BaseViewController<Delegate> where Delegate: AnyObject {
weak var delegate: Delegate?
init(delegate: Delegate) {
self.delegate = delegate
super.init(...)
//keeping OPs code as is
}
}
class SomeOtherDelegateClass: MyDelegate {
func funcA() {
//some code here
}
func funcB() {
//some code here
}
}
class SomeViewController: BaseViewController<SomeOtherDelegateClass> {
func doSomething() {
self.delegate?.funcA()
}
}
protocol MyDelegate2 {
func funcABCD()
}
class SomeOtherDelegateClass2: MyDelegate2 {
func funcABCD() {
//some code here
}
}
class SomeViewController2: BaseViewController<SomeOtherDelegateClass2> {
func doSomething() {
self.delegate?.funcABCD()
}
}
TBH, I really dont see much of benefit of this design! Probably you need to revisit the code structure and see if you can come up with better code structure :)
You should set your delegate as a constraint for the generic type T in BaseViewController:
protocol MyDelegate: AnyObject {
func funcA()
func funcB()
}
class Delegated1: MyDelegate {
func funcA() { print("A1") }
func funcB() {}
}
class Delegated2: MyDelegate {
func funcA() { print("A2") }
func funcB() {}
}
class BaseViewController<T: MyDelegate>: UIViewController {
var delegate: T?
func doSomething() {
delegate?.funcA()
}
}
class SomeViewController1: BaseViewController<Delegated1> {}
class SomeViewController2: BaseViewController<Delegated2> {}
class TestClass {
let viewController1: SomeViewController1 = {
let viewController = SomeViewController1(nibName: nil, bundle: nil)
viewController.delegate = .init()
return viewController
}()
let viewController2: SomeViewController2 = {
let viewController = SomeViewController2(nibName: nil, bundle: nil)
viewController.delegate = .init()
return viewController
}()
// prints:
// A1
// A2
func myFunc() {
viewController1.doSomething()
viewController2.doSomething()
}
}
I am using Xcode 10.3. I have protocol which method is not calling. What is wrong?
My first view controller with protocol:
protocol MyProtocol: class {
func doGetUpdateInfo(valu1:String,value2:String);
}
class Class_A : UIViewController{
weak var myprotocolDelegate:MyProtocol? = nil;
override func viewDidLoad() {
super.viewDidLoad()
myprotocolDelegate?.doGetUpdateInfo(account_no:value1, account_title: value2)
}
}
My second view controller
class Class_B: UIViewController,UpdateBeneficiaryProtocol {
var class_a = Class_A()
override func viewDidLoad() {
super.viewDidLoad()
class_a.myprotocolDelegate = self;
}
func doGetUpdateInfo(value1: String, value2: String) {
print("not calling****")
}
}
What is the wrong with it?
Please see the below example. you are creating a new class for A but so it will not be called. you need to provide a reference for the current class
protocol MyProtocol: class {
func doGetUpdateInfo(valu1:String,value2:String);
}
class Class_A : UIViewController{
weak var myprotocolDelegate:MyProtocol? = nil;
override func viewDidLoad() {
super.viewDidLoad()
myprotocolDelegate?.doGetUpdateInfo(account_no:value1, account_title: value2)
}
func navigateToClassB() {
let classb = Class_B()
classb.class_a = self
self.navigationController?.pushViewcontroller(classb, animated:true)
}
}
And class b should be
class Class_B: UIViewController,UpdateBeneficiaryProtocol {
var class_a : Class_A?
override func viewDidLoad() {
super.viewDidLoad()
class_a.myprotocolDelegate = self;
}
func doGetUpdateInfo(value1: String, value2: String) {
print("not calling****")
}
}
Push controller Class_b as per display in method navigateToClassB.
If you face still issue comment here I will assist you.
I am writing my iOS Application in Swift 3.
I have a UIViewController extension, where I have to check if the controller instance responds to a method. Below is the code that I a trying out.
extension UIViewController {
func myMethod() {
if self.responds(to: #selector(someMethod)) {
}
}}
Here the responds(to:) method throws a compile time error
Use of unresolved identifier "someMethod".
I read in another post, we have to use self inside the selector argument, but even that is throwing some error.
A simple workaround:
#objc protocol SomeMethodType {
func someMethod()
}
extension UIViewController {
func myMethod() {
if self.responds(to: #selector(SomeMethodType.someMethod)) {
//...
self.perform(#selector(SomeMethodType.someMethod))
// or
(self as AnyObject).someMethod?()
//...
}
}
}
A little more Swifty way:
protocol SomeMethodType {
func someMethod()
}
//For all classes implementing `someMethod()`.
extension MyViewController: SomeMethodType {}
//...
extension UIViewController {
func myMethod() {
if let someMethodSelf = self as? SomeMethodType {
//...
someMethodSelf.someMethod()
//...
}
}
}
Create a protocol which requires someMethod()
protocol Respondable {
func someMethod()
}
And a protocol extension which affects only UIViewController instances
extension Respondable where Self : UIViewController {
func myMethod() {
someMethod()
}
}
Adopt the protocol to some of the view controllers
class VC1 : UIViewController, Respondable {
func someMethod() { print("Hello") }
}
class VC2 : UIViewController {}
class VC3 : UIViewController {}
Now call the method in the extension
let vc1 = VC1()
vc1.myMethod() // "Hello"
Otherwise you get a compiler error:
let vc3 = VC3()
vc3.myMethod() // error: value of type 'VC3' has no member 'myMethod'
Swift 4 answer:
If the selector is written as a string you won't get that error.
extension UIViewController {
func myMethod() {
if self.responds(to: "someMethod")) {
}
}
}
And then in the viewcontroller (dont forget the #objc):
#objc func someMethod() -> Void {}
I'm trying to create a protocol that would be implemented by certain classes, all of them should also implement UIScrollViewDelegate. What I thought of is for my new protocol to implement the protocol UIScrollViewDelegate.
protocol MyProtocol: UIScrollViewDelegate {
var myVar: NSString { get }
func myMethod()
}
As the protocol should have its default implementation I also created an extension for this protocol.
extension MyProtocol {
func myMethod() {
print("I'm printing")
}
func scrollViewDidScroll(scrollView: UIScrollView) {
print("I'm scrollin")
}
}
It compiles, but does not work. What am I doing wrong and what would be the right way to create a default implementation of expanded protocol?
What you want to do is the following:
protocol MyProtocol{
var myVar: NSString { get }
func myMethod()
}
protocol MyProtocol2{
var myVar2: NSString { get }
func myMethod2()
}
extension MyProtocol where Self: MyProtocol2 {
func myMethod() {
print("I'm printing ")
}
}
class anotherClass: MyProtocol, MyProtocol2 {
var myVar: NSString {
return "Yo"
}
var myVar2: NSString {
return "Yo2"
}
func myMethod2() {
print("I'm printing in myMethod2")
}
}
In the above code MyProtocol2 is equivalent to your UIScrollViewDelegate,
hence what you will do is:
protocol MyProtocol{
var myVar: NSString { get }
func myMethod()
}
extension MyProtocol where Self: UIScrollViewDelegate {
func myMethod() {
print("I'm printing")
}
}
class anotherClass: NSObject, MyProtocol, UIScrollViewDelegate {
var myVar: NSString {
return "Yo"
}
}
Notice that another class subclasses NSObject, this is because if you do not do so, you will get the error
anotherClass does not conform to protocol NSObjectProtocol
This error is because UIScrollViewDelegate itself is defined to be extending NSObjectProtocol which is an objective-C protocol implemented by NSObject.
So make your class inherit from NSObject to conform to the NSObjectProtocol. Vanilla Swift classes do not.
I have a class with a delegate. I create a subclass, which also has a delegate. I wanted to let the protocol used for the second delegate extend the protocol used for first delegate:
protocol MySuperClassProtocol {
func foo()
}
class MySuperClass {
var delegate:MySuperClassProtocol?
}
protocol MySubClassProtocol:MySuperClassProtocol {
func bar()
}
class MySubClass: MySuperClass {
override var delegate:MySubClassProtocol? // compiler error - "cannot override..."
func test() {
delegate?.foo()
delegate?.bar()
}
}
class UserClass:MySubClassProtocol {
func foo() {
println("foo!")
}
func bar() {
println("bar")
}
}
Is there a way to solve this? The only possible solution I see is to make the 2 protocols independent of each other, and use different names. Like this:
protocol MySuperClassProtocol {
func foo()
}
class MySuperClass {
var mySuperClassDelegate:MySuperClassProtocol?
}
protocol MySubClassProtocol {
func bar()
}
class MySubClass: MySuperClass {
var mySubClassDelegate:MySubClassProtocol?
func test() {
mySuperClassDelegate?.foo()
mySubClassDelegate?.bar()
}
}
class UserClass:MySuperClassProtocol, MySubClassProtocol {
func foo() {
println("foo!")
}
func bar() {
println("bar")
}
}
But this looks a bit weird + will not let me use naming convention for delegate- "delegate".
Sorry for necroposting, the only one solution i found is:
protocol SuperClassDelegate {
func first_method()
}
class SuperClass {
var delegate: SuperClassDelegate?
func do_something() {
delegate?.first_method()
}
}
protocol SubClassDelegate: SuperClassDelegate {
func second_method()
}
class SubClass: SuperClass {
private var subDelegate: SubClassDelegate?
override var delegate: SuperClassDelegate? {
get { return self.subDelegate }
set { self.subDelegate = newValue as! SubClassDelegate? }
}
//override func do_something() {
// super.do_something()
// subDelegate?.second_method()
//}
func do_something_other() {
//subDelegate?.first_method()
self.do_something()
subDelegate?.second_method()
}
}
class InheritanceAndDelegation: SubClassDelegate {
let obj = SubClass()
init() {
obj.delegate = self
}
internal func first_method() {
print("Hello from SuperClass")
}
internal func second_method() {
print("Hello from SubClass")
}
func check() {
obj.do_something_other()
}
}
let inheritanceAndDelegation = InheritanceAndDelegation()
inheritanceAndDelegation.check()
//prints:
//Hello from SuperClass
//Hello from SubClass
Commented code works too. Hope it will be useful for someone.
I was trying to find an ideal solution to this for some time, but could not come up with anything better that this:
protocol BaseDelegateProtocol: class { }
class BaseDelegate: BaseDelegateProtocol { }
class BaseActor {
weak var delegate: BaseDelegate? = nil
}
// MARK: -
protocol ConcreteDelegateProtocol: class {
func doSomething()
}
class ConcreteDelegate: BaseDelegate, ConcreteDelegateProtocol {
func doSomething() {
// Do something
}
}
class ConcreteActor: BaseActor {
private weak var concreteDelegate: ConcreteDelegateProtocol? = nil
override var delegate: BaseDelegate? {
didSet {
concreteDelegate = delegate as? ConcreteDelegateProtocol
}
}
}
Above works in XCode 7 / Swift 2.
This pattern allows adopting more and more protocols on the way down inheriting from BaseDelegate.
There is no need to inherit protocols one from the other, which helps keeping things isolated.
didSet observer on delegate property is automatically called for superclasses, therefore no need to call super.<blah> explicitly, and no risk to 'forget' doing so
Concrete delegate properties can be kept private on each level of inheritance, thereby reducing the clutter.
You can do it in another way, you can add the delegate variable in Subclass and use it to access the SuperClassProtocol also using delegate?.foo().
protocol MySuperClassProtocol {
func foo()
}
class MySuperClass {
//var delegate:MySuperClassProtocol?
}
protocol MySubClassProtocol:MySuperClassProtocol {
func bar()
}
class MySubClass: MySuperClass {
var delegate:MySubClassProtocol?
func test() {
delegate?.foo()
delegate?.bar()
}
}
class UserClass:MySubClassProtocol {
func foo() {
println("foo!")
}
func bar() {
println("bar")
}
}
But the issue with this approach is you can never use MySuperClassProtocol independently unless you create a new SubClass of MySuperClass only for declaring delegate variable.