I have a protocol like this :
#import <Foundation/Foundation.h>
#protocol StoreDisplayerDelegate <NSObject>
-(void) changeActionForObjectWithId:(NSString *)objectID ;
#end
and i have a callass with conforms to the precedent protocol StoreDisplayerDelegate
#interface ShelfVC : UIViewController :<StoreDisplayerDelegate>
....
#implementation ShelfVC
...
- (void)viewDidLoad {
...
DownloadManager *manager = [DownloadManager sharedInstance];
[manager setStoreDisplayerDelegate:self];
....
}
#pragma mark StoreDisplayerDelegate methods
-(void) changeActionForObjectWithId:(NSString *)objectID {
......
}
#end
And in my code ( in the same class) sometimes i am calling the delegate methods to do something form me, for example :
- (void)anOtherMethod{
[self changeActionForObjectWithId:nil];
}
My Questions
1. is : When object is a delegate for an other object, is the methods implemented by the delegate called only by the other object ( witch have a reference for it ) ? i mean by this, for example in the code i have shown should the methode changeActionForObjectWithId: just called by the downLoad manager or can i use it in the inernal of my class like this :
is what i am doing cleaning or bad design of using Delegate pattern ?
I hope that it is clear.
Your delegate method name sounds like a command.
-(void)changeActionForObjectWithId:(NSString *)objectID;
It sounds like your StoreDisplayer is telling delegate to do something. The fact that you are also tempted to call that method from within the ViewController confirms it.
That is not the delegate pattern. The delegate pattern is for a class to inform a delegate of a change, or to ask the delegate for some information. The delegating class (StoreDisplayer?) shouldn't know about what any particular delegate does, so it shouldn't be able to give it direct specific commands. Only delegate generic behaviour to it.
Delegate method look more like these examples:
-(BOOL)actionShouldChangeForStoreDisplayer:(StoreDisplayer*)storeDisplayer;
-(void)actionWillChangeForStoreDisplayer:(StoreDisplayer*)storeDisplayer objectId:(NSString *)objectId;
-(void)actionDidChangeForStoreDisplayer:(StoreDisplayer*)storeDisplayer objectId:(NSString *)objectId;
I'm not saying those are what you need, but they should give you the idea.
When your delegate methods look like this, clearly you will not be tempted to call them from anything other than the class that's doing the delegation (StoreDisplayer).
In my project I have the same situation for different purpose. In my opinion the delegate method must be called only by the other object, because it is its method.
If you need to do certain action in the delegate method, its better to create another private method to performing the action and call it from the delegate methods.
Some example. Instead of doing this:
- (void)anOtherMethod {
[self changeActionForObjectWithId:nil];
}
- (void)changeActionForObjectWithId:(NSString *)objectID {
< some actions >
}
I do this:
- (void)privateMethod{
< some actions >
}
- (void)anOtherMethod {
[self privateMethod];
}
- (void)changeActionForObjectWithId:(NSString *)objectID {
[self privateMethod];
}
Why do this? Because you have to think to the delegate methods to an "extension" to your base object: if you delete the "changeActionForObjectWithId" (becuase, for example, you don't need the delegate anymore after a refactoring) the code will continue to work.
A delegate is a protocol that allows an object to perform certain actions.
In your example:
#interface ShelfVC : UIViewController : <StoreDisplayerDelegate>
This tells the compiler that UIViewController is going to implement some methods in the StoreDisplayerDelegate protocol. How the object that applicable to the StoreDisplayerDelegate behave would depend on the protocol in the delegate methods.
You got a little confused with delegates and protocols. a delegate is a design-pattern wich uses a protocol.
a protocol only defines methods and properties expected to be implemented by another (unspecific) class. from where this methods/properties get accessed doesn't matter.
Related
I have a textView "TexV" which have a custom class "TexV_Class" inherited from UITextView and I have a viewController "VC" with custom class named "VC_Class"
Now how can I make both classes "TexV_Class" and "VC_Class" delegate and make them work together? Is it even possible that same delegate method (eg. textViewDidChange) in BOTH classes runs (leaving the sequence of running for now)
I although had made both classes delegate but only one runs (that of VC_Class having textView delegate methods run)
You can't. The delegate mechanism works by having a single callback object, if you want more than one item to react based on the delegate you can go around this in one of two ways:
1- Fire a notification on one of your delegate so that the other delegate can act accordingly
2- set a custom delegate on TexV_Class that conforms to the method of UITextView that the VC_Class wants to adopt, and have TexV_Class call this delegate from it's delegate callback.
I suggest you 3 ways to do this:
1) Use NSNotificationCenter (the pattern help 1 object communicate one-to-many objects)
2) Use multicast delegate pattern. Implementation detail, you can refer this http://blog.scottlogic.com/2012/11/19/a-multicast-delegate-pattern-for-ios-controls.html
3) Use Proxy Design pattern. (This way I choosen)
class MyTextView.h
#protocol NJCustomTextViewDelegate <NSObject>
- textViewShouldBeginEditing:
- textViewDidBeginEditing:
- textViewShouldEndEditing:
- textViewDidEndEditing:
#end
#property (nonatomic, weak) id< NJCustomTextViewDelegate >textViewDelegate;
Use this:
in MyTextView.m
self.delegate = self;
- (void)textViewShouldBeginEditing:(UITextView)textView
{
// Handle business logi
// .... Do your logic here
if ([self.textViewDelegate responseToSelector:#selector(textViewShouldBeginEditing:)])
{
[self.textViewDelegate textViewShouldBeginEditing:self];
}
}
In MyViewController.m
MyTextView textView = ....
textView.textViewDelegate = self;
Let's say I have defined a protocol for a subclassed UIView as follows:
#protocol MyCustomViewDelegate <NSObject>
- (NSString*) titleForItemAtIndex;
- (UIImage*) imageForItemAtIndex;
#end
I would want the class implementing the delegate methods to implement only one, and not both the delegate methods. If the delegate implements titleForItemAtIndex, it must NOT implement imageForItemAtIndex, and vice versa. The compiler must throw a warning (or some other way to communicate to this to the programmer) if both methods are implemented by the delegate class. Is that possible?
You can ask if the the delegate instance responds to a specific selector:
if ([self.delegate respondToSelector:#selector(titleForItemAtIndex)]) {
NSString * title = [title titleForItemAtIndex];
}
else if ([self.delegate respondToSelector:#selector(imageForItemAtIndex)]) {
UIImage * title = [title imageForItemAtIndex];
}
This will also require that you mark your delegate methods as #optional in the protocol declaration. With this condition you guarantee that the first method has the precedence on the second.
You can add one more else and throw an exception if none of them is called.
I dont think its possible to throw compiler errors. But still exceptions can be raised at runtime. You can use NSAssert and make sure that only one method is implemented at run time. This does not throw a compiler error but causes the app to crash with a log saying that only one method should be implemented.
// Checks for titleForItemAtIndex
if ([self.delegate respondToSelector:#selector(titleForItemAtIndex)])
{
// Delegate has implemented titleForItemAtIndex.
// So it should not be implementing imageForItemAtIndex
// Below assert will check this
NSAssert(![self.delegate respondToSelector:#selector(imageForItemAtIndex)], #"Delegate must not respond to imageForItemAtIndex");
// Now that condition is checked. Do anything else as needed below.
}
// Checks for imageForItemAtIndex
if ([self.delegate respondToSelector:#selector(imageForItemAtIndex)]) {
// Delegate has implemented imageForItemAtIndex.
// So it should not be implementing titleForItemAtIndex
// Below assert will check this
NSAssert(![self.delegate respondToSelector:#selector(titleForItemAtIndex)], #"Delegate must not respond to titleForItemAtIndex");
// Now that condition is checked. Do anything else as needed below.
}
Another approach would be to create separate protocols for both methods, and use the same if assert condition but with conformsToProtocol If you have a lot of mutually exclusive methods, its better to create separate protocols.
I'm using #implementation to add a new function to UIView.
#implementation UIView (test)
- (void)newFunction {
}
#end
Now, in the newFunction I want to "grab" the object (UIView) that was used when calling the function.
For example when I call newFunction within viewDidLoad
- (void)viewDidLoad {
[myView newFunction];
}
I want the newFunction to know what object was used to make the call (in this case, myView).
A simple solution would be to pass it along when making the call ([myView newFunction:myView]), but that is not what I am looking for.
I looked at Apple's documentation on the subject, but didn't really find an answer to my question.
#import "UIView+UIView_Category.h"
#implementation UIView (UIView_Category)
- (void)newFunction
{
NSLog(#"Object = %#",self);
}
#end
What you describe is called a category (not #implementation). It is an extension to the UIView class (in this case).
Generalcally:
#implementation __CLASS_TO_EXTEND__ (__CATEGORY_NAME__)
The category, as it is an extension, is the instance that you call the method on. So, you use self as you usually would to access the current instance.
I have three UIViewController that call a method in another Class, when there is need.
This fourth Class subclass of NSObject, which I will call CheckController, it makes a connection to a database on a server, and to do this takes a few seconds.
I have two questions to ask:
-FIRST: now to get the array back to me from the server, use a method that is almost embarrassing for me to share (bad code for me),
so i need to know how to call this CheckController and return a value in the ViewController from which the call originated.
-SECOND: how do I know in CheckController, from which UIViewController, the method was invoked?
this is code of CheckController:
-(void)connectionWithString:(NSString *)string {
//connection with server - work well
}
...
-(void)connectionDidFinishLoading:(NSURLConnection *)connection {
...
[self returnArray:myObject];
}
-(void)returnArray:(NSMutableArray *)arrayReturn {
//in this method i set the BOOL done to YES, but i believe that is it possible to
//send directly this arrayReturn to ViewController that invoked this method
done = YES;
NSLog(#"arrayReturn = %#", arrayReturn);
}
thanks in advance for the help, and tell me if something is not clear
As you already mentioned your Class is a subclass of NSObject which is good. But you should provide a protocol which calls the delegate if your CheckController receives some data. So in your CheckController.h
#protocol CheckControllerDelegate <NSObject>
#required
- (void)receivedArray:(NSArray*)data
#end
#property (nonatomic, weak) id <CheckControllerDelegate> delegate;
In your ViewController:
[self.CheckController setDelegate:self];
CheckController.m:
-(void)connectionDidFinishLoading:(NSURLConnection *)connection {
[_delegate receivedArray:myObject];
}
For best practice your protocol should also have a method which would be called if an error occurs.
What I am trying to implement is a UITextField that sees words as characters. Specifically, im trying to see the mathemathical expression sin( as one character for example. I thought to solve this problem by implementing my own UITextInputDelegate. However, the four required functions from this protocol never get called when I implement or adopt this protocol. I tried implementing it in the following ways:
By subclassing a UITextField.
#interface BIDUItextFieldDelegate : UITextField < UITextInputDelegate >
By subclassing a NSObject.
#interface BIDTextfieldInputDelegate : NSObject < UITextInputDelegate >
The corresponding .m file contains:
#implementation BIDTextfieldInputDelegate
- (void)selectionWillChange:(id <UITextInput>)textInput
{
NSLog(#"sWill");
}
- (void)selectionDidChange:(id <UITextInput>)textInput
{
NSLog(#"sDid");
}
- (void)textWillChange:(id <UITextInput>)textInput
{
NSLog(#"tWill");
}
- (void)textDidChange:(id <UITextInput>)textInput
{
NSLog(#"tDid");
}
For example for the second approach (via subclassing NSObject), I do the following in the (id) init method in an additional custom UITextfield class which is displayed within the app:
//textInputDel is an instance of the custom NSObject class that adopts the above UITextInputDelegate protocol
self.textInputDel = [[BIDTextfieldInputDelegate alloc] init];
self.inputDelegate = self.textFieldDel;
Does anyone know what I am doing wrong, or has a better solution?
UITextInputDelegate is not a protocol that you implement; rather, the system creates an object conforming to UITextInputDelegate, and assigns it as the .inputDelegate of a First Responder that conforms to UITextInput.
The methods of UITextInputDelegate are methods for your UITextInput-conforming responder to call on your .inputDelegate to inform it that you have changed your text or selection via means other than keyboard input.