nskvopendingnotification error in objective-c - iphone

I have the following problem
during abstraction i have encapsulated a class in objective c which allows me to change a rectangles size and position over an underlying image.
I use this class as in some situations each slightly different.
In one i need to ensure a minimum and maximum size in a other the rect must be a square.
So i observe the value set by the user and check it against rules by using the objective-c methods:
[rectDrawer addObserver:self forKeyPath:#"value" options:NSKeyValueObservingOptionNew context:nil];
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
In this method i check the constraints. But when i want to correct a invalid value and write it back it comes to that problem with "EXC_BAD_ACCESS" exception
I also tried following to avoid the exception but this does not help
[rectDrawer removeObserver:self forKeyPath:#"value"];
rectDrawer.value = _value;
[rectDrawer addObserver:self forKeyPath:#"value" options:NSKeyValueObservingOptionNew context:nil];
is there a possible solution for this

Related

iOS Camera focus value

Is there any way to get the focus value from iPhone camera with autofocus?
I want to use this data to calculate the distance from iPhone to an object in focus.
Obviously this is an old question, but as there is an option to get a "lense value" since iOS8 it should appear here.
Since iOS8 you can get the focus value from the lense by key-value observing lensPosition. It is a property of the AVCaptureDevice class which is part of the AVFoundation framework.
So somewhere in your camera class set the observer:
// Assuming _device is an object of the `AVCaptureDevice` class
[_device addObserver:self forKeyPath:#"lensPosition" options:NSKeyValueObservingOptionNew context:nil];
And in the class you used as observer:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if ([keyPath isEqualToString:#"lensPosition"]) {
NSLog(#"change: %#", change);
NSLog(#"lens position: %f", [change[#"new"] floatValue]);
}
}
The position of the lens will be displayed as a scalar value from 0 to 1.
Also you can set the lens position manually. You can find out more about managing the lens position in the Apple Documentation.
Finally as with all key-value observer don't forget to remove the observer.
NOTE: The lens is a mechanical part in the device and focusing is done by moving the lens via a spring. So values differ depending on the device and situation.
I do not think there is such a thing as a focus value.

Observing insertions and removals from NSMutableSet using observeValueForKeyPath

I would like to be notified about a new insertion in the NSMutableSet and thus this is what I am doing, but for some reason it is not calling observeValueForKeyPath method
Just for test:
-(void)observ{
[self addObserver:self forKeyPath:#"connections" options:NSKeyValueChangeInsertion context:NULL];
[connections addObject:#"connectionName"];
}
This is never called:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if( [keyPath isEqualToString:#"connections"] ) {
NSLog(#"added new object");
}
}
Is NSMutablSet KVC ?
NSMutableSet is indeed KVO/KVC compliant. However, in order to receive the notifications with the way you have this set up, you need to implement the KVC accessor methods for a set. Information can be found here. Essentially, you have to implement methods called:
-countOfConnections
-enumeratorOfConnections
-memberOfConnections:
-addConnectionsObject:
-removeConnectionsObject:
-intersectConnections:
You must use these methods to access and mutate your set in order to receive KVO notifications.
Finally, in your -observeValueForKeyPath method, you can use the value of the key kind in the change dictionary to determine what type of mutation occurred (addition, deletion, etc.). The values can be found here and are listed under "NSKeyValueChange". Hope this helps.

Observing value changes to an NSUserDefaults key

I'm interested in the value change of a particular key which I keep in NSUserdefaults. However, what I have is not working for me. observeValueForKeyPath does not get triggered.
Update: I think I've discovered the issue. Rather than using a defined constant, if I use a string then it gets fired.
[[NSUserDefaults standardUserDefaults] addObserver:self forKeyPath:kSomethingInteresting options:(NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld) context:nil];
}
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context {
NSLog(#"Defaults changed, %#.%#", object, keyPath);
if ((object == [NSUserDefaults standardUserDefaults]) && [keyPath isEqualToString:kSomethingInteresting]) {
NSLog(#"kSomethingInteresting changed in defaults");
}
}
Not ideal but if I precede the addOberver line with:
NSString* keyToObserve = kSomethingInteresting;
And use that in the addObserver line then that works. Seems a bit fiddly?
So I'm going to scrap the use of a defined constant in this instance and in all instances where I need to observe something in userdefaults. Shame, as I like using them for key names throughout.

NSOperation KVO problem

I'm using following function to get my application notified after the operation in nsoperationqueue has finished, so that I can schedule the task that's dependent upon the result of the operation. I'm using:
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
if([keyPath isEqual:#"isFinished"] && _operation == object)
{
NSLog(#"Our Thread Finished!");
[_operation removeObserver:self forKeyPath:#"isFinished"];
[self performSelectorOnMainThread:#selector(showDialog) withObject:nil waitUntilDone:YES];
}
}
My question is since mostly the tasks assigned to these operations are parsing of data if I try to tap some other button or basically do something that results in action, I get the following exception:
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '<Settings: 0x21b970>: An -observeValueForKeyPath:ofObject:change:context: message was received but not handled.
Key path: isFinished
I perfectly understand that since I try doing other things on main thread, because of which the call to main thread:
[self performSelectorOnMainThread:#selector(showDialog) withObject:nil waitUntilDone:YES];
fails to get executed. But what's the solution to this problem as I want both allow user do any action after making a request and also perform the action scheduled after finishing the task assigned to the operation.
Is it really possible?
Thanx in advance.
If you can require Mac OS X 10.6 Snow Leopard, or (I think) iPhone OS 3.0, you can avoid KVO entirely for this. Just create another operation for the work you want to do on the main thread, add the operation it needs to follow as a dependency, and then put the main-thread operation on the main queue:
NSBlockOperration *mainThreadOp = [NSBlockOperation blockOperationWithBlock:^{
[self showDialog];
}];
[mainThreadOp addDependency:backgroundOp];
[[NSOperationQueue mainQueue] addOperation:mainThreadOp];
NSOperation supports dependencies between operations on different queues. Just be careful not to make operations on different queues mutually dependent, because that will result in deadlock.
The reason your are seeing this problem is that you are not using the context pointer.
When you add or remove an observer, pass a context pointer. In your observeValueForKeyPath:ofObject:change:context: , check the context point to make sure the observation being passed belongs to you. If not, call super. It's possible to use self as the context point, or you can take the address of a static string, etc.
Here is an example:
Adding the observer:
[sample addObserver:self forKeyPath:#"finished" options:[self observationOptions] context:(void *)self];
Handling the change notification:
- (void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if (context == (__bridge void *)self){
if ([keyPath isEqualToString:#"finished"]){
// Handle the change here.
}
} else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
Removing the observer:
[sample removeObserver:self forKeyPath:#"finished" context:(void *)self];
Because your code was not able to pass one of the notifications to super in observeValueForKeyPath:ofObject:change:context:, that notification went in but never came out. This is why you got that exception.
It unfortunate that many of the Key-Value Observing examples available on The IntarWebs do not do this correctly and/or pass NULL as the context pointer (even Apple's documentation does this).

Registering a bool for a NSNotification

I'm trying to wrap my head around NSNotification but can't seem to get it to work. Think I'm misunderstanding how to register for an notification.
I have a bool as a property in my connection manager class. At initialisation I authenticate with a few servers and check if I can access an external URL (App will mainly be used on company intranet and an external connection isn't always possible)
The BOOL property will be changed from YES to NO if it cannot access the connection and as this can be responded at any time I thought it would be best to register a notification for when it changes. The property is called externalConnectionAvailable
[ConnectionManager addObserver:self forKeyPath:#"externalConnectionAvailable" options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld) context:NULL];
and have the method:
-(void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
NSLog(#"observer called");
}
But this doesn't get called. Am I doing something completely wrong?
Thanks
In this statement:
[ConnectionManager addObserver:self forKeyPath:#"externalConnectionAvailable" options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld) context:NULL];
Assuming that you are following the "Cocoa Way" and using the usual naming scheme for classes and object instances, you appear to be trying to add an observer for an entire class, as opposed to an object instance.
You should have something like
ConnectionManager *connectionManagerInstance = // initialize manager...
...
[connectionManagerInstance addObserver:self forKeyPath:#"externalConnectionAvailable" options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld) context:NULL];
It was something very stupid. I was just changing the property by calling externalConnectionAvailable not self.externalConnectionAvailable