I just wanted to clear up some confusion that I have with the delegate pattern that should be constructed when there are multiple UIViews and Subviews of these views. To make it clear, let's define some variables.
Let us define these objects as:
ViewController A
UIView B
Subview C
Now, I understand how the delegation pattern works (I think), although I am unsure how to implement this pattern in nested UIViews. Some questions I have are:
Should C contain a delegate implemented by it's super view (B)?
And if yes, should B then pass this information to it's delegate ViewController (A)?
Here's a scenario, let's say C has a UITextView, this text view's height is determined by a string fetched from an API service. B does not have access to the API since this job should be done via the ViewController (A).
Should C then contain a delegate which points to:
The ViewController's (A) delegate implementation?
The UIView's (B) delegate implementation?
Other?
If the answer is ( 2 ) then should B then call the ViewController (A) and pass this information via a chain of events?
Here's a small visual:
A <IBDelegate> <--- B <ICDelegate> <--- C calls Delegate.OnApiComplete(float height);
What is the "Delegate" in this case? (ICDelegate or IBDelegate). And what are the chain of events?
I am just trying to avoid any unnecessary logic to seep into the UIView's when the responsibility should be on the controller.
I understand that you can solve most of these scenario's with a shared object between UIViews, but when it comes to network services, these values need to be retrieved via some sort of callback.
I further clarification is needed, let me know. Any help is greatly appreciated.
So, you have situation like:
ViewController A --> View B --> View C
I would try to ensure that my ViewController A takes decisions both for View B & View C like this:
Create a protocol ViewDelegate and keep both View B and View C
delegate methods in it.
Create a property #property (nonatomic, weak) id <ViewDelegate> delegate; in View B.
Create a property #property (nonatomic, weak) id <ViewDelegate>
delegate; in View C.
From ViewController A while instantiating View B set self as delegate. Like viewBObj.delegate = self.
From View B while instantiating View C set self.delegate as delegate. Like viewBObj.delegate = self.delegate.
This would make ViewController A responding to both View B and View C delegate events.
Delegate are function pointers. Using it, one can call another class' function easily.
To create delegate, common procedure is to, first create protocol and add relevant methods in it (in the class you want to initiate delegate method). This methods can be implemented by class that adopts protocol.
You also need to create generic property of protocol type called delegate property. This will be assigned to instance of class that conforms to protocol.
In your case, class B and class C has some protocols defined in it. Here, B conforms class C's protocol and class A conforms class B's protocol.
Now, class B has object defined of class c in it. In class B, here we need to assign class C's delegate to instance of B(self). (now in class c, delegate property contains instance of B and one can easily call protocol method implemented in class B from class C).
The same scenario happen in class A and B where one can call method (defined in class B's protocol) of class A from class B.
Below is overview of implementation of delegate chain through A -> B -> C.
Class A
Conforms protocol B
It has object of class B
Assign instance of class A(self) to delegate property of class B
In class A, implement protocol methods defined in class B
Class B
Define protocol with methods
Define property of generic type that act as delegate instance
Conforms protocol C
It has object of class C
Assign instance of class B(self) to delegate property of class C
In class B, implement protocol methods defined in class C
Class C
Define protocol with methods
Define property of generic type that act as delegate instance
I hope this will help you understand how delegate works in iOS.
Now in you case, you can conforms protocol of class B and class C into class A (if you don't want any modification into Class B and simply call upper layer's delegate methods).
See below overview
Class A
Conforms protocol B
It has object of class B
Assign instance of class A(self) to delegate property of class B
In class A, implement protocol methods defined in class B
Conforms protocol C
It has object of class C through object of class B
Assign instance of class A(self) to delegate property of class C
In class A, implement protocol methods defined in class C
Class B
Define protocol with methods
Define property of generic type that act as delegate instance
Class C
Define protocol with methods
Define property of generic type that act as delegate instance
Related
I understand how to use delegation with iOS objects that already exist. For example, if I create an instance of a UITableView, and my view controller conforms to the UITableView delegate, I can implement the various methods of the UITableView delegate. My newly create table can receive notifications, for example, when didSelectRowAtIndexPath is called.
My question is why did my table get this particular delegate callback? My understanding is that the delegate is just a list of methods with no implementation. It seems to me there must be a lot more going on. What is really going on "behind the scenes"?
Image if I were to rename all the delegate methods to the following:
- mysteryMethod1
- mysteryMethod2
- mysteryMethod3... Etc
One of these methods is responsible for setting the height of a row at a particular index. Another one these methods will be responsible for editing a particular row.
Everything I read about delegation says the delegator makes a contract with the delegate. The delegate promises to implement the methods. When it does, somehow everything is wired up correctly and everything magically works. What is the magic that I'm not seeing?
I think that in order to know how delegates actually work you should create your own custom delegate first, that way you will see that there is no magic under the hood, you probably can't see the implementation of the actual apple build in delegate methods but I assure you that there is a lot of logic implemented in those but it's just not available for privacy reasons I assume.
When you create your custom delegate let's say for example...
You have Class A and in this class, you start by creating a protocol
protocol ClassADelegate: class {
func changeBackgroundColor(_ color: UIColor?)
}
In this class you have a delegate property like this.
weak var delegate: ClassADelegate?
Let's say that this class is a Viewcontroller and you have an IBACtion on it like a UIbutton, and your goal is that when you tap that button another ViewController in your app change its background color to blue. Inside this action in Class A you do this...
func someAction() {
delegate?.changeBackgroundColor(.blue)
}
,
Let's say that the "magic" happens here in class A, by the way if you are thinking in delegates using UITableview think that UItableView is class A.
ok so now you have Class B that is where you want to change the color right?
Well now class B needs to conform to the protocol like this, just like you also conform to the protocol UITableViewDelegate etc.
class ClassB: UIViewController, ClassADelegate {
}
Now think of the word delegate for a second and think what that means, you are just delegating responsibility to somebody else, right? and yes, in this case, ClassB is going to be the delegated, for that we need to have an instance of Class A in class B just to have access to it's delegate property.
let classa = ClassA()
classa.delegate = self
the final step is just to call the method of the protocol like this..
func changeBackgroundColor(_ color: UIColor?) {
view.backgroundColor = color
}
To conclude if yo see this method in your class but you don't have access to the implementation of the protocol, you will ask yourself "where does this magic color coming from??" but as you saw it just comes from another class where a protocol belongs to, hope this helps.
I m using Xamarin for iOS and I have a custom View which inherit from UIView.
I would like to add a custom delegate to that view.
So far I found that:
Delegate (not useful) example
I want my delegate to be on his own and won't inherit from any other known delegate.
There is no delegate property on UIView (see Apple docs). It does exists in some subclasses, like UITextView (and other types).
What you can do (beside using the base classes provided) is:
(with the unified API) create your own classes that implements the IUITextViewDelegate interface and assign it to the Delegate property;
Create any class that conforms to the delegate (i.e. minimally all required members), add the required [Export], and assign it to the WeakDelegate property.
Is it possible to use a delegate of superclass on subclass
Example: Class A is superclass of class B and superclass A uses the text view method example textviewDidChange. can I somehow call [super textViewDidChange] of superclass A on Subclass B even it isn't on header file of class A
if i rediclare the method on subclass B
When you specify UITextViewDelegate, you're telling the compiler that your class meets the specifications for a UITextViewDelegate. If class A has all the requirements for a UITextViewDelegate, and class B is a subclass, then it too will have all the requirements. Nothing will stop you from assigning any instance as a delegate, so you still have to be careful with that.
Yes,you can. Since class A confirms <UITextViewDelegate> protocol there is no need to redeclare them in header file. Just make sure it implements needed methods.
I am a beginner in objective-C. So please forgive if my question is silly.
In my root view controller A, I added a subview B.
In b there will be another subview C. C contains another subview D.
How can I call a method in A from D.
I know that we can use delegates for passing data to the parent controller.
But my question is that do i need to create delegate which calls C from D and another one for call B from C and so on?
Or is there any method which directly calls a method in A from D?
But my question is that do i need to create delegate which calls C from D and another one for call B from C and so on?
The view controller's job is to manage it's view and all of that view's subviews. If you've got a view that needs to send the view controller a message, like a control that needs to send a message somewhere when the user changes its value, then the view controller should be aware that it's there. In such a case, the view controller can take care of setting itself (or some other appropriate object) as said subview's delegate or target when the view hierarchy is loaded, like this:
- (void)viewDidLoad
{
self.needControl.delegate = self;
}
That way, the needy control doesn't need to know anything about the object that is its delegate. It's not assuming that the object is the view controller, or its parent view, or anything else. All it cares about is that it has a delegate, and that its delegate implements the necessary methods. And that, in turn, helps you keep your code more flexible and maintainable and maybe even reusable.
Do i need to create delegate which calls C from D and another one for call B from C and so on? No
You can use a single delegate to call a method in A from D. From your comments i came to know B,C,D are UIView's controlled your root view controller. So the job is easy you need to set a delegate as its root view controller upon creating each sub views.
1. View B is creating from the root view controller itself so viewB.delegate = self
2. View C is creating from the view B so viewC.delegate = self.delegate
3. Repeat same for view D also
Now all your views are controlled by your delegate rootViewController.
Finally This answer will help you to complete your task
You should structure your code so that class D does not know class A exists at all.
There are a few specific techniques that are common in iOS/Mac programming:
class D has a delegate property, and calls methods on it. Use this when only one object can receive the delegate method, particularly useful for things like a button asking if it should be enabled or disabled right now. Use interface builder to set the delegate of the view to your instance of class A.
class D should have a "target" property (type id) and an "action" property (type SEL), and it sends the action message/selector to the target object. useful for when a view has a specific single action that it triggers, such as when a button is pressed, or the user presses Enter in an text field. Use interface builder to set the target and action of the view to your instance of class A.
class D sends messages and metadata to [NSNotificationCenter defaultCenter], and class A tells the notification center that it wants to observe those notifications. Useful when potentially many objects need to be notified when something happened, such as when a text field receives or looses keyboard focus.
class D has a property or properties sends Key Value Observing notifications whenever it the value of the property changes. Class A would tell the Key Value Observing system that it wants to know whenever a specific property on class D changes. This is useful when you care specifically about some data, such as when the value of a text field changes.
All of these techniques are described in more detail here on stack overflow or in Apple's official documentation.
Class B and C also should not know that class A exists. Class A should be the one that knows how to find the other objects, unless you can use interface builder (the first two options allow that).
Add your A_viewCon.h file into your D_viewCon.h file
create object of A_viewCon and set #property and #synthesize as properly.
call method of A_viewCon in D_viewConwrite following code.
[self.objectOFA_viewCon performSelector:#selector(MethodNameOFA_viewCon) withObject:nil afterDelay:0];
U can register Class A to observe a NSNotification like ->
- (void)addObserver:(id)observer selector:(SEL)aSelector name:(NSString *)aName object:(id)anObject;
and post NSNotifications from Object of class D like ->
- (void)postNotificationName:(NSString *)aName object:(id)anObject userInfo:(NSDictionary *)aUserInfo;
This way u do not need to keep a reference/delegate and still u can communicate between alive objects.
From Apples iADSuite tabbed example there is a variable defined with delegate.
UIViewController<BannerViewContainer> *_currentController;
later it's cast as such
_currentController = (UIViewController<BannerViewContainer> *)_tabBarController.selectedViewController;
Whats the significance of using "BannerViewContainer" in the declaration, how it relates to the later cast and what's happening under the covers here?
Regards
Jim
There's nothing to do with delegates here. BannerViewContainer is a protocol. (You might be confused because delegation is often defined via protocols.)
Declaring a variable or parameter with an angle-bracketed protocol name means that anything assigned to it must be an object which conforms to that protocol: if you try to pass an instance of UIViewController or some subclass thereof, you'll get a compiler warning unless that instance is of a UIViewController subclass which declares conformance to the BannerViewContainer protocol. (That is, you can pass an instance of FooViewController if its header file reads #interface FooViewController : UIViewController <BannerViewContainer>.)
The cast you see later follows the same pattern as many casts: it's a case where the programmer knows that the object he's assigning meets the requirements for that variable, but the reference he's using doesn't have a matching declaration. That is, the tab bar controller only knows that its selected view controller is a UIViewController (or any subclass thereof), but the programmer knows that the views he put into the tab bar are all UIViewController subclasses conforming to the BannerViewContainer protocol.