question about KVO and the method "observeValueForKeyPath" - objective-c

can you help me understand the observeValueForKeyPath method :
here it seems that observeValueForKeyPath is called because we changed the value "for the key : earthquakeList" , but let's say we have another key observed, like "earthquake_New_List",
how can i know that the first, or the second key observed, has changed, if we only have one callback method, the observeValueForKeyPath ?
[self addObserver:self forKeyPath:#"earthquakeList" options:0 context:NULL];
//...
- (void)insertEarthquakes:(NSArray *)earthquakes
{
// this will allow us as an observer to notified (see observeValueForKeyPath)
// so we can update our UITableView
//
[self willChangeValueForKey:#"earthquakeList"];
[self.earthquakeList addObjectsFromArray:earthquakes];
[self didChangeValueForKey:#"earthquakeList"];
}
// listen for changes to the earthquake list coming from our app delegate.
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
[self.tableView reloadData];
}
Thanks

The keyPath parameter in your implementation of observeValueForKeyPath:ofObject:change:context: will tell you which key has changed. So you can do something like:
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
if ([keyPath isEqualToString:#"key1"]) {
// do something
} else if ([keyPath isEqualToString:#"key2"]) {
// do something else
}
}

Related

Detect when SKNode is added as child

I have a Polygon class that is used as data container, but for debugging purposes I want to draw polygons by adding them as children to an SKNode. When I do this I want the Polygon object to add border sprite children to itself. Because of performance reasons I only want to add those sprites when the Polygon has been added as child to another node.
Is there any way that the Polygon object itself can detect that it has been added to the scene, or do I need to tell it by making an extra createSprites call after it has been added to the scene?
I guess I can poll the parent attribute, but I'm looking for something event driven.
In Swift, you can define property observers for the properties of the class yours inherits from.
You could observe changes in the parent property of your custom SKNode subclass, like this:
class MyNode : SKNode {
override var parent: SKNode? {
didSet {
// parent node changed; do something
}
}
}
EDIT: Like I mentioned in the comments, in Objective-C (where you can not use property observers) you can instead use Key-Value Observing (KVO), and observe changes in SKNode's parent property:
Actual code:
- (instancetype) init
{
if (self = [super init]){
// REGISTER for KVO
[self addObserver:self
forKeyPath:#"parent"
options:NSKeyValueObservingOptionNew
context:NULL];
}
return self;
}
- (void) dealloc
{
// UNREGISTER from KVO
[self removeObserver:self forKeyPath:#"parent" context:NULL];
}
// Method that is called when any keyPath you subscribed to is modified
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
// (Check keypath in case you are observing several different
// properties. Otherwise, remove if statement:)
if ([keyPath isEqualToString:#"parent"]) {
// parent node changed; do something
}
}
In Objective-C you could do it like this:
[node addObserver:self forKeyPath:#"parent" options:NSKeyValueChangeOldKey context:nil];
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
//logic here
}
Or in this case simply subclass SKNode and override setParent:

KVO. ObserveValueForKeyPAth is not called

I am not if this will work properly
[[cr1.crossRoad.trafficLights
objectForKey: [NSNumber numberWithInt:pedestrianTL]]
addObserver:view
forKeyPath:#"colorState"
options:NSKeyValueObservingOptionNew
context:nil];
The project I'm developing doesn't work properly. This way I was trying to add an observer to change the view with after every change happening to the cell of the colorState array.
-(void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
[self refreshState:object];
}
The program never enters this method though I change values of the colorState cells. Maybe the problem is with me trying to observe array but not actually what it contains?
The problem was that I was trying to observe an array which was not possible that way.

NSTableCellView / NSTextField did end editing notification -- without text change?

How can I get a notification when the textfield has ended editing (enter key pressed, clicked outside the text field, clicked inside the same column, but outside the text field, etc)
I checked
- (void)textDidEndEditing:(NSNotification *)aNotification
{
//some code here
}
but this notification is only called when the text has actually changed. I need to be notified even if no text changes have been made.
Edit: Some sort of notification that the first responder has changed would work as well.
Any ideas?
Observe the firstResponder state of the window …
…
[theWindow addObserver:self forKeyPath:#"firstResponder" options:NSKeyValueObservingOptionOld context:NULL];
…
… and read the field editor's delegate:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if ([keyPath isEqualToString:#"firstResponder"])
{
NSResponder *oldResponder =change[NSKeyValueChangeOldKey];
if ([oldResponder isKindOfClass:[NSTextView class]])
{
NSTextView *editor = (NSTextView*)oldResponder;
NSTextField *textField = (NSTextField*)editor.delegate;
NSLog(#"This text field lost the focus: %#", textField.identifier);
}
}
}

iOS: addObserver and superview query

I have a uiview named subview1. I add this as subview to a couple of other views depending on certain situations. Now I have the following code
[subView1 addObserver:self forKeyPath:#"superview" options:NSKeyValueObservingOptionNew context:nil];
My problem is the obserValueForKeypath function is never called
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
if (self.subView1 == (UIView*)object) {
if ([keyPath isEqualToString:#"superview"]) {
NSLog(#"superview changed %#",change);
}
}
}
Am i doing something wrong here.
Just check that if it is going into first if block , the problem might be there.Also check if you have declared property for variable for which you are setting the observer if it is in different class.

Control slideshow with current time of AVAudioPlayer

I use a AVAudioPlayer to play a MP3 file. While the player is running I would like to control a slideshow with the current time of the player. Of course I could do this with a NSTimer which is fired when the play starts but that doesn't sound like a sweet solution. How can I ad a observer to the currentTime Value of the AVAudioPlayer?
Thanks,
Philip
The cleanest way to do this is to set up a audio player yourself using AVPlayer and set up a time-passed observation using -[AVPlayer addBoundaryTimeObserverForTimes:queue:usingBlock:].
If you’re stuck with the AVAudioPlayer I believe you can use Key-Value Observing to listen for the currentTime change:
static NSString *someObservationContext = #"something";
[audioPlayer addObserver:self forKeyPath:#"currentTime" options:0 context:&someObservationContext];
and then implement
- (void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if (context == &someObservationContext) {
NSTimeInterval t = [(AVAudioPlayer *)object currentTime];
// do your thing
} else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
Be sure to call -[NSObject removeObserver:forKeyPath:] to remove the observation hook before you tear down the AVAudioPlayer.