I've got an observer on my UItextFields. It basically looks to see if the "enabled" property has changed.
If the enabled status changes, I want a method called fade to run. Fade requires a TextField to be passed to it.
How do I use the textField associated with the Observer that sends the message?
- (void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change: (NSDictionary *)change context:(void *) context;
{
int new = [change objectForKey:NSKeyValueChangeNewKey];
int old = [change objectForKey:NSKeyValueChangeOldKey];
if (new != old)
{
[self fadeEnable:"requires txtField"];
}
}
Thanks
As shown in the Docs,
https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Protocols/NSKeyValueObserving_Protocol/Reference/Reference.html, the parameter 'Object' in the method call encapsulates your textfield.
you just have to cast it and youre done.
To cast it, use:
UITextField *tf = (UITextField *)object;
Edit to address your follow-up Question:
In The case of a Gesture recognizer, you want to get the view that you added the recognizer to. The 'sender' being the recognizer itself, sender.view will get you the associated view.
None of this will ever change, because recognizers only work with VIEWS.
Now, with an observer, you do not necessarily want a view. You want an OBJECT. Thats why 'object' is of type 'id', so you can add observers to objects of arbitrary types. The downside is, of course, that you need a cast. If you dont know what type to cast to, the
-isKindOfClass:
method might be useful.
Oh, and none of this is about interface-builder versus doing stuff in code.
If you find this confusing, i suggest you go study the docs on gestureRecognizers and Key-Value-Observing. If you have specific questions, let me know, or just ask an new question ;)
Related
I have a NSCollectionView in a cocoa application.
I can get information about the currently selected object in the collection view through the following roundabout way:
NSIndexSet* index = [self.currentCollectionView selectionIndexes];
CardModel* card = [[self.currentCollectionView itemAtIndex:index.firstIndex] representedObject];
Does the NSCollectionView class have a method that returns the selected object? Or is this the preferred way to go about it?
Unlike NSTableView you do not have delegates/notifications which gives notifies you about the selection. So selectionIndexes is the way to go.
I am not sure if you have set up observers for array controllers or not. But the code which you have shown is only to retrieve the selected objects. To get notified about the selection of objects you need to add observer for key path selectionIndexes (or what ever is set in IB) on array controllers.
[myArrayController addObserver:self
forKeyPath:#"selectionIndexes"
options:NSKeyValueObservingOptionNew
context:nil];
-(void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
if([keyPath isEqualTo:#"selectionIndexes"])
{
// This will be invoked whenever objects are selected in Collection View.
// Now collectionView selectionIndexes can be used to get the selected objects.
}
}
If you're asking if selectionIndexes is the only way to access an NSCollectionView's selection the answer is yes.
One approach is to use bindings in the xib. Set up an NSArrayController for the items to be represented by the views in the collection. In the xib, in the Bindings Inspector of the Collection View, bind the Content of the CollectionView to the collectionViewArrayController.arrangedObjects. Also bind the Selection Indexes to collectionViewArrayController.selectionIndexes. Now you can make an outlet to the array controller, say in the App Delegate, and access the selected objects there.
For example, declare a selectedCard property, also a collectionViewAC outlet property connected to thecollectionViewArrayController. Now you can get the card item(s) you wish by way of selectedObjects.
- (id)selectedCard
{
id selectedCards = [collectionViewAC selectedObjects];
if ([selectedCards count]) {
return [selectedCards objectAtIndex:0];
}
return nil;
}
Use of bindings keeps everything observed and updated.
I am using ZBAR scanner for scanning bar codes. But it takes quite some time before the camera opens. In the meantime, i want to have a loading animation once the button is pressed and stop the animation after the camera is open. Can anyone plz tell how to detect as soon as the camera is open event handler in ios.
I'm not sure if this is what you are looking for, but I think you can use KVO (Key-value observing) to have event-handler mechanism.
There is this connected property that is KVO-compliant that might tell you when the camera opens (I am not sure though). Here's the documentation:
connected
Indicates whether the device is currently connected.
(read-only)
#property(nonatomic, readonly, getter=isConnected) BOOL connected
Discussion The value of this property indicates whether the device
represented by the receiver is connected and available for use as a
capture device. When the value of this property becomes NO for a given
instance, however, it will not become YES again. If the same physical
device again becomes available to the system, it will be represented
using a new instance of AVCaptureDevice.
You can observe the value of this property using Key-value observing
to be notified when a device is no longer available.
Then you can try to implement observer for this connected property by following the link below. Basically what you need to do is something like:
Event Handler
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if( [keyPath isEqualToString:#"connected"] ){
BOOL isConnected = [ [change objectForKey:NSKeyValueChangeNewKey] isEqualToNumber:[NSNumber numberWithInt:1] ];
if(isConnected){
//remove loading icon..
} else {
//show loading icon..
}
}
}
Event Registration
- (void)viewWillAppear:(BOOL)animated{
AVCaptureDevice *camDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
int flags = NSKeyValueObservingOptionNew;
[camDevice addObserver:self forKeyPath:#"connected" options:flags context:nil];
(...)
}
Here's the documentation that might help you:
KVO Programming Guide
NSKeyValueObserving Protocol
Hope this helps you! :)
It's called only once, like viewDidLoad
It's called right before viewWillAppear. So it's called after the UIViewController navigationController is no longer empty.
Basically I want to set things up programatically stuffs for UIViewController. However, I want navigationController property to already exist. Also I want the whole thing to be called only once.
I'm not super-familiar with view lifecycles in iOS but if by some chance there is not a method that fits your description and you really do need to have such an event, you could always use a call back combined with a property, ie
- (void)viewWillAppear:(BOOL)animated {
if (!self.specialMethodHasBeenCalled) { [self doSpecialMethod]; }
// other viewWillAppear stuff to do every time
}
- (void)specialMethod {
// do stuff
self.specialMethodHasBeenCalled = YES;
}
Might need to do some more stuff for thread safety, but this is just a hacky solution.
I have a UITableView that has cells containing text fields. As the user edits each text field, I need to keep track of the cell's text field value (even when the cell is no longer displayed, so simply tracking the text field does not work). So I used Key-Value Observing and set an observer for each text field in my UITableViewController subclass:
[cell addObserver:self forKeyPath:#"textField.text" options:NSKeyValueObservingOptionNew context:nil];
And save new changes to the text field in the class's observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context method.
This works great in iOS 6, but in iOS 7 KVO isn't called when the user changes the text field value. Apparently the setter method called by pressing "done" on the keyboard doesn't call KVO anymore.
Is there a workaround to this? Or a better way of listening for this change? I need to know what cell the text field belongs to, so implementing the text field's method editingDidEnd doesn't work for me.
Thanks in advance.
I'm not sure about whether there is a workaround for this or not but there surely is a better way of listening for the UITextField text value. If you are creating instances of UITextField programmatically, all you need to do is add an event handler for them to notify your class about the text changing events. For example:
[myTextField addTarget:self action:#selector(editingChanged:) forControlEvents:UIControlEventEditingChanged];
- (void)editingChanged:(UITextField *)sender {
NSString *targetText = sender.text;
}
I have a NSCollectionView wich content is handled by a NSArrayController.
The NSCollectionView is selectable and I need to retrieve a list of selected elements.
I'm trying to observe key property of NSArrayController "selectionIndexes" but it just return me ALWAYS the value of the first element in CollectionView and not the selected items.
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if([keyPath isEqualTo:#"selectionIndexes"])
{
//True if in the array controller of the collection view really exists at least a selected object
if([[arrayController selectedObjects] count] > 0)
{
NSLog(#"Selected objects: %#", [arrayController selectedObjects]);
}
else
{
NSLog(#"Observer called but no objects where selected.");
}
}
}
UPDATE
I never get this method called, if I manually invoke NSLog(#"Selected objects: %#", [arrayController selectedObjects]) I get this
The result is always something like this
END UPDATE
2011-07-05 20:44:45.711 collectionView2[2153:903] Selected objects 1: (
"<Hormiga: 0x10013e330>"
)
I think I have done something wrong binding NSArrayController with NSCollectionView. What could be my fault?
Tell me if you want more info, I can even post the entire program in a zip if you need it.
UPDATE 2
This is the code I use in my controller to observe the arrayController "selectionIndexes" key.
[arrayController addObserver:self forKeyPath:#"selectionIndexes" options:NSKeyValueObservingOptionNew context:nil];
UPDATE 3
One of the problem was fixed, I forgot to set the binding between NSArrayController and NSCollectionView relative to the key "selectionIndexes". Now I can retrieve manually the list of selectedObject and its correct!
My final problem is that I don't receive the notification when selectionIndexes changes.
So observeValueForKeyPath:ofObject:change:context: never get called!
UPDATE 4
I was trying to set the observer in the init method of my controller, but in this way the arrayController is still null. Moving the addObserver in the awakeForNib resolved all my problems!
If you want to keep the array controller’s selection indexes in sync with the collection view’s, you need to bind them as well. In summary:
Bind the collection view Content to the array controller, key arrangedObjects
Bind the collection view Selection Indexes to the array controller, key selectionIndexes.
Also, make sure arrayController has been set before you add an observer. Outlets are guaranteed to be set in -awakeFromNib and other methods that are invoked after it: If you’re using a window controller, you can use -windowDidLoad; if you’re using a view controller, you can use -loadView; otherwise, -applicationDidFinishLaunching: in your application delegate.