Descendant as an parent's delegate - objective-c

Lets say I want to create my own text view with maximum characters constrain. And I want to do that constrain in level below - in text view.
I think of creating CustomTextView : UITextView where customTextView.delegate would be the same object - customTextView (self.delegate = self). The definition of the class would be CustomTextView : UITextView <UITextVIewDelegate> and I would implement – textView:shouldChangeTextInRange:replacementText: to do the constrain logic in.
But somehow this do not work. Can I get explanation why or what can be wrong and how to achieve my intent?

If you are subclassing UITextView, why would you need to set itself as the delegate? The delegate is only used to notify code outside of the UITextView that something changed in the UITextView. This means that the UITextView is notified of changes to itself first and, using the delegate, you can notify external code (UIViewController, etc.) of what happened. If you are subclassing the UITextView, it should receive those change notifications from the OS.
However, looking through the documentation, I cannot see how you would track the built-in events by subclass alone. Here's an article I found with a Google search: Subclassing a UITextView

Related

Detecting when NSTextField becomes active

To be specific I would like to receive notifications when an NSTextField gets focus, or when the user clicks on it and is about to start editing.
I've tried the textDidBeginEditing: method but this is only fired when the user actually starts to type and I need it when the text field becomes the first responder.
I've tried overriding -(BOOL)becomeFirstResponder but that's only called when the text field first becomes the first responder and not any time after that.
I've tried registering for NSControlDidBeginEditing notifications but never got any.
Is this possible?
Implement the window's delegate method windowWillReturnFieldEditor:toObject:. This tells you that the field editor is switching to a different object. Look to see if this object is the text field.
Alternatively, subclass NSWindow and override makeFirstResponder:. Call super, look to see what responder is becoming first responder and whether the call to super returned YES, and return the result of the call to super.
Just to be clear #matt's answer put me on the right path; I thought I just ought to clarify exactly how you can do this.
Aim
So I wanted to have an NSTextField subclass that would know when it became active (i.e. first responder), and then notify it's delegate.
Problem
It turns out the under the hood of OS X text editing is a messy world and you can't really rely on NSTextField to do it all. Basically when an object that is involved in text editing becomes the first responder, something (the window, the system, the NSApplication) gives it an _NSKeyboardClipView (I think it's called that...) as a subview. In turn the _NSKeyboardClipView has an NSTextView as a subview, and it's the NSTextView that becomes the first responder.
Solution
• Subclass (or extend) NSWindow and override the makeFirstResponder: method.
• Fire a notification using NSNotificationCenter who's object is the responder object that is passed to the makeFirstResponder: method.
• Catch the notification in your NSTextField subclass.
• Here's the horrible bit: you need to check that the notification.object is, a) a subclass of NSView and, b) the notification.object.superview.superview == self (you will have to cast to NSView here because the object will be of type id). e.g:
- (void)didBecomeFirstResponder:(NSNotification *)note
{
if ([note.object isKindOfClass:[NSView class]] && [[(NSView *)note.object superview] superview] == self) {
// You just became the first responder
}
}
It's horrible and tacky/hacky but it does work.

Objective C View to Controller Communication

What is the proper way to accept user input in a view and then transfer it to that view's controller? I know the NotificationCenter is one option, but surely there is a more elegant way to transfer data from a view to its controller?
All help is greatly appreciated and I always accept an answer!
Use the delegate protocol design pattern, or target-action by subclassing UIControl. Think about how a UIButton tells a view controller that it's been pressed. In interface builder, you connect an action - a selector something like touchUpInside: to a target - the view controller that owns it. In non-IB, you directly tell the UIButton what selector and what target to use.
Both methods make sense in different cases. For a UITextField, for example, it makes more sense to use delegation because it's possible for the text field to send you any number of events, such as an event when the user begins editing, ends editing, or types a character.
For a button, it makes more sense to use target-action because there's really only one event expressed in different forms.
For swipes and drags and other gestures, use UIGestureRecognizers.
You're looking for Delegation or a Data Source. You can see more information about this here, Delegation and Data Sources
A brief example of this would be, something along the lines of this:
//MyViewSubclass.h
#protocol MyViewSubclassDelegate
//Implement your delegate methods here.
-(void)didTouchView;
#end
#interface MyViewSubclass {
id<MyViewSubclassDelegate>delegate;
}
#property(nonatomic,assign)id<MyViewSubclassDelegate>delegate;
Of course, #synthesize your delegate in MyViewSubclass.m
Now in the class's header, that you want the delegate of MyViewSubclass to be, you need to conform to the `MyViewSubclassDelegate Protocol.
#import "MyViewSubclass.h"
#interface MyViewController : UIViewController <MyViewSubclassDelegate>
In your #implementation of MyViewController., implement the MyViewSubclassDelegate method of -(void)didTouchView.
When you initialize and create your MyViewSubclass object, you set MyViewController as the delegate:
myViewSubclass.delegate = self // Self being MyViewController.
In your MyViewSubclass, when you're ready to forward any information, or simply want to fire a method you would do [self.delegate didTouchView]
Hope this helps !
You are looking for delegation, where the controller set itselfs as the delegate of the view. You know it from UITableViewDelegate.
Make your view a subclass of UIControl and implement the target/action design pattern - use the sendActionsForControlEvents: method to message the controller.
Often the UIKit objects like UITextField have delegate methods that you can implement to perform your business logic. E.g UITextField has a delegate method called - textFieldDidEndEditing: that gets called after the user has dismissed the keyboard.

NSTextField and controlTextDidEndEditing

I have a class 'EditingField' extending the NSTextField. The textfields are variables in my AppDelegate.
I wish to do something after the user has ended editing the textfield. Apparently i am to use the controlTextDidEndEditing or textFieldDidEndEditing. Which one am i to use?
Furthermore where exactly am i to implement the methods and how do i set a delegate if that is required?
If you're using NSTextField (i.e. are developing for OS X) then you'd use controlTextDidEndEditing. If you're using UITextField (i.e. are developing for iOS) then you'd be using textFieldDidEndEditing.
The delegate methods can be implemented in any class you wish, in a very small application perhaps even in the app delegate, otherwise you'd probably implement them in the controller responsible for the part of the UI containing the text field.
To set a delegate, use the setDelegate: method.

3 notifications instead of one

I'm developing simple MVC app in Cocoa/Objective-C. I have a strange issue (or misunderstanding) with notifications and KVO.
I have AppController object in MainMenu.xib, hence I implement awakeFromNib method where I register for NSImageView changing its image property. I add self as an observer in the following way:
// options:3 equals to new/old passed values in changeDictionary
[backgroundImageView addObserver:self
forKeyPath:#"image"
options:3
context:NULL];
The backgroundImageView is an IBOutlet in AppController connected to NSImageView.
In standard observeValueForKeyPath:ofObject:change:context method I just log the received notification.
Problem is - when i change the image value of NSImageView I get 3 notifications instead of one. Can you help me with this? Maybe I'm overlooking something in options or in generally registering observer?
UPDATE: backgroundImageView is the instance of BackgroundImageView class which is sublcass of NSImageView. I subclassed the latter one for handling drag and drop operations as drag destination. When performDragOperation: is called (the last 'state' of the dragging) it changes the value for image property with setImage between willChangeValueForKey and didChangeValueForKey.
… it changes the value for image property with setImage between willChangeValueForKey and didChangeValueForKey.
When you send an accessor message, you get KVO notifications for free with it. You should remove the {will,did}ChangeValueForKey: messages, because they're the cause of at least one of the extraneous change notifications.
Is your AppController the File's Owner of two other nibs? If so, it'll receive an awakeFromNib message for each of those, too. MainMenu plus two makes three awakeFromNib messages, which means you'll add yourself as an observer three times.
There does not seem to be any obvious problem with setting of the observer.
Have a look at how you update the image that you observe, maybe it's being modified 3 times?

Events for custom UIView

What's the best way for registering events for my UIView subclass, so that I can connect them to IBAction-s in interface builder?
Currently I've just got a standard UIView dropped onto my main view and I've set the class to "RadioDial" (my custom class). This displays the view fine, but I have no idea how to get events out of it.
Thanks
Please clarify: do you mean that you would like Interface Builder to offer your view controllers to wire up custom events that your view subclass will be emitting (much like the Button controls allow you to wire up Touch Inside, etc)?
If you need this type of functionality, you will need to use a generalized 'delegate' property on your View combined with a protocol.
#protocol RadioDialDelegate
-(void)dialValueChanged:(id)sender
#end
#interface RadioDial
{
id<RadioDialDelegate> radioDelegate;
}
#property (nonatomic, assign) IBOutlet id<RadioDialDelegate> radioDelegate;
This will allow the controller to wire up to the view (assuming it implements RadioDialDelegate) and receive any events that come out of the view. Alternatively, you can use an untyped delegate and in your View code, use a late bound call:
if([radioDelegate respondsToSelector:#selector(dialValueChanged:)]) {
[radioDelegate dialValueChanged:self];
}
Create a method in your view controller (if nothing else, you should have a RootViewController in you project). Let's say your method is
-(void) buttonClicked { code code code }
In the controller's header file (for example RootViewController.h) you then put:
-(IBAction) buttonClicked;
And in IB you right-click your button/radio dial/whatever. You will see a list of events and you can drag FROM the connector of the event you want your controller to receive, to the object in IB that represents the controler (probably First Responder). This depends on how your IB structure is set up, but it should be straightforward.
Another alternative is to learn how to create UIViews programatically, and forget about IB for the time being. Opinions are divided about whether it's better to learn to use IB at the outset, or whether it's better to learn how to do everything in code and save IB for later. In any case, it's necessary to learn both ways of setting up an interface at some point.