How to make two Classes delegate of UITextView? - ios

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;

Related

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

After Buttonclick delegation: (ViewController) has no segue with identifier 'pushToSecondStep'

I'm really going crazy on this.
But let me explain to you my little project first:
I have an Custom UITableView TDStartTableView.
Also in there I have some methods implemented for rendering the table. No problem there.
Inside of one TableViewCell there is a button.
When that Button is clicked it triggers this method:
- (void)triggerPush {
[self.delegate pushNextView];
}
self.delegate is specified in the .h file of TDStartTableView like this:
#property (nonatomic, weak) id<TDStartTableViewDelegate> delegate;
Also, the reference is set in my UITableViewController:
self.tableView.delegate = self;
So essentially what I'm trying to do is: Create a custom UITableView with Buttons etc. and then listen on the events from a ViewController that is implementing that UITableView and the protocol
So because the protocol forces me to implement pushNextView this method is in my UIViewController:
- (void)pushNextView {
NSLog(#"This works");
}
To this point everything works just fine, no problem there!
But now comes the tricky part.
I create a segue from my UIViewController to a new ViewController. I connect them via a segue and name the segue appropriately. pushToSecondStep.
Now one would think, that when I change the implementation of pushNextView to this
- (void)pushNextView {
[self performSegueWithIdentifier:#"pushToSecondStep" sender:self];
}
it works. But what I get is:
'Receiver (<TDFirstStepTableViewController: 0x8dc97d0>) has no segue with identifier 'pushToSecondStep''
Please help, I'm going crazy :D
The problem was, that I overwrote a constructor of TDStartTableView.
The proper form is that you implement all constructors, so that Objective-C can instantiate them all by itself:
- (id) initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
return self;
}
Also when you implement a custom UITableView Widget you shouldn't use UITableViewController but UIViewController.
Also you don't initialize your custom UITableView yourself, Storyboard already does that for you, so if you want to set special variables for it like numberOfRows then just declare a property and then set it via a setter-method outside and call [tableView reloadData].
Also, thanks https://stackoverflow.com/users/1095089/shubhank for helping me in the chat :)

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.

Problems with <UITextinputDelegate> protocol implementation

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.

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