I am having a problem I am working on a class which is subclass of UITextField.
Which will be used in many classes further.
But I don't want to let user to use it's delegate methods in any way.
Is there any way to do this ?
Override setDelegate: so that it throws an exception or logs an instruction on what to do. That way your API users will know what's actually going on.
-(void) setDelegate: (id <UITextFieldDelegate>) delegate
{
NSLog(#"*** Use the blocks API instead of calling %s", __PRETTY_FUNCTION__);
[self doesNotRecognizeSelector: _cmd];
}
Override the -setDelegate: method such that it never actually sets a delegate. You can just provide an empty method that fails to call super:
-(void) setDelegate:(id<UITextFieldDelegate>) delegate
{
// this method intentionally empty to prevent a delegate from ever being set
}
Related
I use a protocol with some optional methods.
#protocol PhotoDropDownDelegate <NSObject>
#optional
- (void)getEditResult:(NSString *)status;
- (void)getImageForDiagram:(UIImage *)image andImagePath:(NSString *)imagePath;
- (void)dismissPhotoDropDown;
#end
I assign this for a class
photoDropDownViewController.photoDropDownDelegate = self;
I use only one method
- (void)getImageForDiagram:(UIImage *)image andImagePath:(NSString *)imagePath
{
// Make a Image on center of screen
PhotoLayer *photoLayer = [PhotoLayer nodeWithLengthOfShape:300 andHeight:200 andPathToImage:imagePath];
photoLayer.position = ccp(400, 500);
photoLayer.nameObject = [self makeNewName_ForShape];
photoLayer.isSelected_BottomRightElip = YES;
photoLayer.isSelected = YES;
[photoLayer doWhenSelected_Elip_BottomRight];
[photoLayer show_Elip];
[list_Shapes addObject:photoLayer];
[self addChild:photoLayer];
photoLayer = nil;
// Set Button Delete
selected_GerneralShapeLayer = (GerneralShapeLayer *) [list_Shapes lastObject];
[self updateStatusForButtonDelete];
}
Then the compiler show error:
[AddDiagramLayer dismissPhotoDropDown]: unrecognized selector sent to instance 0xb2a8320'
when I implement the others methods the error is disappear
-(void)getEditResult:(NSString *)status {
}
-(void)dismissPhotoDropDown {
}
As I've known, if a method in #option we can use it or not.
I don't understand what happened here. Can anyone explain to me
All the #optional directive does is suppresses compiler warnings if the optional methods are not implemented. However, if you call a method that the class does not implement, the app will still crash, as the selector (method) you tried to call is not recognised by the class, since it's not implemented.
You can work around this by checking whether the delegate implements a method before calling it:
// Check that the object that is set as the delegate implements the method you are about to call
if ([self.photoDropDownDelegate respondsToSelector:#selector(dismissPhotoDropDown)]) {
// The object does implement the method, so you can safely call it.
[self.photoDropDownDelegate dismissPhotoDropDown];
}
This way, if the delegate object implements an optional method, it will be called. Otherwise, it won't, and your program will continue running as normal.
Note that you should still use the #optional directive to denote methods that are optional to implement, in order to avoid compiler warnings when you don't implement them. This is particularly important for open source software or libraries that will be distributed to clients, as this directive tells the developers that haven't read your implementation, but can only see the header, that they don't need to implement these methods, and everything will still be fine.
I need to override - (void)viewWillAppear:(BOOL)animatedfor all ViewControllers adding NSLog(#"blabla") in this method. I.e. after every call of viewWillAppear invokes implemented early realization of viewWillAppear + my NSLog message. Is it possible? If yes, please give me an advice.
Currently I have tried this code
#implementation RuntimeTest
IMP previusImp;
IMP newIMP;
- (void)ovverrideViewWillAppearInViewController:(Class)vcClass {
newIMP = class_getMethodImplementation([self class], #selector(viewWillAppear:));
Method viewWillAppearMethod = class_getInstanceMethod(vcClass, #selector(viewWillAppear:));
previusImp = method_setImplementation(viewWillAppearMethod, newIMP);
}
- (void)viewWillAppear:(BOOL)animated {
previusImp(self, #selector(viewWillAppear:), animated);
NSLog(#"log2");
}
#end
then I have
#implementation IRViewController2
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
NSLog(#"log");
}
#end
My custom viewWillAppear invokes first, then viewWillAppear from IRViewController2. And after this my application crashes with EXC_BAD_ACCESS. What's wrong?
if you can't use a subclass because you want to do it globally, but also don't want to lose the old version of the method (so category override is out of the question) then you need to swizzle away the old method, put in your new method that then calls the old method... I have used something called JRSwizzle to perform this in the past, it makes it easy to swizzle without writing a bunch of runtime code.
if (![self jr_swizzleMethod:#selector(originalInit) withMethod:#selector(init) error:&err])
{
NSLog(#"unable to jr_swizzle methods, error: %#",err);
exit(EXIT_FAILURE);
}
if (![self jr_swizzleMethod:#selector(init) withMethod:#selector(myInit) error:&err])
{
NSLog(#"unable to jr_swizzle methods, error: %#",err);
exit(EXIT_FAILURE);
}
then your -myInit method can call -originalInit or whatever methods you are using.
i am declare the protocol in one UIView class i want to implement the protocol method in another UIView class. but the protocol method does not call what can i do. Any one Help me
Did you call the delegate function in UploadView?
Also, since it is optional function, you have to check if the delegate response to the function before calling it.
- (void)yourFunction {
...
if ([self.delegate respondsToSelector:#selector(takeAnotherPhoto:)]) {
[delegate takeAnotherPhoto:self];
}
...
}
I am here confronted with a certain problem. I have a protocol which states a method, that returns the datasource for my tableviews. The datasources are generated by one class, for 3 tableviews. If you tap on one cell, you get to the next tableview with a different source and so on (I think you get the point).
Everything works fine for the first tableview, but as I hand over the deletage to the next tableview I still do not get the datasource for the second. Do I have to release the delegate at a certain point? And if I have to, how do I get it back, when the navigationbarbuttonitem is tapped on...?
Tell me if you have any ideas.
EDIT:
if ([Where isEqualToString:#"System"])
{
if ([exchangeDelegate respondsToSelector:#selector(getNewDataSourceForSystem:)])
{
[exchangeDelegate getNewDataSourceForSystem: [controlDelegate setBranchNavigation:What]];
}
}
else if ([Where isEqualToString:#"User"])
{
if ([exchangeDelegate respondsToSelector:#selector(getNewDataSourceForUser:)])
{
[exchangeDelegate getNewDataSourceForUser: [controlDelegate setLeafNavigation:What]];
}
}
if ([exchangeDelegate respondsToSelector:#selector(getNewDataSourceForCostumer:)])
{
[exchangeDelegate getNewDataSourceForCostumer: [controlDelegate setRootNavigation]];
}
each respondToSelector goes to a different class.
EDIT:
* Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Costumers getNewDataSourceForSystem:]: unrecognized selector sent to instance 0x8a3b0e0'
Thats what I get as an exception when I leave out respondsToSelector:#selector.
Have you called -[UITableView reloadData] to inform it about invalidation of its current state?
And have you overloaded you delegate setter method in order to also fetch and set the new datasource and delegate as needed? Probably something like this:
-(void)setDelegate:(id<MYDelagate>)delegate;
{
myTableView.dataSource = [delegate tableViewDataSource];
myTableView.delegate = [delegate tableViewDelegate];
_delegate = delegate;
}
So, as it seems, using a singleton is the proper way to store my data for my views:
I created a singleton.
The singleton holds my 3 different data-arrays.
The delegate sends the new arrays to the singleton.
I am fetching the data from the views via the singleton.
As simple as it is ... thank you guys for your inspiration :-)
I have a problem that I solved using delegates, but now I am thinking I may have made a mistake.
This is what I want to do.
I have a class that runs on a delay. When it is done it has a finished delegate that it calls.
Now I have the main class that creates two of these delay classes.
I don't want them to both be handled by the same isfinished method in the main class. I want to use two different ones.
However I believe with the protocol method of creating delegates that this will not work for me.
Is there a way around this?
delayclass setdelegates MainclassFunction1
delayclass setdelegates MainclassFunction2
If I understand you correctly, take a look at the NSTableViewDelegate protocol. There, each delegate method's first argument is the NSTableView instance sending the message.
You can solve your issue by changing your delegate methods to have your delegating object send itself as an argument. Then, in your delegate, you'd do something like this:
if (theDelegator == objectA)
{
// Do something
}
if (theDelegator == objectB)
{
// Do something else
}
This way, you've got one cleanly-implemented delegate method that can handle multiple objects delegating to it.
Using delegates doesn't seem like the correct approach to me; they're generally used for augmenting behavior. What sounds most appropriate here is the target/selector pattern, like NSTimer.
#interface MyObject : NSObject {
#private
id target;
SEL selector;
}
#property(assign) id target;
#property SEL selector; /* The selector must return void and accept one argument, which is the MyObject instance that invoked the method. */
#end
#implementation MyObject
- (void)notifyTarget {
[[self target] performSelector:[self selector] withObject:self];
}
#synthesize target;
#synthesize selector;
#end
This is generally the cleanest approach since the delegate callback doesn't need to disambiguate the sender. Using notifications seems like too much overhead for a problem in this domain.
As mentioned, commonly delegate methods would include the object initiating the callback, so you can differentiate that way. Alternately you could have the object post a notification instead, which will also make the originator available.
Why are you not just using NSTimer, adding different timers and having them call whatever selectors you like in the class you are using as a delegate now?
Something like:
NSTimer *timer1 = [NSTimer scheduledTimerWithTimeInterval:0.5f target:self selector:#selector(myMethod1:) userInfo:nil repeats:YES];
NSTimer *timer2 = [NSTimer scheduledTimerWithTimeInterval:0.5f target:self selector:#selector(myMethod2:) userInfo:nil repeats:YES];
Where your methods are:
- (void) myMethod1:(NSTimer*)theTimer
{
// do Something
}
- (void) myMethod2:(NSTimer*)theTimer
{
// do Something different
}
You want to save off and retain both timer1/timer2 references, so that you can stop the timers in dealloc ([timer1 invalidate]).
Short note: Generally, it's bad style to have "if" statements that switch on an object. We all do it occasionally for getting that second list w/o needing a new controller, but switching is what method calls do internally, so ideally you'd just let the ObjC runtime take care of doing the right thing. Several options:
-(void) tableViewSelectionDidChange: (NSTableView*)theView
{
SEL theAction = NSSelectorFromString( [NSString stringWithFormat: #"tableView%#SelectionDidChange:", [theView autosaveName]] );
[self performSelector: theAction withObject: theView];
}
-(void) tableViewUKSourceListSelectionDidChange: (NSTableView*)theView
{
// UKSourceList-table-specific stuff here.
}
-(void) tableViewUKUsersListSelectionDidChange: (NSTableView*)theView
{
// UKUsersList-table-specific stuff here.
}
This works best when you have a non-localized string label, like the autoSave name, but can also use the tag, although that makes the code less readable (which one is "table 1"?). Sometimes it's better to just write a subclass that has a special string for that purpose, or even has methods where you can specify selector names to forward the delegate methods to.
Caleb's suggestion is also good, it's also called "target/action" in case you want to google for it. I have several (Mac) classes that have a regular "action" for clicks, a "doubleAction" for double clicks etc.