- (void)setTableView:(UITableView *)tableView {
_tableView = tableView;
[_tableView addObserver:self
forKeyPath:#"frame"
options:0
context:nil];
[self updateFrame];
}
The exc_bad_access occurs when trying to add an observer.
In the assembly code, the error code is 'NSKeyValueObserverRegistrationLock'.
Have no idea what's causing the error.
I'm running XCTest so there might be a possibility that error was cause by injecting the test code into application code.
Anybody helps?
A couple of things.
You should define your options parameter. The NSKeyValueObservingOptions struct doesn't have an entry for 0. If you are after the new value then use NSKeyValueObservingOptionNew.
Next I assume the function you have listed resides in a UIViewController? UIViewController doesn't have a frame property. It's view does though (so does your tableView). I'm not sure which frame you're trying to observe, but you can try:
[_tableView addObserver:self.view
forKeyPath:#"frame"
options:NSKeyValueObservingOptionNew
context:NULL];
Or
[_tableView addObserver:tableView
forKeyPath:#"frame"
options:NSKeyValueObservingOptionNew
context:NULL];
Related
I have the following observer in my ViewController.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification object:nil];
This view controller also conforms to the UITextFieldDelegate and UITextViewDelegate and implements textFieldDidBeginEditing and textViewDidBeginEditing.
Now, here's the weird part.
If you tap on the UITextField, the order of calls is textFieldDidBeginEditing AND THEN keyboardWillChangeFrame:.
If you tap on the UITextView, the order of calls is keyboardWillChangeFrame AND THEN 'textViewDidBeginEditing'.
Anyone not see a problem with this? Shouldn't text_____DidBeginEditing be called first no matter whether it's a Field or View. Why is this?
It's leading to weird animation issues. I need it to be consistent one way or the other.
I believe you can use the UIKeyboardWillShowNotification, and something like the above code for what you are trying to do:
- (void)keyboardWillShowNotification:(NSNotification*)notification {
NSDictionary *info = notification.userInfo;
CGRect r = [info[UIKeyboardFrameEndUserInfoKey] CGRectValue];
r = [self.view convertRect:r fromView:nil];
UIViewAnimationCurve curve = [info[UIKeyboardAnimationCurveUserInfoKey] integerValue];
double duration = [info[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationCurve:curve];
[UIView setAnimationDuration:duration];
/* view changes */
[UIView commitAnimations];
}
Use UIKeyboardDidChangeFrameNotification instead of UIKeyboardWillChangeFrameNotification.
I have an observer on an UIView to adjust a UIWebView when the size is changed (e.g. on rotation of the device):
[[self view] addObserver:self forKeyPath:#"frame" options:0 context:nil];
Naturally I need to remove this observer when the view is dismissed (otherwise there is an exception). But where would I do this? I tried in dealloc, or in viewDidDisappear, but I get a SIGABRT when I do this.
- (void) viewDidDisappear:(BOOL)animated {
NSLog(#"Is moving %d - %d", self.isMovingFromParentViewController, self.isBeingDismissed);
[[self view] removeObserver:self forKeyPath:#"frame"];
}
I tried to move it in earlier on ViewWillDisappear, but the same result.
Moreover, I am not completely happy with this later solution (even if it would work), as it will potentially also unload when the view is temporary out of view (i.e. with pageViewController), although that is not that big a deal for me at the moment.
Tracking the problem down to this item and trying to solve it has already cost me a day, so any suggestions are really appreciated!
#import "USST_Test.h"
#implementation USST_Test
-(void) observeValueForKeyPath:(NSString *)KeyPath ofObject:(id)object change:(NSDictionary *)
change context:(void *) context{
NSLog(#"yes i have been changed",nil);
NSLog(#"%#",[change objectForKey:#"new"]);
}
-(void)setFirstName:(NSString *)firstName{
[self addObserver:self forKeyPath:#"firstName" options:NSKeyValueObservingOptionNew context:nil];
}
#end
Here is my code and I always get NSNull printed.
I am new to Objective-c and any help is appreciated.
I'm not sure that you understand the purpose of KVO. You're having an object observe itself every time the first name is changed. Typically, another object would add an observer once, using a call like this:
[object addObserver:self forKeyPath:#"firstName" options:NSKeyValueObservingOptionNew context:nil];
This means that self would like to be informed when object changes its firstName key. Calling [object setFirstName:name] will automatically trigger the KVO update, so no extra code is needed in it.
You don't need to implement custom setter for this.
Somewhere when you init the UUST_Test class call
[self addObserver:self forKeyPath:#"firstName" options:NSKeyValueObservingOptionNew context:nil];
And remove
-(void)setFirstName:(NSString *)firstName{
[self addObserver:self forKeyPath:#"firstName" options:NSKeyValueObservingOptionNew context:nil];
}
But be careful to remove the observer when the UUST_Test object will be destroyed. For that you can implement -(void)dealloc method but do NOT call [super dealloc] if you are using ARC which I think you use.
I'm trying subclass a UIView in which I want to add more subviews. Since I'm changing frame property of my view in code, I want my subviews to resize when this view is resized, so I've added the following code in my initWithCoder: method:
[self addObserver:self forKeyPath:#"frame" options:NSKeyValueObservingOptionNew context:nil];
And in the observation method, I'll reset view's frame manually. Everything works fine, but when I push some other view controller and move back, I got this message:
Observation info was leaked, and may even become mistakenly attached to some other object.
So, how can I fix this? I know for sure that the observer is not removed, but there is not any viewDidDisappear stuff here. What should I do?
Thanks!
You should remove the observer for all added observers, So do like following code,
- (void)dealloc {
[self removeObserver:self forKeyPath:#"frame" context:NULL];
}
How do you remove an observer from an object under ARC? Do we just add the observer and forget about removing it? If we no longer manage memory manually where do we resign from observing?
For example, on a view controller:
[self.view addObserver:self
forKeyPath:#"self.frame"
options:NSKeyValueObservingOptionNew
context:nil];
Previously, I would call removeObserver: in the view controller's dealloc method.
You still can implement -dealloc under ARC, which appears to be the appropriate place to remove the observation of key values. You just don't call [super dealloc] from within this method any more.
If you were overriding -release before, you were doing things the wrong way.
I do it with this code
- (void)dealloc
{
#try{
[self.uAvatarImage removeObserver:self forKeyPath:#"image" context:nil];
} #catch(id anException) {
//do nothing, obviously it wasn't attached because an exception was thrown
}
}
Elsewhere on stack overflow, Chris Hanson advises using the finalize method for this purpose and implementing a separate invalidate method so that owners can tell objects that they are done. In the past I have found Hanson's solutions to be well-thought-out, so I'll be going with that.