Get values of variables defined by protocol from any VC - ios

protocol(myProtocol):-
protocol myProtocol {
var type:String { get set }
var sub:String { get }
var msg:String? { get set }
}
Class(myVC):-
class myVC: UIViewController, myProtocol {
//Protocol Declarations
var sub = myTypes.type.rawValue
var type = myTypes.type.getType()
var msg :String?
.... }
Extension:-
extension UIViewController
{
func getData() {
if self is myProtocol {
let msg = self.msg
} }
}
Getting error at 'self.msg' saying Value of type UIViewController has no member 'sub'
How do i go about it?
Any help is appreciated.

All you need to do is write another line of code in your extension class. I just tested it in my end and it worked for me. Here is the code I wrote -
extension UIViewController
{
func getData() {
if self is myProtocol {
let x = self as! myProtocol
let msg = x.msg
print(x.msg)
}
}
}

According to your example, you need to change your extension definition
extension UIViewController
as
extension myVC

Related

Why protocol type never gets a value?

I am trying to understand more protocols. I could not figure out myProtocolFunction never call and print or passing the variable as below.
I think my problem is about initialization. When I try with two viewcontroller everything is okay but MyStruct protocol instance is nil. Thanks for your help.
class ViewController: UIViewController, MyProtocol {
var myProtocolValue: String = ""
var globalInstance = "a"
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func click(_ sender: Any) {
var myStruct = MyStruct()
myStruct.myProtocol = self
}
func myProtocolFunction(passing: String) {
globalInstance = passing
print("never print")
}
}
protocol MyProtocol {
func myProtocolFunction(passing: String)
}
struct MyStruct {
var myProtocol: MyProtocol?
init() {
makeSomething()
}
func makeSomething() {
myProtocol?.myProtocolFunction(passing: "abc")
}
}
1- You need to make
var myStruct = MyStruct() // an instance variable
#IBAction func click(_ sender: Any) {
myStruct.myProtocol = self
}
2- Also you call init before even you set myProtocol as its called when you do var myStruct = MyStruct() and at that time myProtocol is nil as its not yet set
init() {
makeSomething()
}
Check full working edit
class ViewController: UIViewController, MyProtocol {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
func myProtocolFunction(passing: String) {
print(passing)
}
#IBAction func click(_ sender: Any) {
var myStruct = MyStruct(self)
}
}
protocol MyProtocol {
func myProtocolFunction(passing: String)
}
struct MyStruct {
var myProtocol: MyProtocol?
init(_ mine:MyProtocol) {
myProtocol = mine
makeSomething()
}
func makeSomething() {
myProtocol?.myProtocolFunction(passing: "abc")
}
}
Think about protocols as a type, in your struct you are basically saying
that this struct have a variable of this type ( your protocol )
and on init you are trying to call its function.
What you're missing is setting an instance of type ( your protocol )
so it can get called.
for instance :
MyStruct = MyStruct(myProtocol: ViewController())
Now your nullable protocol have a value and can call it's function in another word, protocols can't have implementation directly into them they're more like a signature contract
Read more about protocols here.
You need to create MyStruct() object out of the click action else when the scope is over your object is deinitialize.
Also, You have to call .makeSomething() function on the button click as the time of object creation delegate is nil.
var myStruct = MyStruct() // Create an instance here
#IBAction func click(_ sender: Any) {
myStruct.myProtocol = self
// Add your action
myStruct.makeSomething()
}

Add a generic delegate to a base class in Swift

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()
}
}

Protocol implementation method not calling in Swift

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.

Type checking with generics and raw types?

I have a class
class SomeViewController<T: SomeViewModel>: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource { ... }
And another class:
class AnotherViewController: UIViewController {
private weak var someVC: UIViewController?
...
func someFunc() {
if someVC is SomeViewController { ... } // attempt 1
// or
if let vc = someVC as? SomeViewController { ... } // attempt 1
...
}
...
}
I need to see if someVC is a SomeViewController so that I can access an instance variable that has nothing to do with the generic type. However, when doing a check via either attempt 1 or attempt 2, the check always fails and my inner code never executes. How do I see if it is of a type, but not specific generic type e.g. I don't have to put the type of SomeViewModel?
EDIT: Added more code for clarity.
This doesn't work because Swift wants to know the type of the generic. If you just want to access a property without dealing with the generic, you can extract that to a protocol.
protocol SomethingThatHasFoo {
var foo: String { get }
}
class SomeViewController<T>: UIViewController, SomethingThatHasFoo {
let foo = "foo"
}
class AnotherViewController {
private weak var someVC: UIViewController?
func someFunc() {
if let vc = someVC as? SomethingThatHasFoo {
print(vc.foo)
}
}
}
Here is an example that works:
class SomeViewModel{}
class A: SomeViewModel{}
class SomeViewController<T: SomeViewModel> : UIViewController{}
class AnotherViewController {
private weak var someVC: UIViewController?
init(vc: SomeViewController<A>) {
someVC = vc
}
func someFunc() {
if someVC is SomeViewController<A> {
print("\(String(describing: someVC))")
}
if let vc = someVC as? SomeViewController<A> {
print("\(vc)")
}
}
Then you have to initialize it like this:
let someVC = SomeViewController<A>()
let anotherVC = AnotherViewController.init(vc: someVC)
anotherVC.someFunc()
Hope that answered your question

Using Selector in Swift 3

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 {}

Resources