What is the difference between following delegate method call? - ios

I am confused about these delegate method calls.
Which one is the correct way of calling the delegate method?
#protocol XYZDelegate <NSObject>
#required
- (void)someMethod:(id)someObject;
#end
method 1:
- (void)someButtonAction:(UIButton *)sender {
if([self.delegate && [self.delegate respondsToSelector:#selector(someMethod:)]]) {
[self.delegate someMethod:sender];
}
}
method 2:
- (void)someButtonAction:(UIButton *)sender {
if([self.delegate && [self.delegate respondsToSelector:#selector(someMethod:)]]) {
[self.delegate performSelector:#selector(someMethod:) withObject:sender];
}
}

They are both pretty much the same. They will result in the same outcome.
The second is slightly less efficient.
What I would change is the line...
if([self.delegate && [self.delegate respondsToSelector:#selector(someMethod:)]]) {...
The method someMethod: is required by the protocol.
So you can remove it completely...
- (void)someButtonAction:(UIButton *)sender {
[self.delegate someMethod:sender];
}
And it will still work. You can send a message to nil and it just won't do anything. If the delegate is not nil then by definition it will respond to the selector.
If the delegate object does not conform to the method then you will get a compiler error (or maybe just a warning?).
Anyway, that should suffice.
Just as a side note. I personally prefer the first method and if there is more than one parameter then you would have to call it that way to be able to pass the parameters in corrcetly.

The difference is one calls the delegate method directly, while the other uses the runtime, through performSelector, to do so dynamically.
The latter is less efficient and pointless, but the results are the same.

Related

How to check a block if is realize?

In my code, if I use the block directly:
- (IBAction)checkPendingAction:(UIButton *)sender {
self.block(sender.titleLabel.text); // if the block is no realize, there will report EXC_BAD_ACCESS(code=x, address=0x11xx)
}
If I use delegate, I can use the below code to check my delegate and delegate method if is realize:
if ([self.delegate respondsToSelector:#selector(myDelegateMethod:)]) {
[self.delegate tabBarClickWriteButton:self];
}
So, can I check the block if is realize in iOS?
make your block a property with 'strong' reference. and use weak reference of self in it if needed.
before calling block just check
if(block) {
block(data);
}
You need check block as below
if (self.yourblock != nil) {
self.yourblock(self.titleLabel.text);
}

respondsToSelector for super class invocation

I have the following method:
- (void) someMethod
{
if ([super respondsToSelector:#selector(someMethod)])
{
[super performSelector:#selector(someMethod)
withObject:nil];
}
}
someMethod does not exist on superclass. as i understand, if there is no such method, runtime will ask the next responder in chain for such method till the NSObject class. And i was sure, that if statement will return NO.
Statement return YES. After that it performs selector without crash. As result - infinite recursion.
so, i have two questions:
Why [super respondsToSelector:#selector(someMethod)] returns YES ?
Why [super performSelector:#selector(someMethod) withObject:nil] does not crash with error 'does not responds to selector' ?
I think i've missed something essential.
Please, help.
Yes, you missed something essential as you suggest. From the documentation for respondsToSelector:
You cannot test whether an object inherits a method from its superclass by sending respondsToSelector: to the object using the super keyword. This method will still be testing the object as a whole, not just the superclass’s implementation. Therefore, sending respondsToSelector: to super is equivalent to sending it to self. Instead, you must invoke the NSObject class method instancesRespondToSelector: directly on the object’s superclass, as illustrated in the following code fragment.
if( [MySuperclass instancesRespondToSelector:#selector(aMethod)] )
{
// invoke the inherited method
[super aMethod];
}
HTH

Make two Protocol methods exclusive (implement one or the other, not both)

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.

Using cleaning delegate pattern

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.

Swizzling and super

I am trying to swizzle the canPerformAction:withSender: method for UIResponder and all its subclasses which have overridden this method.
I am doing this by storing the original implementations in a dictionary keyed by class name; and looking up the dictionary in the swizzled version of the implementation before calling out to the original implementation.
This seems to work fine for some cases, but fails when the original implementation calls out to super. Then my swizzled method continuously keeps getting invoked and the program gets into infinite recursion.
What could be wrong here?
After the swizzle the -original with -custom:
-(void)custom {
[self custom]; // calls -original
}
-(void)original {
[self original]; // calls -custom
}
Said that, if you have the methods swizzled in the superclass, objc_msgSendSuper will do the same: call original for custom and versa giving you the recursion.
-(void)custom {
[self original]; // calls -custom, makes recursion
}
-(void)original {
[self custom]; // calls -original, makes recursion
}

Resources