In iOS, what prevents me from having a list of delegates for an object? I know that you are not supposed to do it, but I don't understand if it's just because it doesn't conform to the Delegate pattern or if there is some real technical issues by doing it. I'll explain what I refer to with an example:
Protocol:
#protocol MyDelegate <NSObject>
- (void) someMethod;
#end
Class Header:
#interface SomeClass : NSObject
// Correct use of delegate pattern
#property (nonatomic, weak) id<MyDelegate> delegate;
// Incorrect use of delegate pattern
#property (nonatomic, strong) NSArray<id<MyDelegate>> delegates;
#end
Class implementation:
#implementation SomeClass
// Correct use of delegate pattern
- (void) someMethodThatCallsDelegate {
...
[_delegate someMethod];
}
// Incorrect use of delegate pattern
- (void) someMethodThatCallsDelegate {
...
for(id<MyDelegate> delegate in _delegates) {
[delegate someMethod];
}
}
#end
In my own projects, I often find myself in a situation where several Objects want to know of some event. Typically in network classes. In these cases, I just use NSNotificationCenter instead, but the thought of just having a list of delegates for the object always appeals me (Since I'm also an Android programmer, where a Set of Listeners is completely normal). So, what are the reasons for not having a List of Delegates?
(I also understand that in many cases it's bad design to have more than one delegate for an object, but I'm talking about the cases where it's not, such as in netcode)
There is nothing to stop you doing this. In fact, this is probably what I use protocols for more than for delegates etc...
However, I'd think about what you call the objects and the protocol.
A delegate is some object that your main object "delegates" work to. A table view (for instance) knows it has to have a number of rows, sections, etc... but instead of calculating those itself it says "my delegate is going to do this work for me". It then allows the same tableview to interact with any delegate.
Your objects are obviously not like that as there are many of them. They may all have some common usage though. What is that usage? Is delegate the right word to use?
If they are all "Listeners" then it would make more sense to call the protocol Listener with a function someListenedToActionWasTriggered and to call the array listeners.
How you guys slim down your view controllers?, sometimes you end up implementing a lot of protocols in your view controller, so there’s a lot of code inside the controller itself. Reading about how to slim down view controllers in iOS I found that a common way is to move DataSources (http://www.objc.io/issue-1/lighter-view-controllers.html) to other class, but what about other delegates?, or if you create views by code?. First, I think about move each delegate to a NSObject class, so I try this:
self.locationManager.delegate = [[FRRYPetDescriptionViewControllerLocationDelegate alloc] init];
Then I ask in IRC and somebody suggest categories, so this is what I got so far:
// FRRYPetDescriptionViewController.h
#interface FRRYPetDescriptionViewController : UIViewController
#property (nonatomic) CLLocationManager *locationManager;
#property (nonatomic) TPKeyboardAvoidingScrollView *scrollView;
#property (nonatomic) UIView *contentView;
#end
// FRRYPetDescriptionViewController+Protocols.h
#interface FRRYPetDescriptionViewController (Protocols) <UITextViewDelegate, UIActionSheetDelegate, MFMailComposeViewControllerDelegate, UIGestureRecognizerDelegate, MKMapViewDelegate, UIViewControllerTransitioningDelegate, CLLocationManagerDelegate>
#end
// FRRYPetDescriptionViewController+UIAdditions.h
#interface FRRYPetDescriptionViewController (UIAdditions)
- (void)createScrollView;
- (void)createContentView;
#end
// FRRYPetDescriptionViewController+Callbacks.h
#interface FRRYPetDescriptionViewController (Callbacks)
#end
// FRRYPetDescriptionViewController+LocationAdditions.h
#interface FRRYPetDescriptionViewController (LocationAdditions)
#end
This makes me think, what about “private” methods?, do I need to declare all properties in the view controller header file?. What you guys think about this approach or there’s some common pattern to follow to not end with a fat controller?.
Thank you.
The link that you have referred to has beautiful explanation for less bulky controller's programming. But techniques are bit tricky unless you are a seasoned developer. You have asked about multiple techniques in your question. Please check my views on them below: -
Delegates - I personally prefer to keep the delegate code in my controller itself to avoid unwanted confusion specially when you are working with multiple scenarios within the same controller.
Create Views Programmatically - This is the portion where we can cut the large amount of code from UIViewController. Unless it is a single control such as a single label or button, we should make a custom UIView class and let it set all the common properties for view customisation. Controller should only invoke it with necessary parameters.
Properties in Header File - No, concept of data encapsulation says that we should only make those variables public which are required. Rest should move to private domain so that we external objects can't interfere with the class object functionality. So you should declare these properties in class extension (inside .m file). Moreover it is not required to have all variables as properties, when they are private you can declare them as instance variables as property declaration does nothing but to create the getter/setter for that variable.
Private Methods - Same goes to methods as well. If it doesn't have to be exposed to other objects; it should not be in header file. Keep it in extention as private method.
I know there are a lot of similar questions here but I still need some clarification about this concept.
First of all let me start by saying that I do understand what protocols are and how to use them, what I'm having problem understanding is delegation. I do understand that delegation is when one object in a program acts on behalf of another object, sound very simple but hard to see the whole picture.
1- Is delegation just a way to let the compiler know where to look for the code that will be manipulating the object (UITableView etc.)?
2- Do delegation and protocols work together?
3- Can delegation exist without protocols? If yes, can you show me an example.
4- When we declare a protocol and a class conforms to it, can we say that this class conforming to the protocol is delegating on behave of the protocol?
How much of the above is true?
Thanks a lot
1- Is delegation just a way to let the compiler know where to look for the code that will be manipulating the object (UITableView etc.)?
No, delegation is a design pattern. It's just a concept.
2- Do delegation and protocols work together?
Yes they work well together and it's probably the best practice to use protocol for your delegate.
3- Can delegation exist without protocols? If yes, can you show me an example.
Yes you can. Delegation concept is just to remove intellect of an object and put it in the delegate. For exemple an UITableView does not know how many row it has, or what to do when a cell is clicked, so it asks to its delegate.
But the delegate is still another object.
It's better if it implements a particular protocol, but you can do it without.
For exemple :
I've a MyView that is a subview of a MyCustomViewController.
MyCustomViewController.h
- (void)myViewIsTouched;
MyView.h
#property (nonatomic, weak) MyCustomViewController *delegate
MyView.m
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[self.delegate myViewIsTouched];
}
There is no protocol in this exemple, but it's still a delegate.
(A better way is still using a protocol instead of declaring the method in the .h)
4- When we declare a protocol and a class conforms to it, can we say that this class conforming to the protocol is delegating on behave of the protocol?
I'm not sure about what're saying. But protocols and delegate are not the same thing. An object implementing a protocol does not mean that it's a delegate.
Delegation allows objects to be able to change their appearance / state based on changes in other parts of your application. Setting a
delegate property on an object will allow the compiler to do some
checks at build-time.
Delegation is often achieved by using protocols, since it allows the
delegate object to be of any class instead of a sub-class of a class
with specific behaviour.
Yes, but this would result in your classes becoming tightly coupled since Foo needs to know about Bar and vice-versa. Using protocols allows you to use any class, hence id property, resulting in a loosely coupled system.
Example:
#class Foo;
#interface Bar : NSObject
- (void)respondToSomeAction:(Foo *)obj;
#end
#implementation Bar
- (void)respondToSomeAction:(Foo *)obj {
NSLog("responding to %#",obj);
}
#end
#interface Foo : NSObject
#property (nonatomic, weak) Bar *delegate
#end
#implementation Foo
- (void)someActionTriggered {
[self.delegate respondToSomeAction:self]
}
#end
When a class conforms to a protocol, the class is compelled to adopt the behaviours of the protocol (implement the methods). It only becomes a delegate if it is given some task to do on behalf of another class, e.g. supply the number of rows in a table.
Suppose I have several objects (models) that belong to a UIViewController. When one of the models changes or does something, I want it to notify the UIViewController so that the view can update immediately, or perform some animation in response.
How do I do this? Specifically,
(1.) How do the individual objects know about the ViewController? If I store a pointer to the ViewController inside each object, then I introduce a cyclical reference where a ViewController refers to children that refer to ViewController.
(2.) Even with a weak pointer, the model objects themselves don't know which view inside the ViewController corresponds to itself. For example, say there are 10 views and 10 models. The models aren't coupled with the views (i.e. each model has a view that represents it in the array of 10, but the index isn't always the same, since the user is constantly switching them around, so while the models have a stable index 0...9, the view representing model 0 could be at index 1, or later at index 2, 3, ..., 9), so when a model updates, it needs to tell the ViewController somehow which of the 10 views represents it, except it doesn't know. So the ViewController in turn can't know which View to update.
I should add that my current code just gives each model object a pointer to its corresponding View, so that it doesn't need to go through the ViewController to access the correct View and update its contents. But this would seem to violate MVC, so I'm trying to correct my code and realized I don't know how in this particular situation.
Sorry if that is confusing. I'll update the question if anything is unclear.
EDIT: Updated with more concrete example code.
#interface ViewController : UIViewController<ProfileViewControllerDelegate>
{
BattleModel* battle;
}
#property (nonatomic, strong) BattleModel* battle;
#property (nonatomic, weak) NSArray* heroPersons; // Person objects
#property (nonatomic, weak) NSArray* villainPersons; // Person objects
#property (nonatomic, strong) IBOutletCollection(PersonImageView) NSArray* villainImages;
#property (nonatomic, strong) IBOutletCollection(HealthBarView) NSArray* villainHealthBars;
#property (nonatomic, strong) IBOutletCollection(PersonImageView) NSArray* heroImages;
#property (nonatomic, strong) IBOutletCollection(HealthBarView) NSArray* heroHealthBars;
#property (weak, nonatomic) IBOutlet UITextView* reporter;
That describes the ViewController Interface. Now, each Person class handles modification of the Person, in addition to how the Person reacts to attacks.
#interface Person : NSObject
{
__weak Profile* profile;
__weak PersonImageView* personImg;
__weak BattleModel* currentBattle;
Reaction* currentReaction;
}
// Reaction happens in the following methods:
-(BOOL) targetedFoeWithMove:(SelectedMove*)selMove log:(UITextView*)reporter;
-(BOOL) wasTargetedByMove:(SelectedMove*)selMove log:(UITextView*)reporter;
-(void) hitFoeWithMove:(SelectedMove*)selMove log:(UITextView*)reporter;
-(void) wasHitByMove:(SelectedMove*)selMove log:(UITextView*)reporter;
As you can see, I currently violate MVC because the reporter is passed into the model Person, and also a pointer to the personImg, which the VC should handle. Anyways, as the battle happens, the Reaction* is queried inside the various targeted, hit routines, and that's where modifications happen, and the reporter is notified. Notice how the Person has NO IDEA whatsoever which index its corresponding PersonView is occupying in the grand scheme UIViewController, so when currentReaction triggers in some deep routine, and passes up the data, the ViewController has no idea which UIView to update. It knew at one point (when the Person was created), but the heroImages and villainImages array gets shifted around a lot (even switching sides if one Person goes from hero to villain), so the index it had at birth isn't the index it necessarily has at the point when a Reaction triggers and needs to update the PersonImageView. That's a bit of an annoyance, so I might need to have data passed back up to the UIViewController, telling it which PersonImageView just underwent a Reaction (how would I do that?).
Here is a sample Reaction, just for completeness and helping you understand the system:
-(void) wasHitByMove:(SelectedMove*)selMove log:(UITextView*)reporter
{
[self.currentReaction personWasHitByMove:selMove inBattle:self.currentBattle log:reporter];
}
And depending on if the Reaction is relevant (there are several subclasses of Reaction that do different things), a modification like "loseLife:(int)life" is called through a Person property setter, and that's when I need the report/animation to be bubbled up to the VC. Right now, the erroneous code (bad design) is simply going directly to the personImg for the animation, then the reporter for the textual notification. I realize this is bad design, which is why I'm here, but it isn't as simple as telling the VC through a callback, "(BOOL) Hey, something happened to me." because which PersonImageView is "me"? How does the ViewController, in the middle of its own method executing the logic of the battle, know to respond immediately to the callback? How is the callback even made? (Re: Delegates. So attach the delegate protocol to Person, PersonImageView, and UIViewController? And since they all follow the protocol, then they can interpret the common message through the protocol method?)
I also looked in NSNotification but find that too complicated for this purpose; it seems like it's more of a passive Observer type of thing, where in my application, when a Reaction triggers, I need the UIViewController to immediately update the screen with UITextView text + PersonImageView animations. Immediately in the sense that before the Reaction can trigger again, the animation needs to happen, as it could involve the PersonImageView recoiling, or falling down, or changing appearance. It isn't a real-time game, but the next attack will have already been queued and will be coming momentarily after the one before has triggered the currentReaction, so any kind of delay or passive observation might be bad.
Delegates.
Suppose you have a view with a button. Give it a protocol:
#protocol MyButtonViewDelegate
#required
- (void)buttonPressed;
#end
Now your view with a button has a property like this:
#property (nonatomic, weak) NSObject<MyButtonViewDelegate> *delegate;
Which is its reference to the view controller.
The view with a button's class will have a method like this which is hooked up to the button:
- (IBAction)buttonPressed:(id)sender {
[self.delegate buttonPressed];
}
Your view control conforms to the MyButtonViewDelegate protocol and sets itself as the delegate to the view. It then implements the method buttonPressed:
- (void)buttonPressed {
// do whatever you want to do when that button was pressed
}
If you need to pass a reference to the view in this method, you can do that too:
#protocol MyViewDelegate
#required
- (void)someMethod:(id)sender;
#end
Then:
- (IBAction)someUserInteractionWithView {
[self.delegate someMethod:self];
}
The delegate then implements the method from the protocol:
- (void)someMethod:(id)sender {
// sender is a reference to the view which called this method on delegate
}
You can write a protocol method to send as many arguments as you want. You can even have these methods return values that you make use of:
#protocol MyResizableViewProtocol
#required
- (CGRect)newSizeForResizableView:(MyResizableView*)resizableView;
#end
Something within the view class triggers this method to be called on the delegate and request a new size. The delegate implements this method:
- (CGRect)newSizeForResizableView:(MyResizableView*)resizableView {
return CGRectMake(0.0f, 0.0f, 100.0f, 400.0f);
}
And the resizable view makes use of the method as such:
- (void)timeToResize {
self.frame = [self.delegate newSizeForResizableView:self];
}
As far as I'm concerned, understanding protocols and delegates is one of the more important aspects of iOS development.
Bocks are a great way to implement callbacks in objective-c. Here is a link to Apple's documentation. Apple already implements blocks all over their APIs with NSOperationQueue, NSOperation, view animation, and many others. Check out this article about communication patterns in iOS, it explains the right circumstances for using delegation, blocks, notifications, and others.
There are several ways to do this. One way is by notifications. Have your models send out notifications when these interesting events happen. Your view controller can then sign up to receive these notifications and act accordingly.
In each model, do something like this:
[[NSNotificationCenter defaultCenter] postNotificationName:#"somethingInModel3" object:self];
In the view controller, do something like this in init or viewDidLoad:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(handleModel3Event:)
name:#"somethingInModel3"
object:nil];
The selector specifies the method that will handle the notification. You need to write that method as appropriate.
You'll also need to put (e.g., in dealloc in the view controller):
[[NSNotificationCenter defaultCenter] removeObserver:self];
I am working on a delegate pattern for authorization in my app.
Most things i've seen before use something like:
#property (weak) id<Delegate> delegate;
Does that make it weaker than say
#property (weak) UIViewController<Delegate> *delegate;
I realize i am asking for any pointer in the first one and in the second I am expecting a typed pointer. But i only want my delegate to be a UIViewController or subclass.
Can anyone explain the differences and pros and cons?
But I only want my delegate to be a UIViewController or subclass.
Then go for the second way - the first one indicates that it can be any object that conforms to the <Delegate> protocol.
There are not real pros or cons. The contract is just different. One says "I don't care what class it is as long as it conforms to that protocol" and the other says "I want a subclass of UIViewController which also conforms to the protocol".
The only thing here is that the idea of the "delegate" pattern in Cocoa is generally to give the client of your API a way to create an object that will customize the behavior of one or several other components.
Since you want this property to be a view controller, the semantic is more than just a delegate so I would not call it a delegate but a xxxViewController with "xxx" being the actual functional relationship between your object and that view controller.