Problems with <UITextinputDelegate> protocol implementation - ios

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.

Related

How to make two Classes delegate of UITextView?

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;

Getting data out of custom UITableViewCell and back into UITableViewController

I have a UITableView comprised of custom UITableViewCells. In each cell, there is a UILabel and a UISlider. Does anyone know how to, upon a change in value of one of the sliders, send the new value of the slider from the custom UITableViewCell (in a separate file) to the UITableViewController, so that I can then update the array from which the table was populated?
The closest I've got so far is a failed hack: firing a setSelected event when a slider value is changed. Whilst this highlights the changed custom cell, the event is not picked up by didSelectRowAtIndexPath in the UITableViewController.
Whilst code is always appreciated, a conceptual/method solution is what I am looking for.
Thank you in advance,
Jamie
What you need is called Delegate Pattern.
Quoting from there to explain what does it mean:
Delegation is a simple and powerful pattern in which one object in a
program acts on behalf of, or in coordination with, another object.
The delegating object keeps a reference to the other object—the
delegate—and at the appropriate time sends a message to it. The
message informs the delegate of an event that the delegating object is
about to handle or has just handled. The delegate may respond to the
message by updating the appearance or state of itself or other objects
in the application, and in some cases it can return a value that
affects how an impending event is handled. The main value of
delegation is that it allows you to easily customize the behavior of
several objects in one central object.
These diagrams will help you understand what goes on:
Architecture:
Operation:
Now as to how to implement it, this is what you have to do.
For Objective-C:
First of all, create delegate methods of your UITableViewCell. Lets name it ContactTableViewCell.
In your ContactTableViewCell.h file, do this:
#protocol ContactCellDelegate <NSObject>
#required
-(void) didMoveSliderWithValue:(float) value;
#end
#interface ContactTableViewCell : UITableViewCell
#property (weak, nonatomic) id<ContactCellDelegate> delegate;
Now conform your TableViewController to this delegate. Let's name your VC MyTableViewController.
In MyTableViewController.h, Do this:
#interface MyTableViewController : UIViewController <ContactCellDelegate> //Use UITableViewController if you are using that instead of UIViewController.
In your cellForRowAtIndexPath, before returning cell, add this line:
cell.delegate = self;
Add implementation for the delegate method INSIDE your MyTableViewController.m.
-(void) didMoveSliderWithValue: (float) value
{
NSLog(#"Value is : %f",value);
//Do whatever you need to do with the value after receiving it in your VC
}
Now let's get back to your ContactTableViewCell.m. In that file you must have added some IBAction to capture the value change event in slider. Let's say it is the following:
- (IBAction)sliderValueChanged:(UISlider *)sender {
self.myTextLabel.text = [#((int)sender.value) stringValue]; //Do whatever you need to do in cell.
//Now call delegate method which will send value to your view controller:
[delegate didMoveSliderWithValue:sender.value];
}
When you call delegate method, it will run the implementation that we wrote earlier in the MyTableViewController. Do whatever you need in that method.
What happens here is that your Cell sends the message to your desired VC (Which is delegate of the Cell), that "Hey, Call the delegate method that we wrote earlier in your body. I am sending you parameters right away". Your VC takes the parameters and does whatever you wanted it to do with that info and at that time.
For Swift:
First of all, your TableViewCell.swift file, create a protocol like this:
#class_protocol protocol ContactCellDelegate {
func didMoveSliderWithValue(value: Float)
}
Now in your Cell class, create a delegate property like:
var cellDelegate: ContactCellDelegate?
In your Slider IBAction, call the delegate method like this:
self.cellDelegate?.didMoveSliderWithValue(slider.value)
In your VC do these changes:
Make it conform to the delegate:
class MyTableViewController: UIViewController, ContactCellDelegate
Add this line before returning cell in cellForRowAtIndexPath
cell.cellDelegate = self //Dont forget to make it conform to the delegate method
Add the implementation of required delegate method:
func didMoveSliderWithValue(value:float) {
//do what you want
}
I have kept the Swift part precise and summarized because It should be very easy to change the detailed Obj-C explanation to Swift implementation. However If you are confused about any of the pointers above, leave a comment.
Also see: StackOverflow answer on using Delegate pattern to pass data back

Initialising a category in objective-c

I'm writing a category for UITextField to include validation. I wish to change the text field's visual according to validation state (such as having an approved icon as its right view). For this, I keep a validation state property and wish to update the visual on its setter.
Here's what I have (UITextField+Validation.h)
#interface UITextField (Validation)
// Validator registration
- (void)addValidator:(id<HyValidator>)validator;
// Validation
- (void)validate;
#end
UITextField+Validation.m
#interface UITextField (Validation_Private)
#property (nonatomic, strong) NSMutableArray * validators;
#property (nonatomic) HyValidationState validationState;
#end
#implementation UITextField (Validation_Private)
- (NSMutableArray*)validators
{
if (self.validators == nil) {
self.validators = [[NSMutableArray alloc] init];
}
return self.validators;
}
- (void)setValidators:(NSMutableArray *)validators
{
self.validators = validators;
}
- (HyValidationState)validationState
{
}
- (void)setValidationState:(HyValidationState)validationState
{
}
- (void)addValidator:(id<HyValidator>)validator
{
[[self validators] addObject:validator];
}
- (void)validate
{
}
#end
The question is: how do I initialise validators and validationState?
Don't use categories for this. Subclass instead. Or, better yet, use the UITextField's delegate to do the validation, as intended.
Using categories to extend the behavior of existing system classes is generally considered to be bad design.
By using delegation, you can decouple input validation from a specific input class and, thus, your validation can be easily re-used across other input mechanisms.
You want to add a storage to your class UITextField (simple ivar to hold the data). Since you don't have the code you can't extend the class. However in objective C you can achieve this using associated reference. ObjC Runtime comes handy helping you to attach a storage to your class and make you interact with the storage as if it was built in within the class.
An example of how to achieve this is found in Ole Begemann blog here http://oleb.net/blog/2011/05/faking-ivars-in-objc-categories-with-associative-references/

Delegate referencing to itself

I been developing a custom UIAlertView class to have an completion block. Is it ok to have a delegate reference to itself?? For example:
PYAreaAlertView.h
#interface PYAreatAlertView : UIAlertView
#property (nonatomic, copy) CompletionBlock completion;
- (id)initWithCompletion:(CompletionBlock)completion;
#end
PYAreaAlertView.m
#interface PYAreaAlertView () <UIAlertViewDelgate>
#end
#implementation PYAreaAlertView
- (id)initWithCompletion:(CompletionBlock)completion
{
self = [super init];
if (self)
{
_completion = completion
self.title = #"Add Area"
self.message = #"";
self.delegate = self // Is this ok??
}
return self
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
NSString *buttonTitle = [alertView buttonTitleAtIndex:buttonIndex];
if ([buttonTitle isEqualToString:#"Done"] && self.completion)
self.completion();
}
Beware, that you are also exposing the delegate property to the user of your class, since PYAreatAlertView is a UIAlertView. So your logic of executing a completion block may not work in case user provides different delegate.
Also, just a word of caution: It is recommended that UIAlertView should not be subclassed.
From UIAlertView docs,
The UIAlertView class is intended to be used as-is and does not support subclassing. The view hierarchy for this class is private and must not be modified.
In such scenarios, you are better off creating a custom UIView and replicating the alert view appearance. Here you can implement the delegation and/or completion block design.
EDIT:
In theory, a delegate is an object that acts on behalf of, or in coordination with, another object when that object encounters an event in a program. So when you set the delegate of your class as self you defeat the purpose of delegation pattern.
Hope that helps!
self.delegate = self is completely ok and a pretty common pattern when subclassing framework methods. delegate is almost always a weak reference so you're not getting a circular reference.
This is perfectly legal because your class conforms to the <UIAlertViewDelegate> protocol.
This is also a good idea because instead of out-sourcing your delegate to another class, you can keep all of it in house.
One contrary to this technique though, is that fact that it breaks the Model-View-Controller style. Having your view (subclasses of UIView) dealing with logic breaks the MVC paradigm. You might try creating a new class called MyAlertViewDelegate : NSObject <UIAlertViewDelegate>, instantiating it, then assigning it as your delegate. This keeps your MVC intact by separating the Model and the View.

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.

Resources